Rodrigo Rosenfeld Rosas

Why I Prefer Rails over Grails

Sun, 07 Aug 2011 21:20:00 +0000

I've been willing to write such an article for 2 years now. A recent thread in Grails users mailing list triggered the initiative to finally write it. Actually, I was replying a message but it became too big and I decided to take the chance to write an article on the subject.

Should I use Grails?

That was the thread subject. And the text following is my answer.

I've been working with Grails for more than 2 years now. Before that, I learned Rails in 2007 and like it. I didn't move to Grails because I love Grails though.

I moved because I changed my job and Grails was used in the new job. I've changed my job again last month, initially to work with Rails but then, when they found out that I also knew Groovy and Grails, they decided to offer me another Grails opportunity.

So here I am, working with Grails for probably more two years at least I would guess... Since 2007, I never stopped watching Rails or Ruby closely, so I think I'm pretty able to compare both.

Then, I would say that choosing between them will depend on what you want to achieve. If you want to run your application in a Java web container, maybe Grails is the way to go. I've never deployed a Rails application with JRuby and Warbler, so I'm just guessing.

If you just want to be able to integrate your web application to your legacy Java code, than both Groovy and JRuby will allow you to do that easily. Differently from Groovy, though, JRuby will allow you to "require" jar's at run-time easily. But maybe Grails has better integration with Maven. Again, I say maybe because I never tried to do that with the JRuby + Warbler approach besides really simple experiments.

If you just want to write web applications, than you're in the situation as me and I can help you more on that.

Let me explain to you what are the reasons I prefer Rails myself and what I don't like in Grails. I invite all Grails community to participate in this discussion and help alleviate the shortcomings perceived by me about Grails.

Testing

I don't know if that is your case, but I don't even consider writing a new application without a good test coverage. Unfortunately I was not given the opportunity to do that yet because the companies I worked with didn't want to give me time for writing the tests.

Unfortunately, this seems to be a common approach in Grails community as most of the plugins I used didn't have test coverage, so I guess my companies were not alone. In the other side, it is a strong practice of Rubysts to write tests for their code, including most plugins available. Also, the Rails code base itself has a great test coverage. In the other side I've experienced some bugs in Grails like runtime dependencies added to BuildConfig.groovy not being included in the war in previous releases which suggests me that its test coverage is not comparable with the Rails' one.

Then, if you search for books written entirely about tests for Rails, you'll find lots of them:

Also, testing uses to be one of the first chapters in almost Rails book, reflecting the importance that Ruby and Rails users give to automated testing.

Also, there are tons of projects dedicated to some part of test creation for Ruby:

In the other side, I didn't find a single book specialized in testing Grails applications. I've only seen a single small chapter about testing in Grails in some Grails books. Also, there are lots of great articles and tutorials on Rails testing while I can't find good resources on Grails testing.

Since I prefer specifications over assertions, I started to write some tests for Grails with EasyB. But its documentation and features can't be compared with the Rspec one. Also, I don't find so many alternatives in the Groovy world yet. I have some problems with EasyB, but it was the best I could find and that's what I've being using for testing Groovy and Grails code.

Also, while I can write unit tests for Rails that can actually touch the database, this is not possible with Grails. Grails will force me to use mocks in unit tests. But if part of the logic involves direct queries to the database, which is almost always my situation, then I'm forced to use integration tests for all my tests which, added to the slow boot time for Grails applications, make test writing a very slow task. Also, writing an integration test when actually I want to unit test my class just because of a Grails limitation doesn't seem right for me.

Documentation

Grails documentation is usually sparse with references to Hibernate's documentation, Spring's documentation, Shiro's documentation etc. While I agree that using existent libraries is a good thing, I also like to see a well organized and comprehensive documentation instead of jumping between several sites, each one using a different documentation organization and style. Specially when most of them are crappy for my taste.

In the other side, I usually find great documentation for Rails and its several available plugins with concise information showing how to use them in a glance.

Speed of development

Class automatic reloading

This seems to be changing in Grails 2.0, but for the last 2 years I've had enormous trouble writing Grails application because every change I make in my domain classes (which I do often), Grails will restart my application, loosing any session and spending a lot of time in the rebooting process. This really slows down the development time. This also happens to classes under src/ while doesn't happen to controllers and GSP's.

Necessary time for booting

Compare the time of booting a fresh Grails application with booting a Rails one. Rails will make the application available barely instantly. This becomes more annoying when Grails will insist in rebooting after changing some classes and while the application gets bigger or when you do lots of processing in Bootstrap. In Rails, this is super fast in development mode because of the Ruby autoload feature that will allow you to lazily evaluate your classes.

Language API and features

Groovy API is based in Java API, which was badly designed in my opinion. Ruby, differently from Java, will have Date, DateTime and Time classes, for instance. Java, in the other side, has java.util.Date and java.sql.TimeStamp, etc. I've seen people arguing that it's because Ruby is much newer, but actually both languages were born in 1995.

The Ruby API is also very well written in my opinion and has also great documentation. Everything fits great in Ruby while Groovy tries to make some methods simpler adding methods to standard Java classes but still it is built on top of Java's API, which means it couldn't be as well integrated and well-thought as one that was built specifically considering the language features from the beginning.

With regards to the language itself, I really prefer the Ruby way of monkey-patching (reopening classes) and its way of writing meta-programming. Specially, I love Ruby modules and the concept of mixins (instead of supporting multiple inheritance), while I don't think there's something like that in Groovy.

Also, I don't understand why Groovy created a new syntax (""" - triple quotes) for multi-line strings instead of allowing multi-line strings using single quotes just like Ruby. On the other hand, I don't like the fact that Ruby doesn't support multi-line comment like most languages (no, don't tell me that =begin and =end were really intended to be used as multi-line comments).

Dependency management

Ruby had RubyGems for a long time for managing dependencies and easily install gems (libraries, programs). There's a huge repository of Ruby gems. Java has Maven, but Maven doesn't allow you to specify "hibernate > 3.6". You need to be specific.

And then, Maven will try to solve conflicts if you need a dependency that depends in Hibernate 3.6.5 and another one that depends on Hibernate 3.6.6. And Maven will not always be able to solve this dependency well.

In Ruby, suppose one gem depends on "hibernate >= 3.6" and another one depends on "hibernate = 3.6.6". Then RubyGems will be able to choose hibernate 3.6.6. But what if your application depends on latest gem version? Than you don't specify the version and it will fetch the last one. Then, say that some time has passed and another developer needs to replicate the dependencies. It wouldn't be so uncommon that the newest version of one of the dependencies is not compatible anymore with that one used when the application was first developed. For solving this specific problem Rails had a rake task (rake rails:freeze) in its early times that would copy the gems to a vendor folder so that the application could be easily deployed anywhere. But that wasn't a really good solution and then, some years ago, Yehuda Katz released Bundler, which solved this problem by writing a file that recorded all gem versions used in last "bundle" command which allowed that configuration to be replicated anytime without vendoring all gems.

Bundler is a great tool and all Rails application starting from Rails 3.0 use it for managing dependencies. I don't know a similar handy project for Groovy.

Mountable applications

The next version of Rails (3.1.0), soon to be released, will allow mounting some applications in certain paths that could interact with the main app. I guess Django supported this for a longer time, but Grails won't support this feature in 2.0 as far as I know. This is also a great feature.

Memory usage

Unless JRuby is being used, you don't need to previously allocate memory to your application. The memory will increase as it needs more memory. That means you can run lots of Rails application in the same time in your development environment without being concerned about limiting their memory before running the application. That usually means you have more free available RAM.

Database evolution

My first web applications were written in Perl about 15 years ago or more. While at Electrical Engineering college I didn't have lots of web development spending most of my developing time with C and C++, working in embedded and real-time systems.

In 2007, I was back to web development and needed to update my knowledge. When I looked for web frameworks, I was evaluating mostly TurboGears, Django and Rails, after discarding MS .NET and Java-based ones. I didn't know Ruby nor Python at that time so I wasn't biased against any of them. The argument that I really bought while choosing Rails over the other alternatives was the database evolution approach. If I remember correctly, both TurboGears and Django used the same approach used by Grails. You write your domain classes and then generate the database tables based on these classes attributes. I didn't like this approach at all because I was really concerned about database evolution. In the other hand, Rails supported database migrations and the model classes attributes didn't have to be replicated since they would be dynamically fetched from the mapped database table at run-time during Rails initializatin. I really prefer this approach but database migrations only seems to be supported by the Grails framework itself in Grails 2.0, which wasn't released yet by the time I'm writing this.

For a long time we used to "dbCreate=update" in DataSource.groovy and that is simple not maintainable. I hope Grails 2.0 will teach developers best practices like those used by Rails since always.

Framework API

Regarding the framework API itself, I really prefer the Rails API. There are lots of useful DSLs, that I don't find in Grails, specially for defining hooks like before_save, after_save, before_validation, etc. You can specify these hooks in many useful ways and calling them multiple times. Also, instead of static variables you have a declarative DSL for defining associations like has_many, belongs_to, etc. I also always found odd that Grails used closures instead of methods for controller's actions, although this seems to have changed to better in next to be released Grails. Also, I like the fact that Rails generators will create controllers inherited from ApplicationController by default, which means you can add methods to the ApplicationController class if you want to add them to all controllers.

Also, Rails allow me to specify which layout to apply directly in the controller instead of in ERB (GSP equivalent). Also, I don't need to write boilerplate code in my views like in GSPs.

Vim support

I'm a Vim user and Vim support for Groovy indentation and code highlighting is terrible. In the other side, there's good support for the Ruby language and the Rails framework.

Concerns about good default

Rails has always been worried for offering good default for web applications. This is specially true with security concerns. All text will be sanitized inside "<%= ... %>" blocks unless explicitly said not to do that. In Grails you can do that, but that is not set by default and will only work with the "${...}" style, which can't be always used as my long experience with Grails has showed. I'm not sure when they're not allowed through because it never made sense to me... :( But it seems the problem is using this syntax in a nested context like "${[something, "abc: ${2 * someValue}"].join('<br/>')}" but I don't remember exactly.

Interactive console and tab-completion

Another time-saving while writing Rails applications is that auto-complete works in the interactive console (irb) and the "delete" key works as expected in Linux, differently from "groovysh". I've also opened an issue in JIRA presenting a patch to Jline to fix this annoyance that was also present with JRuby at that time. JRuby fixed the problem but groovysh still doesn't behaves correctly with regards to the "delete" key.

The tab-completion will be also available while debugging a Ruby application using the ruby-debugger gem for instance. And I can even debug Ruby applications in Vim, my favorite editor. :)

Hard to debug errors

Errors in GSP's will display unrelated lines. Also, the stack-trace is so big when errors happen, as usual in Java applications, that a friend called them MonsterExceptions.

Both of them were said to be fixed for Grails 2.0 but I didn't test it yet.

Rails errors on the other hand are very precise and easy to find the source of the error.

New code - old behavior

I remember that one of the oddest behavior I experienced while first learning Grails was that after fixing some piece of code that bug persisted and some while later it worked. It was the first time in my life as a programmer that I've seen such behavior. In Rails, when you change some code, the change will be in effect immediately or it won't make effect at all until you restart your application depending on what you're modifying. But since Java didn't support listening to file-system events asynchronously until the recent Java 7, Java applications use to implement file-change monitoring using the poller method. So, it may take a while before your changes make effect and you'll never know if the file was already recompiled or not.

Final words

Actually, I was expecting to write a more detailed article some years ago with more concrete examples but that would take some time and that's the reason why I didn't write it before. But, as I was replying the message by e-mail, the answer was becoming so big that I decided to write such an article even if it's not the way I would like it to be. I hope I get some time in the future to polish it. Also, as I get some feedback from Groovy and Grails users and after Grails 2.0 is finally released, I intend to update this article to reflect the changes and any possible mistake that I could have made, as soon as I get some time.

So, sorry for the unpolished article, but that's what I can currently write. I hope it can be useful anyway. So, good luck in your framework decision, whatever it be!

comments powered byDisqus