Geertjan is a DZone Zone Leader and has posted 468 posts at DZone. You can read more from them at their website. View Full User Profile

Significant Productivity Gains with Grails?

07.09.2009
| 14582 views |
  • submit to reddit

A colleague asked me today: "Would you argue that using Groovy / Grails can make you significantly more productive for smaller projects as compared to something like JSF? If yes, why?" 

In response, I created a very small application. At that point, when the small application was complete, I imagined I had shipped it to the customer. I then imagined that, much later, someone else had been given my sources with the instruction to add a new feature. Below, in two parts, are some general conclusions I drew as a result. Feel free to argue!

Creating the Initial Project

Here's the small application, i.e., an on-line pet cemetery. Everything below was generated by the Grails commands, following the Introduction to the Grails Web Framework, a document that also introduces you to the related NetBeans IDE tools.

There is one addition to what is outlined in the above document, in the context of the page shown below—I used the "grails generate-all" command in order to have Grails generate the controller and views for the domain class I had created. I then had 4 GSP files (i.e., Grails JSP files) which I tweaked slightly to change the texts.

The content above is some test data that I included in the application within the "BootStrap.groovy" file, which is one of several configuration placeholders that every Grails application provides:

class BootStrap {

     def init = { servletContext ->
         new Pet (type: "Cat", name: "Weebles", story: "Run over by tractor.").save()
         new Pet (type: "Cat", name: "Humphrey", story: "Attacked by rabid hamster.").save()
         new Pet (type: "Dog", name: "Mister Sox", story: "Flushed down toilet.").save()
         new Pet (type: "Cat", name: "Lucky Lambkins", story: "Hit in face by newspaper.").save()
         new Pet (type: "Dog", name: "Quincy", story: "Unforeseen avalanche.").save()
     }
    
     def destroy = {
     }
    

Secondly, this is how I created my domain:

class Pet {

String type
String name
String story

static constraints = {
type(blank: false)
name(blank: false)
story(maxSize: 1000)
}

}

Simply by defining a 'maxSize' larger than 255, I end up with a text area for the "story" item, while the "type" and "name" are both represented by text fields:

That's also great because it means... Grails gives me "domain-driven development". That's very powerful, since my domain is where all the knowledge of the application resides. Its structure and relationships, as well as a high-level encapsulation of user requirements, is also held by an application's domain. Really powerful feature of Grails that everything throughout the application is generated from the domain... right up to whether a domain item is represented by a text field or a text area! 

Also, to get the drop-down list containing the types of pets supported, I replaced the input element in the generated "create.gsp" class with the following element:

<g:select from="['Dog', 'Cat']" id="type" name="type"/>

Grails has a number of these special tags that provide out-of-the-box functionality, such as "g:countrySelect", for example, which gives you a drop-down list of country names.

Best of all, whenever I made a change in my application, I only needed to refresh the browser (i.e., no redeploy of the app was necessary) to see my changes.

Adding the New Feature

Next, I imagined I had shipped the above application to my end user. After some time, many dead pets having been registered, the end user wants to have some search functionality added. For whatever reason, someone else ends up tasked with the request. No problem, especially if they already know Grails, since everything in my project is in the same place as every other project that uses Grails (convention over configuration):

So first I create a new GSP file called "search.gsp" (for which I use a file template in NetBeans IDE). Once I had my new GSP page, I looked inside the "list.gsp" page for the place where the link to "New Dead Pet" is defined. (Remember, that list.gsp page, together with all its content, was generated by Grails, hence I didn't do anything in there except tweak some labels.) Having found that element, I simply copied it and then modified it, as follows:

Now, when I refreshed the browser, I saw this:

I clicked the new link and saw this:

Since all actions are defined in the related controller, I added a dummy search action there:

def search = {}

Refreshing the browser, I saw the "search.gsp" page that I had created earlier. The time had come to add some content. I called one of the predefined (i.e., not by me, but by Grails) methods on my domain object, using the IDE's code completion to search for the method I needed:

I ended up with ${Pet.count()} in my GSP page.

Refreshing the browser (i.e., again without doing a redeploy) I saw the result:

Now it was time to get serious! 

In almost no time at all, I created this simple search form...

...which, when the button is clicked, results in the following page being shown:

How to do it?

  1. Create two new GSP pages, one named "search.gsp" and the other "results.gsp".

  2. Copy the header from one of the generated GSP files, so that the look and feel of your pages is the same.

  3. Define the body of "search.gsp" like this:
    <h1>Search</h1>

    <g:form action="results">

      <label>Type</label>
    <g:textField name="type"/>
      <g:submitButton name="search" value="Search"/>

    </g:form>

    <p>Searching ${Pet.count()} pets...

    Take note of the "name" attribute of the textField. Here it is called "type". Also take note of the "action" attribute of the GSP form. Here it is called "results". As a result of the "results" name, when the user clicks the button the "results" action in the controller is called, the "results.gsp" page opens, and the content of the textField is passed in as a parameter accessed via "params.type".

  4. However, the "results" action doesn't exist. Add it as follows to the controller, where ALL the actions are found, which is very convenient of course.
    def results = {
    def pets = Pet.findAllByType(params.type)
    return [ pets: pets, term: params.type ]
    }

    Since we never created the "findAllByType" method on the Pet domain object, we need to spend some time creating that. But, wait a minute! We DON'T need to spend any time creating that because this is one of the many brilliant "dynamic finders" provided by Grails. Based on the definition of our domain object, Grails makes available a set of methods that can be called on our database, simply by passing in the search string received from the user! Here's the list of dynamic finders available to the pet cemetery application, created automatically by Grails for the domain object defined earlier:

    At this point, the "results" action makes two pieces of data available to its matching "results.gsp" page. Firstly, a search term and secondly a list of pets retrieved from the database. And here's the definition of the body of the results page shown earlier:

    <h1>Results for "${term}"</h1>

    <ul>
      <g:each var="pet" in="${pets}">
        <li><b>${pet.name}</b> (${pet.story})
      </g:each>
    </ul>

    Then simply refresh the browser again and you have fully functioning search functionality! It gets a lot more powerful, i.e., this whole "dynamic finder" story, and a lot more complex, but for that you'll need to read "Grails in Action" by Glen Smith and Peter Ledbrooke.

Conclusion

At this point, I can go quite some way in answering the original question: "Would you argue that using Groovy / Grails can make you significantly more productive for smaller projects as compared to something like JSF? If yes, why?"

My answer in the affirmative is based on the following, resulting from the above experiments:

  • Grails creates a project structure and forces everything to be in a specific place, so that I don't have to worry about that and so that whoever ends up extending the application later will immediately know where to find everything.

  • Domain-driven development is great and it's wonderful that Grails forces me to work in that way. All the rules and requirements of my application can be defined and then I can generate the whole application framework around that. When the domain needs to change, I can regenerate the main files again and tweak them where necessary.

  • Built-in validation. Since the fields "type" and "name" are prevented from being blank, via the constraints closure in the domain class, the end user sees red error messages (which can be customized) and is prevented from storing such entries in the database, if either of these fields is blank.

  • Since so many files are generated, I can reuse a lot of the formatting and styles, simply by looking at how Grails did it for me in the other files. For example, the "search.gsp" and "results.gsp" took almost no time to make, since I copied so much from the "create.gsp" and the other generated GSP files.

  • All the actions are in the same place (the controller) and they are tightly connected to specific GSP files.

  • The GSP files have some very powerful tags, so that you can, for example, include a drop-down containing a list of countries or a date/time selector, coupled to your controllers and domain objects, without very much work at all.

  • Database access is handled for you so that, without knowing anything about either Hibernate or Spring, you're using them under the hood. It's also very easy to hook your own database into the application, replacing the in-memory system that Grails applications automatically have access to.

  • The "dynamic finders" are brilliant. I have no idea how they work, but I have no need to know either. They just work and my IDE supports me by showing what's available.

  • Groovy is the icing on the cake or, better put, the cement between the crevices, letting me code far more quickly and intuitively than I would be forced to do in Java.

  • No redeployment necessary during development. Tweak a file, change a controller, whatever, then save and refresh the browser and there's your change.


Anyway, that's what I'll be telling my colleague based on my personal experiences with Grails! Anything else I should be telling him about in this context? Probably quite a lot. For example, I haven't even touched on the built-in testing features yet! But, specifically for smaller projects, what else could be included in my list?

 

AttachmentSize
pet-cemetery-1.png22.81 KB
pet-cemetery-2.png17.54 KB
pet-cemetery-3.png22.23 KB
pet-cemetery-4.png30.37 KB
pet-cemetery-5.png23.29 KB
pet-cemetery-6.png25.34 KB
pet-cemetery-7.png49.54 KB
pet-cemetery-8.png20.44 KB
pet-cemetery-9.png5.77 KB
pet-cemetery-10.png8.84 KB
pet-cemetery-10.png10.01 KB
pet-cemetery-11.png37.58 KB
Published at DZone with permission of its author, Geertjan Wielenga.

Comments

Geoff Longo replied on Thu, 2009/07/09 - 1:41pm

Great article as usual Geertjan!

Andrew Arrigoni replied on Thu, 2009/07/09 - 1:53pm

Some dumb questions from a guy who is only just looking at Groovy and not ever used Grails. How dfficult is it to integrate AJAX type requirements to Grails? JSF gives me some convenient frameworks to use. To use your example app, imagine I wanted the search form to populate the search results on the same page in an AJAXy way. I know how to do this with IceFaces and RichFaces. How would you do this with gsp?

I'd be interested to see you compare a Groovy powered Seam/JPA app w/ JSF/RichFaces that does roughly the same thing. I don't know if there is an equivelent for the Dynamic Finders but I'm no expert.

Eric Muntz replied on Thu, 2009/07/09 - 2:09pm

You'd probably want your colleague to better define 'something like JSF'. Suppose we're talking JBoss Seam and using the accompanying Eclipse tools. You can do very similar things with that environment, in fact I see nothing in your post that can't be easily accomplished with the seamgen tools or the JBoss Tools plugin for Eclipse. For me, the real time saving features of Grails come when you start looking beyond the simple use case of just putting up a CRUD screen or two, and start using Grails plugins. Want simple multiple-domain searching that is insanely configurable? Use the Grails searchable plugin. Want to use OpenID for authentication? Use the OpenID plugin. And so on. There are plugins for soooo many things, it's really quite impressive.

I've also found that doing RESTful applications is really easy with Grails and you'll get nice clean bookmarkable URLs very easily, if that's something important to you.  

There are a lot of powerful things about the framework, but I really don't think a simple CRUD app is going to make an argument for it being easier than something else.

Wai Ho replied on Thu, 2009/07/09 - 2:34pm in response to: Eric Muntz

It is only a simple CRUD app because Grails makes it so simple... :-)

robin bajaj replied on Thu, 2009/07/09 - 3:21pm

Question from a Java developer (still evaluating Grails from the sidelines, haven't gotten time to jump in yet) - Can you use any javascript libraries like jQuery/YUI etc in .gsp files.

tomas lin replied on Thu, 2009/07/09 - 4:18pm

Yes, there are plugins that enable both yui and jquery usage. Grails provides the idea of tags ( like velocity tags ) where you can encapsulate some of the logic. By default, it comes bundled with Prototype and scriptaculous for Ajax. Take a look at the grails plugins section http://www.grails.org/plugin/home

tomas lin replied on Thu, 2009/07/09 - 4:30pm in response to: Andrew Arrigoni

Grails supports Ajax, but the CRUD templates it ships with don't. In Grails, you would just set a div where you would want your results, create a template on the server side that returns the desired HTML block, and add this to your div.

Maurizio Turatti replied on Thu, 2009/07/09 - 7:48pm

Has anybody some performance figures about Grails, comparing to "pure" Java / JSP? I wonder how it behaves in a loaded enterprise site, the risk could be to develop stuff and then discover you have to revert back to Java becuase of speed. Anyway, I'm looking already at Grails and in terms of productivity it is impressive.

 Regards

Sumit Bando replied on Thu, 2009/07/09 - 8:03pm

Talking about keeping knowledge close to the domain model, you can specify that Pet type can be either Cat or Dog, by changing the constraint to: type(inList:['Cat', 'Dog']) and not have to add this manually to the GSP.

Kristian Rink replied on Fri, 2009/07/10 - 1:48am

Hi Geertjan;

very well-written article, as always. :) However, regarding the "productivity gains", I'd like to address one point: Does this still hold true in situations in which one is not in the comfortable situation of "starting from scratch"? Example given, at the moment we're messing with building a more or less convenient user interface to a system that provides backend services via Hessian and, in some places, EJB remoting. Everything in the system from data access to "business" logic is just accessible in such a manner. Would such an environment still benefit from Grails for the "front-end" stuff, or would this mean simply throwing away way too much of the comfortable features Grails offers and instead ending up with custom code all over the place, considering JSF or even plain JSP+Servlets the easier solution after all?

Overally, I am mesmerized by the Grails approach, but I have yet to see it applied to a, well, "real-world" problem not starting off from scratch...

 Cheers,

Kristian

Alessio Spadaro replied on Fri, 2009/07/10 - 3:03am in response to: Kristian Rink

Hi Kristian,

  i think that this kind of scenario is one that grails handles well. Almost everything you can configure throught spring is immediately available for use from grails controllers and services (for ejb see this post and this one ). Integration with Hessian should be even easier using the remoting plugin

Also, you shouldn't have any problem importing any java library on the grails side for immediate use and you can rely on the growing number of plugin to ease the development.

I think that this http://www.opensymbolic.org/ is a good example of grails front-end to several, existing back-end

Best,

 Alessio

Michal Huniewicz replied on Fri, 2009/07/10 - 3:30am

To answer one of the questions: certainly you can use YUI (you need a plugin for this). On the article itself: I think that calling this domain driven design might be a bit far fetched. Yes, generation of almost everything begins with a domain class and yes, they are more than POGOs, but how much of business objects are they? How much logic do they really convey?

Kristian Rink replied on Fri, 2009/07/10 - 3:51am in response to: Alessio Spadaro

Mille grazie, Alessio, you made my weekend. ;) Seriously, thanks a bunch for the hints, I will have a thorough look at each of them and see where it takes me...

 All the best,

K.

Geertjan Wielenga replied on Fri, 2009/07/10 - 4:40am in response to: Sumit Bando

Hi Sumit, thanks! I was wondering about that. But, I've tried it and no list is created. In other words, even though this constraint limits what the user can enter, visually they still see a text field rather than a drop-down list.

mark taylor replied on Sat, 2009/07/11 - 5:47pm

OMFG!  Geertjan can CODE too?!?!?!

 Seriously, nice article BUT essentially meaningless.  Just like Rails, Grails is super productive for apps that fit it's 'Sweet Spot' but for applications out side of this narrow zone, productivety does not match.  The phenomenon should have formal name but as of yet does not. 

I propose:

DSL Domain Impedance Mismath 

Passion Lab replied on Sun, 2012/09/02 - 3:57pm

Then simply refresh the browser again and you have fully functioning search functionality! It gets a lot more powerful, i.e., this whole "dynamic finder" story, and a lot more complex, but for that you'll need to read "term papers online http://www.best-term-paper.us/" by Glen Smith and Peter Ledbrooke.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.