I'm also an Django developer and did a play application some time back[0], so maybe I can give some insight on development with Play!.
My background in functional program was non-existent at the time so going in I was already going to have problems. I choose to create my project as Scala project since I wanted to learn the tech. While Scala can be done with normal OOP/procedure programming I wanted to have the full affect of using Scala .
(These are my findings over the 2.0.x branches of Play! but should still be relevant to the current branch)
Management:
Starting of a project is pretty simple, I have to say the Play! has done a great in baking in a good cli right into their framework and making it easy to plug in your own custom commands. I should mention that I was developing on a Windows 7 machine, in normal cases this wouldn't have been a problem but at the time with the 2.0.x version there were quite a few bugs with the project builder. For one, I couldn't use google closure compiler support due to some path finding issues "\" vs "/" and the stage, staged/start command didn't take windows into mind when generating the script. But for the most part these were small problems. It also has a less compiler ,which had a few problems causing me to patch my local ivy install, but should be all addressed now.
* Routing :
The routing files is located in conf/routes, which has a pretty simple DSL for defining your routes in a simple format :
<http_method> <path or regex> <method with option for defaults>
On thing that was lacking was the option to define multiple http methods for a route, meaning I could have a GET and POST route handled by the same function. While this may not be the best way to handle, but in some cases say with a /login route [1] it would be nice to have it all handled in one function or alteast defined once, but you have to declare both [2]
* Controllers:
Think of Play! controllers as Django class based views(cbv), the only difference is that Play! uses controllers are static, in all intent and purposes they still work the same and allow you to structure your code into sections of your site.
* Data Modeling:
Play! doesn't have an ORM/mapper per-say but they have a small jdbc wrapper that allows you to map your classes using Scala combinators syntax [3]. In a simple app this is easy to do, but you
are still writing SQL and prone to errors. In my case I went with Squeryl [4], I tried to use ScalaQuery (which is now named Slick) but didn't like the api, maybe on my next project I'll
revisit Slick since they have some nice features. By using Squerly I was able to get back the ORM mapping you would get with Django by first defining my Schema in code[5] (also provides sql create statements),Then I was able to easily map to Scala case classes, a win win here.
* Schema Migrations:
The default play doesn't have an eloquent way of managing schema changes, with Django you have South and it works fine most of the time. With play, you have a simple <revision>.sql setup stored in conf/evolutions/.
Simply you tag your "up" and "down" schema changes and run a command in the cli to apply them.
* Templating:
The default Play! template system is pretty robust by its self, you can embed some scala code in it if needed. On thing about the template lang is that you must declare your templates with scala markup,
so if you start a Play! project with Java you will still have to learn a bit of scala. Following with the how type safety of play and JVM technologies, the templates allow follow suite.This is good but sometimes you will run in a few problems when you want to pass a subset of data to templates, it took a while to realize that to access session information inside a template(again this maybe wasn't the best way to handle my problem) you had to declare an "implicit" value to gain an handle to the Request object. There are some other templates like one forked from Grovvy that are more advanced then the default system. But you can get pretty far by using the default templating engine.
* Request Handling:
Now this part I really liked, each request in Play! is handled by an "Action", and you are able to compose multiple actions together and come up with some nice implementations for say validating permissions.
For instance, I needed to validate that a user had access to edit content for a giving dynamic domain and came up with a easy way[6] to just do
and have the associated artist and request all accessible without having to fetch the artist in my controller for example. You can also defer requests that may block so you can retain full non-blocking support throughout your codebase.
* Forms:
Play! has a great form api, its simple and pretty expressive [7] and provides validation, but I ran into the problem where I wanted to convert my posted data set into a Scala case class for instance
or wanted to convert to a Double rather then an Integer. So I had to implement a "Binder" ,to implement this was actually simple then I thought after looking at the source.
With a custom "Binder" I was able to say pass a string to the controller and its associated values and have it marshal to a Scala case class and then simplely invoke my method,
its better to show by example then explain so check out the following [8][9]
So take you have a request like GET stats/metric&range=30days, rather then having to do the request parsing,database fetching in you controller you can create a binder and have it all done for you,
so when it reaches the controller you are working with an data object rather then primitive values (Interger,Strings etc):
As you see you pass a string value for "range" but since you are asking for an Range object, with the Binders Play! will convert in-between the two. The ~ syntax is just my sugar to quickly
apply the range against the chosen metric (in this case the total Plays for an artist for the last 30days) and have it outputted back to the client all in json format (the "g" method is just a helper to convert the
Scala case classes to json string output, I got tired of writing Json.forJson over and over). All the code that handles the actual querying is done by the "Play" metric providing an interface to apply the
"Range" rules onto a predefined query, all type safety. I have to say I was pretty amazed and proud of myself for this setup alone, it made it really easy to build new metrics one I had the framework setup.
* Deploying :
Deploying on Django requires a few extra software to get everything going, you need a webserver and some workers (uwsgi,gunicorn etc). With Play! you just run "play start" into the cli and that’s it.
There is a command to stage your changes that will execute its own start script. But unlike other Java web frameworks there is no need to have container (tomcat for example) in-front of your application,
let along any webserver. This allows for quick development but in production you may want to add a web server or caching proxy in-front of it for best practices but its really isn't needed.
I could probably go into more detail (and may if others see any value) but Play! is a good framework for the Java/Scala community. Its not feature rich as say Django or Rails but with every
problem or "Man I wish this was baked in" it wasn't that hard to do it my self, and this is from a guy that has never developed in Scala and Play! was my first introduction the Scala and the Play!
framework as a whole.Ofcouse there were some "What were they thinking" moments and odd default configurations but you get that with anyframework I would guess. I did have lots of fun in the process and it made coding fun again, so I would definitely use Play! again, it seems now its more polished and some of the problems that I had
have been addressed not the mention the new Json api is just beautiful.
Great writeup, but I have a comment on deploy: do you mean that "play start" can be used for production? Because otherwise, Django has runserver for development. It just shouldn't be used for production.
There is also `play dist` and `play stage`. They both wrap up all necessary assets / dependencies so that you don't even need play installed in order to start a play server (as the play framework jar gets bundled too). We use this for deploying rather than `play start`. The difference between dist and stage is that dist creates a single zip file in the target directory, whereas stage does not. Both create a file named 'start' in the target directory. The docs are not completely clear on that point.
You do not need "play" installed, as Play is using SBT as the package manager.
So without the framework installed and in your PATH, you can just go to an app's directory and do "sbt start". It will download all dependencies needed, compile your app and start the server.
My background in functional program was non-existent at the time so going in I was already going to have problems. I choose to create my project as Scala project since I wanted to learn the tech. While Scala can be done with normal OOP/procedure programming I wanted to have the full affect of using Scala .
(These are my findings over the 2.0.x branches of Play! but should still be relevant to the current branch) Management:
Starting of a project is pretty simple, I have to say the Play! has done a great in baking in a good cli right into their framework and making it easy to plug in your own custom commands. I should mention that I was developing on a Windows 7 machine, in normal cases this wouldn't have been a problem but at the time with the 2.0.x version there were quite a few bugs with the project builder. For one, I couldn't use google closure compiler support due to some path finding issues "\" vs "/" and the stage, staged/start command didn't take windows into mind when generating the script. But for the most part these were small problems. It also has a less compiler ,which had a few problems causing me to patch my local ivy install, but should be all addressed now.
* Routing :
The routing files is located in conf/routes, which has a pretty simple DSL for defining your routes in a simple format :
<http_method> <path or regex> <method with option for defaults>
On thing that was lacking was the option to define multiple http methods for a route, meaning I could have a GET and POST route handled by the same function. While this may not be the best way to handle, but in some cases say with a /login route [1] it would be nice to have it all handled in one function or alteast defined once, but you have to declare both [2]
* Controllers:
Think of Play! controllers as Django class based views(cbv), the only difference is that Play! uses controllers are static, in all intent and purposes they still work the same and allow you to structure your code into sections of your site.
* Data Modeling:
Play! doesn't have an ORM/mapper per-say but they have a small jdbc wrapper that allows you to map your classes using Scala combinators syntax [3]. In a simple app this is easy to do, but you are still writing SQL and prone to errors. In my case I went with Squeryl [4], I tried to use ScalaQuery (which is now named Slick) but didn't like the api, maybe on my next project I'll revisit Slick since they have some nice features. By using Squerly I was able to get back the ORM mapping you would get with Django by first defining my Schema in code[5] (also provides sql create statements),Then I was able to easily map to Scala case classes, a win win here.
* Schema Migrations:
The default play doesn't have an eloquent way of managing schema changes, with Django you have South and it works fine most of the time. With play, you have a simple <revision>.sql setup stored in conf/evolutions/. Simply you tag your "up" and "down" schema changes and run a command in the cli to apply them.
* Templating:
The default Play! template system is pretty robust by its self, you can embed some scala code in it if needed. On thing about the template lang is that you must declare your templates with scala markup, so if you start a Play! project with Java you will still have to learn a bit of scala. Following with the how type safety of play and JVM technologies, the templates allow follow suite.This is good but sometimes you will run in a few problems when you want to pass a subset of data to templates, it took a while to realize that to access session information inside a template(again this maybe wasn't the best way to handle my problem) you had to declare an "implicit" value to gain an handle to the Request object. There are some other templates like one forked from Grovvy that are more advanced then the default system. But you can get pretty far by using the default templating engine.
* Request Handling:
Now this part I really liked, each request in Play! is handled by an "Action", and you are able to compose multiple actions together and come up with some nice implementations for say validating permissions. For instance, I needed to validate that a user had access to edit content for a giving dynamic domain and came up with a easy way[6] to just do
and have the associated artist and request all accessible without having to fetch the artist in my controller for example. You can also defer requests that may block so you can retain full non-blocking support throughout your codebase.* Forms:
Play! has a great form api, its simple and pretty expressive [7] and provides validation, but I ran into the problem where I wanted to convert my posted data set into a Scala case class for instance or wanted to convert to a Double rather then an Integer. So I had to implement a "Binder" ,to implement this was actually simple then I thought after looking at the source. With a custom "Binder" I was able to say pass a string to the controller and its associated values and have it marshal to a Scala case class and then simplely invoke my method, its better to show by example then explain so check out the following [8][9]
So take you have a request like GET stats/metric&range=30days, rather then having to do the request parsing,database fetching in you controller you can create a binder and have it all done for you, so when it reaches the controller you are working with an data object rather then primitive values (Interger,Strings etc):
As you see you pass a string value for "range" but since you are asking for an Range object, with the Binders Play! will convert in-between the two. The ~ syntax is just my sugar to quickly apply the range against the chosen metric (in this case the total Plays for an artist for the last 30days) and have it outputted back to the client all in json format (the "g" method is just a helper to convert the Scala case classes to json string output, I got tired of writing Json.forJson over and over). All the code that handles the actual querying is done by the "Play" metric providing an interface to apply the "Range" rules onto a predefined query, all type safety. I have to say I was pretty amazed and proud of myself for this setup alone, it made it really easy to build new metrics one I had the framework setup.* Deploying :
Deploying on Django requires a few extra software to get everything going, you need a webserver and some workers (uwsgi,gunicorn etc). With Play! you just run "play start" into the cli and that’s it. There is a command to stage your changes that will execute its own start script. But unlike other Java web frameworks there is no need to have container (tomcat for example) in-front of your application, let along any webserver. This allows for quick development but in production you may want to add a web server or caching proxy in-front of it for best practices but its really isn't needed.
I could probably go into more detail (and may if others see any value) but Play! is a good framework for the Java/Scala community. Its not feature rich as say Django or Rails but with every problem or "Man I wish this was baked in" it wasn't that hard to do it my self, and this is from a guy that has never developed in Scala and Play! was my first introduction the Scala and the Play! framework as a whole.Ofcouse there were some "What were they thinking" moments and odd default configurations but you get that with anyframework I would guess. I did have lots of fun in the process and it made coding fun again, so I would definitely use Play! again, it seems now its more polished and some of the problems that I had have been addressed not the mention the new Json api is just beautiful.
[0]https://github.com/cideas/bulabowl [1]https://github.com/cideas/bulabowl/blob/master/app/controlle... [2]https://github.com/cideas/bulabowl/blob/master/conf/routes#L... [3]https://github.com/playframework/Play20/blob/master/samples/... [4]http://squeryl.org [5]https://github.com/cideas/bulabowl/blob/master/modules/commo... [6]https://github.com/cideas/bulabowl/blob/master/app/actions/A... [7]https://github.com/cideas/bulabowl/blob/master/app/models/Fo... [8]https://github.com/cideas/bulabowl/blob/master/app/binders/p... [9]https://github.com/cideas/bulabowl/blob/master/modules/commo... and https://github.com/cideas/bulabowl/blob/master/app/controlle...