Overview

I've spent the past couple of weeks reading up on Grails, a web application framework inspired by Ruby on Rails. It takes advantage of Groovy, a dynamic programming language that runs on the JVM and is best described as a cross between Java and Ruby. Groovy has support for most existing Java syntax, but also a lot of Ruby-style syntax and dynamic features. To be honest I find that the Java aspects of Groovy (and Grails) drag the whole experience down a bit compared to writing Ruby, but it should be significantly nicer to work with than pure Java.

The big selling point of Groovy and Grails over Ruby on Rails comes from the compatibility with the whole Java ecosystem. You can have your clever dynamic language without giving up the Java libraries and deployment environments that your projects and customers may demand. This is clearly quite a compelling idea if like me you've got a long history of doing big Java web apps but have recently been converted to the dynamic cause.

One thing that is very important to realise is that Grails is not a port of Rails. It is in fact built on top of the Spring stack, including Spring MVC, REST support, dependency injection, transactionality and Hibernate amongst others. If you're already familiar with Spring this is probably a good thing, though I do worry that the framework on top of framework approach could lead to having more to learn (and mess up) overall.

Practical findings

My initial experiments showed an interesting result that rather worried me. I set up a domain class and a controller with def scaffold = true to provide built-in CRUD for my domain class. However the CRUD pages this presented were noticeably sluggish in the browser and benchmarking confirmed it could only manage about 2 requests per second. This is lamentably poor and even now I can't figure out how it's managing to spend so much time achieving not very much.

After a bit of experimentation I determined that if I use grails generate-all to put the scaffolding code in place in my classes (rather than using the dynamic scaffolding) then things speed up enormously. In fact I can now get about 200 requests per second. It's hard to see how there can be such a massive performance gulf between the two scenarios as I would have thought that the only extra overhead for dynamic scaffolding is the initial dynamic intercept of the missing action method and calling into the scaffolding code. Hopefully a Grails expert can explain this, or I will eventually figure it out myself. At least now I have determined that for real-world scenarios there isn't going to be a performance issue, though I am surprised that the Grails docs don't have a massive "Warning – dynamic scaffolding is really slow" box.

For now I haven't done much but read the docs and try a few things. I hope to get deeper into it soon.

3 Comments

  1. Graeme Rocher

    Remember if you run Grails in development mode (grails run-app) it will be slow, since it doesn’t cache anything and performs file / class modification checks. To benchmark Grails create a WAR and deploy it onto your container of choice.

  2. Yes, I was aware of that and was generally using ‘grails prod run-app’ for these benchmarks. I also tried building a war and deploying that, but the performance was still extremely poor for dynamic scaffolding. It’s not a problem – I’m just intrigued to know why it is so.

  3. Graeme, I was wondering if you could help I have to demonstrate tommorrow why grails is appropriate for an application to develop , the trouble i have come across is getting column names from syscolumns with a domain class and controller , which is fine but then on the same page I need the actual data for the table_name in syscolumns that a user choose.
    So:
    If a user selected a COUNTRY table as a static table I get all the column headers and display them in a list action and iterate in the list page to get all the column heading. I now need to get the data back for the first five rows for those headings and have full CRUD, any ideas?

Leave a Reply

Your email address will not be published. Required fields are marked *