Grails Best Practices

 

The following post is based on my upcoming presentation at Springone 2GX, entitled “Grails Gotchas and Best Practices”.

This summer at Zirous we had a group of interns working on a project in Grails. It didn’t take us long to realize how important it was to share these best practices with them. Just because you can do something doesn’t mean you should. These best practices give people excellent guidelines to work with.

Domain-driven design

Begin your domain model classes, starting here will address the important parts of your application. Once you complete this you can let Grails to do the heavy lifting. These domain classes will drive the rest of the development process.  The domain model is structured by the domain and services classes.

It is easy to create a RESTful API in Grails is for a domain class. This can be done by adding the grails.rest.Resource transformation.

import grails.rest.*
@Resource(uri='/books') class Book {
    String title
    static constraints = { 
       title blank:false 
    } 
}

When you create your domain objects Grails creates your test cases too. You can use the test cases to ensure your validations are working correctly and cover your bases.

Validation logic works better in your domain class instead trying to jam it into your controller. If you need to you can easily implement custom validators when needed.

class Player {
    ...

static constraints = { 
    loginName size: 5..15, blank: false, unique: true 
    password size: 5..15, blank: false 
    email email: true, blank: false 
    age min: 18 
    } 
}

Conventions

Grails is a convention driven development which need to follow as per convention means Views should just be views. Controllers should just be controllers contrary to Burt Beckwith’s “Worst Practices”, “Put most of your code in controllers”.

Grails services are transactional by default. It is a best practice to keep the transactional portion of your code in the services. You can shut it off with the transactional property.

class CoachService {
    static transactional = false
}

Make sure to add any functional logic to your services and model objects. Once you pass the request to the controller it can call your service.

Dependency injection is a key component of how Grails works. As you put together the pieces in your Grails application make sure the names and folders(grails-app) line up.

Location

I like to remember the KISS acronym, Keep it Simple Stupid. Make sure your controllers are in the controller folder and services go into the services folder.

Naming

If you have a Player model object, and you need a PlayerController and PlayerService for it. This lets Grails do its magic and auto wire based naming conventions. I know this issue has bitten me a few times. Coming from Java before this I needed to learn this a few times.

Controllers

Put your controllers on a diet. Make sure they don’t have database operations or any business logic in them. It should take the request and send it to a service or domain class and then back.

Command objects can provide validation beyond what your domain class can provide. You can use them for form submission and tricky business logic. It can be used in conjunction with data binding.

@grails.validation.Validateable
class LoginCommand {
    String username
    String password
    static constraints = { 
        username(blank: false, minSize: 6) 
        password(blank: false, minSize: 6) 
     } 
}

Use the standard naming convention of “<DomainClass>Controller”.

Service

Grails services are the place for business logic. You can expose the service as a RESTful web service if needed. A service is transactional by default, but you can make it non-transactional if none of their methods update the database. Common operations should be setup for reuse across the application. 

Domain

If you need to override the getters and setters you can to make the domain properties better to work with. Named queries can be chained together for complex queries. Keep the logic specific to the domain object. Take any complex business logic that deals with groups of objects and put it in the services. Moving domain logic to Services is a hangover of inconvenient persistence layers.

package org.bookstore
class Book { 
     String title 
     Date releaseDate 
     Author author 
}

Plug-ins

Take any re-usable logic and functionality into a Grails plugin, this can remove the complexity from your application and be tested individually. Then you publish your plugin to the public plugin repository(older 2.4 and before, newer versions). You can bootstrap your data during development with fixtures plugins. If you need to make a small change to the plugin you are using, then instead of making the plugin inline for this small change, you can override these files by following the same directory structure or package.

Testing

Grails encourages Test Driven Development approach which means test first so it make sure that your functionality is covered. Test often so you get rapid feedback when something breaks, which makes it easier to fix. This speeds up the development cycle. It also maintains test coverage and avoids gaps in testing as much as possible. As well as being faster to run and debug they also enforce loose coupling better.

What best practices would you add?

Are there any that you think are not needed?

How do you incorporate best practices into your development?

 

No comments yet.

Leave a Reply

Powered by WordPress. Designed by Woo Themes