This article is continuing in the series on exploring Hyperscala. If you have not already done so, I would highly recommend reading the following previous posts as many topics discussed here build on concepts previously discussed:
The Play Framework is perhaps the most popular web framework among Scala developers today. I have been asked quite a few times what is wrong with Play that made me decide against using it and instead write my own web framework. To be fair, Play is a pretty awesome framework and is a great choice for web applications. However, there are a few problems I have with it that led me to choose against using it moving forward:
- Templating Language
- Though Play does a far better job of this than pretty much anyone else I've seen, you're still dealing with special syntax in your HTML templates for accessing your Scala code. This is incredibly problematic when there is a separation of designer and programmer. Life becomes quickly more difficult when the programmer injects all the Play-specific code into the HTML file that came from the designer and then the designer needs to make a change. Not only does it become difficult for the designer to even preview what the content should look like now, but it is highly likely that the designer will mess something up when they are trying to make changes to the HTML. This was something I spent a lot of time considering and trying to come up with a better solution for in Hyperscala. I have worked at a lot of large companies that have teams of designers and teams of developers and it is incredibly painful bridging that gap. In Hyperscala there are actually several solutions to this problem, but the best one for this specific scenario, I believe, is DynamicContent. We've discussed this in a previous post and demonstrated it in yet another post. The idea is keeping the HTML clean and pure and the developer simply loads in only what they need to manipulate by the HTML 'id'. In my opinion, this is the simplest solution and a much cleaner separation between the designer and the developer.
- Yes, there is module support in Play, but it is confusing at best and extremely limited at worst. There is an inherent problem in any framework that doesn't have complete control over the HTML and Play simply does not. The way Play works is very similar to JSPs where content is injected but the HTML is never parsed or comprehended. This leads to several problems when you have modules that need to introduce something like jQuery but shouldn't load it multiple times and want to avoid an issue where another module is trying to load a different version. These are complicated issues that need to be dealt with in large web applications. In Hyperscala the Module system is incredibly powerful and solves all of these problems incredibly well. Not only that, but a Module in Hyperscala is dead simple to write and even more simple to use.
- Complicated Setup
- Any framework that needs its own console in order to create an application is too complicated. Yes, I agree that it's cool that the Play framework has its handy-dandy console utility to create your application for you, setup your IDE, and probably even brush your teeth for you. However, I very much dislike "magic" that happens and is unexplained. I prefer to understand what is going on under the hood and though you can do this in Play, the decision was made as a default route to hide this from the developer. I prefer to work with frameworks in which you add a Maven dependency and then start writing some code. I don't want configuration files. I don't want a bunch of boilerplate code that is generated on my behalf. I want to instantiate something and run it. This is exactly what Hyperscala does. Once you include your Maven dependencies for Hyperscala you need only create an implementation of Website and add a Webpage to be up and running. In Play you have a minimum expectation of an Application.scala, index.scala.html, application.conf, and routes file.
In an effort to compare Hyperscala with Play practically I decided to take an example from Play and re-write it in Hyperscala. My hope was for a simple 'Hello World' example to keep it simple and straight-forward, but what Play considers their 'Hello World' example is quite a bit more than that. It will have to do.
First lets take a look at the Application.scala file:
This is fairly simple. The idea is that this page asks you for your name to display, the number of times to repeat it, and a color. When you hit submit, it validates the form (based on the validations specified near the top of the page) and then either displays errors or writes out the name you specified the number of times you specified in the color you specified. Notice here that the form validation process is hard-coded, so no special handling is necessary. I point this out now because in Hyperscala there is no "default" for how validation should be handled so it takes a little more code (but not much).
Next we take a look at the HTML files defined for the display.hello.scala.html index.scala.html main.scala.html
It's fairly clean and I'm sure once you get used to the Play syntax it becomes easier to grasp. However, this would be quite difficult for a designer to work with. I'm sure there is a better way to represent the page for designers, but then you obviously lose out on much of the power of Play.
Now lets take a look at how this same functionality would look in Hyperscala. Like I've said several times now, there are many ways to accomplish the same task in Hyperscala and this is just one way.
First lets look at the HTML, since this is what we really should start developing from. We can focus on getting the design exactly how we want it before we even think about Hyperscala:play_hello_world.html
This is our basic HTML for the page. Notice there is absolutely nothing specific to Hyperscala or non-HTML in the file at all.play_hello_world_configuration.html
I've extracted the 'configure' page out into this snippet because we're not only going to replicate Play's Hello World example, but we're going to leverage the Realtime module of Hyperscala to avoid doing a POST and thus keep you on the same page for the entire experience. I could have replicated the form posting utilizing FormSupport mixin, but hopefully this will work as a good example of how easy real-time communication is in Hyperscala. Again, notice that there's nothing special about this HTML. It can easily be previewed in the browser and edited by a designer.
Now, lets take a look at our Scala code:PlayHelloWorldPage.scala PlayHelloWorldConfiguration
Not much to see that hasn't already been explained in past examples but there are a few things of note. First, notice the call to Realtime.connectStandard(). This, as the scaladocs says, connects all inputs, textareas, and selects to fire change events and buttons to fire click events to the server. We can do this manually, but this saves us a few lines of code. The other thing of note here is the adding of validation. The 'addValidation' method is received as an implicit conversion on FormFields (input, textarea, and select) by importing org.hyperscala.ui.validation._. We utilize some built-in validations and use the ClassValidationsHandler to apply the error class to the outer container and set the message to the error container when validation fails on a field. Like I said before, how validation works in Hyperscala is not built-in, it's part of the UI sub-project and defines some convenience functionality of how error might be handled, but opens the door to supporting validation errors any way you see fit.
In conclusion, I would argue that while in this example the lines of code may be equivalent, the benefits should be seen particularly for larger applications and for interaction with designers. I do not want this to come off as me bashing Play Framework. I have nothing but respect for the framework and the developers that created and use it. My purpose in this post is merely to compare and contrast the architectural choices in one framework against another and to hopefully better explain why I believe Hyperscala to be a better framework in many situations.
Source code referenced for the Play Hello World example came from Play samples on github:
Source code referenced for the Hyperscala comparison came from Hyperscala examples on github: