Play 2.0, Scala and the new way of doing things

Recently there’s been a (heated) discussion on the Play framework mailing list about Play 1.x vs Play 2.0, Scala, and the added level of complexity.

First off, some of these points are completely valid. For many Java hackers, Play 1.x was an enlightenment. While it’s true that it was a copy of Ruby on Rails in Java, it was the first framework which allowed agile web development on the JVM (i.e. hot-reloading, compile errors are shown in the browser, no XML configuration, and so on). With 1.1 and 1.2 it added most of the needed features while keeping a light style of development. Many people feel that with Play 2.0, this lightness has gone.

Why is that? Let me show you some examples.

Claim 1: You have to learn a new language

Play 2.0 is written in Scala, and even though it has a Java API, as a non-Scala developer you quickly encounter code you don’t understand. First and foremost, it’s the templating engine, which is based on Scala. The framework authors’ response is that you can switch out the templating engine. But why use a web framework if you have to switch out every component? And it’s obviously not the first thing you want to do when trying out something for the first time. I still don’t understand why they didn’t bundle the Groovy engine.

The build file is not only written in Scala, but even a Scala DSL. I initially found this to be an advantage since I already knew SBT. Well, at least I thought so. SBT 0.7 was a joy to use, but apparently it’s a fun exercise to completely change the DSL with every point-release. They should also have changed the name because this tool is anything but simple.

And for the record, the route files are written in Scala-style, too. However, this shouldn’t be a big a deal, as the route syntax is pretty limited.

Whether or not you like Scala itself is a very personal choice; you should at least give it a try. Yes it’s a complex beast, but it also allows you to write beautiful code, especially if you embrace the functional paradigm (see the examples below).

Claim 2: Compilation times are slower

This is what I found to be the biggest problem with Play 2.0. Agile development with fast tournaround times makes only half as much sense when one small change in a templates results in the recompilation of 60 classes and takes 10 seconds. Fortunately, the authors of Play and of SBT (the compiler being the main culprit here) are aware of that. So hopefully, compile times will improve in the near future.

Another annoyance was unexpected runtime errors (e.g. VerifyError) every now and then. This should vanish as the framework matures.


So, is Play 2.0 a step in the wrong direction? Absolutely not. I used Play 2.0 with Scala for about three months (even before it reached RC status), and found it an an absolute joy to use. In short, this is because it supports a style of development I’d call Functional Web Programming. Let me show you what I mean by that.

Action Composition

Actions (i.e. the methods that are invoked by clicking a link or pushing a button) are composable, which means you can take one, and wrap it around another, and end up with a new action that is a combination of the two. This allows for powerful and scaling abstractions.

The basic action is called Action (no surprise here) and is essentially a function which maps a request to a result. For example, in our application we have pages that can only be accessed by an administrator. So the easiest way to protect those pages was to define an action called AuthenticatedAdmin which in turns calls Authenticated (whose only job is it to verify if the user is logged in), which in turn calls the actual action.

In terms of code it looks like this:

def Authenticated[A](p: BodyParser[A])(f: AuthenticatedRequest[A] => Result) = { Action(p) { implicit request => request.session.get("email").flatMap(email => UserDAO.findByEmail(email)).map { user => f(AuthenticatedRequest(user, request)) }.getOrElse(Results.Ok(views.html.error("Not Authorized", "You have to log in to view the requested page"))) } } def AuthenticatedAdmin[A](f: AuthenticatedRequest[AnyContent] => Result) = Authenticated { implicit request => request.user.adminProfile match { case Some(profile: AdminProfile) => f(AuthenticatedRequest(request.user, request)) case _ => Results.Ok(views.html.error("Not Authorized", "You need administrator privileges to access the requested page")) } } ▸ Read more...

Tagged with: , ,

What I like / dislike about the iPad

I’ve been an iPad user right from the beginning and been using iPad, iPad 2, iPad 3, and iPad Air 2. So here are my collected thoughts about it. ▸ Read more...

Tagged with: