where be dragons

pragmatic grails development


GroovyMN August 2013
@aaronhanson



Uses For Grails


Rapid Protoype Development

grails generate-all


Enterprise Development

grails install-templates

grails create-controller

setProperties() & command objects

DataBinding Docs Link

def user = User.get(id)user.properties = params

slightly better

def userCommand = new UserCommand(params)def user = User.get(id) // still insecure probablybindData(user, params)


Grails 2.3 (new, but similar)

@Transactionaldef update(User user) {    ....    user.save flush:true    ....
}

Fat Controllers


Not always a bad thing.

Prototyping or future legacy code?

Is it used anywhere else?
Maybe OK then. Refactor later.


In larger applications it's unlikely to be a good thing.

Making Database Calls In The View Layer

Prototyping you might do this:

<g:select name="states" from="${State.list()}"/>

But you should probably do this instead:

class FooController {    def list() {        // ...        [states: States.list()]    }}
<g:select name="states" from="${states}"/>


GOTCHA!

 <g:each in="${customer.phoneNumbers.sort()}" var="phoneNumber">

GSPs


Use more templates

Use more taglibs


Be mindful of the need to

.encodeAsHTML()

.encodeAsURL()


g:* tags will do it for you

roll your own or output from model directly,

 you're own your own

Domain vs Concept 

Controllers/Services


OK For CRUD Applications

ProductController

ProductService

Product


Better For Other Applications

CatalogController

ShoppingService

Making everything a service

You're lazy. So am I.


Why do we often create services for everything?

class FooService {    def barService    ...} 


Not everything needs to be a service. 

Libraries with good old fashioned functions are OK too.

src/groovy


Try to keep your app out of your libraries.

smart domains

Quit using your domain classes as services.


Domain instances should operate on the things they know about.


If you need to look up information or do more logic, use a service.

Services are good to funnel calls and add things like caching.


Think about DomainClass.* as DB.* 

Foo.executeQuery('select * from Bar where id = 1')

Doesn't have anything related to Foo. Smell.

Injecting services in your domains


Why?

Is it really a service or is it a library?

Perhaps you're trying to do too much?


Testing can be difficult


Code coupling possibility higher

Making Everything Transactional




Stop it!


custom urlmappings


<g:link>
doesn't always do what you think if you have
multiple mappings to the same thing

order is important, as is length
naming them can help

Be careful with relative and absolute links.

You'll probably be deployed behind a reverse proxy
and can run into issues with link generation.

testing


phases vs test type


unit - fast

integration - slow

functional - slow


Quit writing unitegration tests

(yes I made up a word)

dbcreate vs migrations

dbcreate
great for development
painful for QA (w/o bootstrap)
careful with create/update options vs create-drop

migrations are better for:
deployment
keeping developers in sync
making sure that you don't forget something
(although you still could)

If you can choose, just do auto-migration.
It's just plain easier than running them separately.

Time Left?


Package naming/Plugins


Questions/Heckling?