Apr 21 2013
Update: This post has gotten a lot more attention than I expected and I just want to say to those reading: Thanks for stopping by!
On a recent project, my team evaluated several web frameworks for an upcoming web application. We chose The Play Framework. I was very attracted to its simplicity and the rapidity with which we could get things working. The Scala templates are also very powerful and much simpler (for me at least) than JSP templates. All in all it seemed like a match made in heaven. We were all really enjoying working with it. Unfortunately the honeymoon ended shortly thereafter.
One of the first things I noticed about Play is how sparse the documentation is. Examples are very basic, which is sometimes ok, but frequently not ok. Searching Google for documentation often returned results on the Play page, but for the wrong Play version. This is not a big deal for many Java APIs/Frameworks, but with Play? This leads me to the next point.
Massive Changes between Releases
It’s commonplace for API’s to have breaking changes between major versions. The Java world typically deprecates functionality at least a release ahead of removal/breakage, which is polite, but not strictly necessary. But Play has thrown caution to he wind and seems to be in a constant state of upheaval. Between 1.x and 2.x the framework changed dramatically. Most of the documentation from 1.x is completely invalid for working on 2.x. And plenty of the documentation from 2.0 is not valid for 2.1. I’m all for agility, but at a certain point I’d like stability in the API and app, so that I can upgrade with confidence.
Scala vs Java
Our Team chose to develop in Java for many reasons, not the least of which was time. None of us know Scala to the extent that we could be productive with it. Sure, we could learn it but that would take time: Time we didn’t have. There’s also the fact that we would be leaving this app for the staff to continue to support. As a consultant you always have to consider the aftermath of your departure. How easily will the staff (even the ones that have worked beside you) be able to add features or fix bugs when you leave? Java was the natural choice. But something I’ve noticed is that the Scala and Java APIs aren’t congruent. Of course there will be some differences, but I’ve noticed extra features in the Scala API that I’d like to use, but can’t (Wrapping requests, filtering, etc).
In recent versions of Play I’ve noticed that formerly mutable objects are now immutable. That’s great. It sure makes concurrent programming easier. But what if I need to modify something? For instance, Play gives you the ability to intercept HTTP requests as they come in. But the Request objects are immutable. Can I wrap/decorate a Request? Sure…if I’m using the Scala API. Another example is the Configuration object. In previous versions of Play you could update your configuration at runtime. That ability has also been taken away. So how could I convert the JSON on an incoming request body into a Java object and then put it back on the request for controllers to consume? How can I modify configuration after start-up so that devops can dynamically set passwords and other sensitive data? Good questions. I can’t find answers in the documentation or mailing lists.
(update on changing configuration)
Do It Yourself JSON Parsing
Maybe I’m spoiled having used other Java Frameworks, but I don’t expect to have to manually invoke the JSON serializer for simple POJOs. Jackson Mapper does an excellent job and many other Frameworks have integration for it. For instance in Spring or one of the JAX-RS implementations, you only need to set some annotations on a method and the JSON on the request body will be deserialized and passed to you automatically. Not so with Play. Sure Jackson Mapper is built in, but you still have to write boilerplate to serialize or deserialize your data. This isn’t a show-stopper, but it’s a rough edge that takes away from the conciseness of my code.
Many organizations have existing servers and deployment processes and are, understandably, slow to change. On a recent project, the client had a pretty standard set up: an Apache web server fronting a Tomcat Servlet container. They expected the build product to be a WAR, so Play’s standard way of deploying was not acceptable. The Play2War plugin served the purpose of converting our project to a WAR, but it also has some rough edges. Granted it’s not 1.0 yet, but there are no other alternatives as previous 1.x plugins are not compatible. Once we got that working, however, we quickly realized that the client’s needs were too dynamic for Play to handle. Their current application starts up with development DB information. Their devops deployment team runs a script that prompts them for passwords and then sends an HTTP POST to a non-public endpoint in the app that updates the DB and reloads The EntityManger. This seems to be impossible in Play because of the immutable Configuration and because there is no published way to reload the JPA helper class. I could technically maintain my own EntytManagerFactory, but why would I want to do that if there’s already JPA integration?
It very well could be that the problems I’ve had with Play are a result of a difference in ideologies between Scala and Java programming. If that’s the case, fine, but the framework shouldn’t stop me from doing something without offering an alternative path or best practice. Maybe there are work-arounds for all of my problems, but I just couldn’t find them. I can read the source if need be, but it shouldn’t be a replacement for documentation. I’ve found that my colleagues and I spend way too much time trying to get something to work in Play that already works in Java EE or Grails. More often than not we’ve hit a dead end. And it’s not as if we didn’t do our homework. We did a fairly thorough spike in Play. We did discover the immutability issue then, but assumed that surely there must be a “Play way” of doing it. Regardless of the issues, I still enjoy developing in Play. For simple, 100% greenfield apps it’s very rewarding and productive to use. But unless I discover solutions to my problems, I’ll probably just use Grails or JEE for new JVM web apps.