A recent project I’ve been working on uses Grails, the Groovy-based Java web platform, patterned on Ruby on Rails. Grails is a Java relational database to web stack built on the well established open source frameworks, Spring and Hibernate. The design philosophy seems to be to take some of the best ideas from Rails and write DSLs (Domain Specific Languages) in Groovy to stitch everything together in a convention-over-configuration style. It’s a great idea in principle, but I think they’ve taken it too far. Here’s why.
It is too automagical. Grails is touted as a productivity tool, because presumably less code needs to be written. The developer can concentrate on writing the application and not on writing infrastructure such as Spring XML files or Hibernate mappings. It’s true that if the conventions are followed, Grails usually behaves as expected. And this is the first problem. One must learn the conventions. There is a learning curve, and so this ramp up time must be subtracted from the expected productivity increase. Of course programmers usually get going as soon as they grasp the basics of a framework. Danger lies here. Because without a deeper understanding of the machinery, it is quite easy with a dynamic language such as Groovy to quickly lose one’s way and lose too much time debugging when things don’t work as expected. And that’s only if you notice things that aren’t working as expected. There is more to productivity than writing less code.
Active Record considered harmful
Briefly, in the active record design pattern, a domain class in an object-oriented language is mapped to a database table and contains fields corresponding to table columns. The class often contains collections of other domain classes mapped to tables that have a foreign key reference. This much is true even for basic Hibernate. But in the active record pattern the domain class also contains all the methods for querying the database. In Rails and Grails this means that in any layer of the application a database query can be made. In the model/view/controller of Grails, the active record is the model, the view is a GSP tag file (similar to Java JSP), and controller classes handle processing of HTTP requests. Grails has a service layer, as well, if you want to use it. But nothing prevents a database operation from being done in a GSP, in a controller, in a domain class method, or in a service. Only design discipline on the part of the developer can separate concerns like presentation, business logic and database operations. My main beef with Active Record is that it’s too easy to write code that’s becomes hard to understand with respect to how it queries the database. Grails makes it so easy to work with the database that programmers start to forget it’s there and begin to treat database calls as if they were simply local method calls. It is easy to query up huge amounts of data and then only use a bit of it. I’m talking about one line of code.
So, if it’s easy to write very inefficient database code, but this speeds up feature delivery, why is it so bad? Everyone know that premature optimization can be a problem, too. The problem, as I see it here, is that when it comes time to optimize, where do you look? If you haven’t been focused on where in the code database queries are being made, it’s going to be a more difficult task.
Like many out-of-the-box Java stacks, Grails brings along a lot of dependencies, both in terms of infrastructure like the versions of Spring and Hibernate and also in terms of Grails plugins. I suppose since Rails has plugins that Grails had to have them. A plugin is basically a Groovy DSL over some common Java library. The upside is the ease of use of a DSL. The downsides are that one must learn the DSL, and one is limited by the capabilities of the DSL, which may only support a subset of the library it wraps. Moreover, plugins have bugs and they bring their own dependencies, both on Grails versions and on the versions of the supporting libraries. That’s a lot of downsides to pay to get a groovy DSL.
Testing in Grails
Grails has DSLs and also classes to support testing. If you have used JUnit TestCase or GroovyTestCase, will you be at home? To some degree, yes. Grails supports unit, integration and functional testing out of the box and you can add Spock (with a plugin, of course). I found the Grails extensions for testing to be confusing. As a programmer with extensive experience with unit testing and mocking libraries like JMock and Mockito, I did not find it simple to dive into the Grails testing mojo. One thing that makes it difficult is again my nemesis, Active Record. Since domain classes have a database dependency to them, they require a testing setup that uses an in-memory database. Grails makes it easy to do, but not easy to understand what’s going on.
Grails brings with it a ‘world view’. It is an opinionated framework that you must conform to. The essential problem, in my view, is that a framework that has made it easy to do something has obscured and made it difficult to understand how it works. It requires more time, even for experienced developers, to become steeped in its conventions, as well as its inner workings, before the productivity starts to roll. And it carries a risk that inexperienced developers will make mistakes that could be costly down the road. Like all powerful software tools, it takes mastering to make it the most effective. I’m not convinced that the time I’d spend mastering Grails would ultimately pay off. I would rather spend the time mastering alternatives.
One last point. I think Groovy is an excellent VM language. It, too, makes it easy to do something with the penalty that it obscures how it works. But the problem in this case is confined to a language and not to a framework. I don’t consider myself a master of Groovy yet, but I do find it worth the time to master.