I often speak to clients and developers that are pushing the Play Framework as the ideal web framework when developing Scala web applications. I started considering why Play is the framework that people tend to settle on, especially large companies. I think there are a few reasons:
- It's supported by Typesafe *cough*, I mean Lightbend. Certainly Lightbend is the main company supporting Scala and to many people that means you should use whatever technology they are pushing.
- It has commercial support. This is a bleed-over from point #1, but I think warrants its own point. Especially for big companies having the ability to get commercial support is very important. It is unfortunate that truly open-source projects that are entirely community driven are seen as riskier, but typically that is the mentality.
- Play is actively maintained. It has been around for years and is sure to be around and maintained for many to come. Having a long history seems to give a lot of credibility to frameworks whether they deserve it or not.
- It's huge! There are a ton of modules and features that Play has available for your various needs and that provides a compelling option to companies that want to grow and expand and may need those nifty features in the future.
- Easy to get going. The handy-dandy Activator makes creating and managing your application stupid simple (with an emphasis on "stupid"). Especially for people building initial prototypes and evaluating the options available often find this compelling. Activator helps get them going fast without much fussing with the build tools or framework.
- Big companies use it so it must be good! LinkedIn and the Guardian use it and certainly others, so it must be a good choice, right?
These are all important and mostly valid points, but for a developer that has created many web frameworks over the years and has built his fair share of web applications most of these points are not as valid as it might seem on the surface. I'll attempt to address each of them and hopefully give some insight into why I think Play Framework is not the right tool for the job and no matter what you are writing in Scala there are better options available.
- Lightbend backing the framework is definitely a solid point in favor of the framework, but it doesn't mean it's the best framework for Scala. For example, Lightbend also supports Slick, but there are serious performance problems in that framework which led me to create ScalaRelational. For an overview of the crazy performance distinctions between the two frameworks see here (this just scratches the surface, there are simple queries that should take milliseconds to complete that take minutes and up to hours to run).
- Though perhaps one of the most compelling points in favor of Play Framework, commercial support doesn't mean the primary active development on any "supported" framework by Lightbend is being done by Lightbend. These are primarily open-source frameworks that Lightbend has taken it upon themselves to commercially support and most of the actual development is still being done by the open-source community.
- Actively maintained is a very good sign in any framework. Not actively maintained frameworks are incredibly risky unless they have a specific function and aren't currently being maintained because they fulfill that function well and don't need further development. For a web framework that's certainly not the case. The Spring Framework for Java is still actively maintained, but it's a monolithic and painful platform that inspired self-loathing and hate. Many projects start off good or at least good intentioned only to eventually expand themselves into something that has long since lost the focus and benefits of its original intent. I wouldn't say Play has gotten as bad as Spring, but once you get past the dead-simple getting started tutorial, the nitty-gritty of the framework starts to seep into your bones causing maintenance and maintainability nightmares.
- Though having support for the various features you may eventually need built as modules to your framework is very nice, it also often results in the framework itself trying to solve too many problems and ending up solving nothing very well. I try to focus on using frameworks that specifically focused to a specific problem and solve that problem well. When a framework tries to solve too many problems it starts making compromises and watering down the overall benefits of the framework.
- Oh Activator, how I loathe thee! I'm sure it seemed like a good idea to create a shiny wrapper around SBT to help create your project, run it, and even deploy it without being bothered with understanding how building your Scala project actually works. However, it's when you need to manually do something and you realize you don't have a clue how the stupid thing works that it becomes a maintenance nightmare. I'm a software developer, and software developers should be smart enough to create a new project from scratch without needing a tool to hold your hand. If you aren't smart enough to create your build from scratch then you're either an idiot, or the tools are far too complicated. Instead of dumbing down the complex tools by wrapping it, why not attempt to solve the problem by making the tools themselves less painful to learn? Yes, I'm talking to you SBT! What used to be Simple Build Tool has had to change its name to stop the laughter in derision (now Scala Build Tool). SBT has definitely improved recently, but there is still far too much complexity to manage and maintain.
- Big companies make stupid decisions constantly. Web frameworks are one the primary areas in which they make stupid mistakes. You may argue, "but their site works, so it must have been the right choice", but take a look at Facebook's architectural history and you'll see a good example of sheer stupidity leading down a path of pain and the only way they could stay afloat was due to their popularity they could keep throwing money at it. Don't use big business as an example of what you should do. Most companies can't just keep throwing money at a solution until it works, and even ones that can't would be better off spending that money on other things and keep their programmers sane. I've worked for and more recently have consulted for lots of big businesses and even for the US government (the biggest and most wasteful business in the world). I try to avoid consulting for big companies when I can now for this very reason.
These points hopefully address at least the primary reasons many people choose Play Framework, but the answers themselves aren't evidence of why it shouldn't be used, they are simply responses to the common reasoning I hear. My specific reasons why I try to avoid Play are a bit different:
- Templates with their own dialect and learning curve and injecting code directly within. This is just wrong on so many levels. The time it takes to learn Play's specific template dialect is problematic, the injection of code in your templates make things incredibly messy, and don't get me started on the nightmare of trying to refactor code.
- Play Project Structure. Why? Seriously! There is no logical reason to break from the standard of normal Scala projects "src/main/scala" to the mess that is Play's arbitrary and rigid project structure. Not only does this further increase the learning curve, but it makes your code very different from every other Scala project. Again, why? There is no explicit gain from their mediocre project structure changes, and in the latest version you can override it, but it says it's "experimental" and might cause problems.
- Routes file. Again, why? It's a freakin' text file that compiles to Scala. It's unfortunate that Scala doesn't have a powerful DSL that would make more sense than writing a text file...oh wait, it does! I have spent a great deal of time contemplating this and I really have no idea why they would do this. If we were talking about a configuration file that could be changed in production without rebuilding your project that would be one thing, but the routes file is compiled and built into your project.
- Performance is bad. Six months ago I was working on a project and they were experiencing serious performance issues in their web services. They were using Play and PlayJSON. After a little bit of testing I found that the major bottleneck was Play. I quickly swapped out for Spray and uPickle and the performance was then lightning fast, it was fewer lines of code, and the code was much clearer and easier to maintain. Now, I can't generically defend that Play's performance is always bad, and it's possible in the latest releases that it is no longer an issue at all, but the framework has been around for years and there is just no excuse for serious performance issues like that making it into the code.
- Distraction from simplicity. When I work on a project my mantra is, "make it as simple as possible, no more and no less". Developers working on projects have a tendency to over-complicate things and especially among Scala developers attempt to be clever and end up creating a maintenance nightmare for themselves. Developers also focus too much on simplicity and leave glaring holes in functionality or paint themselves into a corner that they can't code themselves out of. A project should be as simple as possible while keeping in mind the overarching goals and a consideration of where the project is going. Play is not a very flexible framework and when you need to diverge for business needs they make it painful to do so.
Wow, I got through an entire post without writing any code. I think this is a first. In summary, yes, I've spewed a lot of hatred towards Play Framework, and though most of it is justified, it is not a horrible framework. I think there are better frameworks like Scala.js, Spray, Finagle, and possibly even Akka-HTTP now if they've resolved some of the missing features and performance problems. I know it's a Java framework, but I've also been pretty impressed with Undertow.
Play Framework developers: If you read this, I apologize for the harshness, but hopefully this can be taken as constructive criticism and I would happily recant in a future post.