Getting Groovy (and Grails)

Explorations in Groovy and Grails Development

The Gr8 Conference: Practical DSLs with Groovy

with 5 comments

This session by Guillaume LaForge was probably the one I was looking forwards to the most. I do a lot of work with Software Product Lines, Domain Specific Modeling and Domain Specific Languages. I’d seen Neil Ford the other month at No Fluff Just Stuff Boston presenting on using Java, Groovy and Ruby for internal DSLs and I was interested to see what Guillaume would cover. Historically Groovy has been somewhere in the middle of Java and Ruby in terms of support for the kind of syntactic sugar that allows for the creation of business user readable DSLs and I was interested to see both how Guillaume presented the topic and what specific information  he’d include.

He started off by introducing the problems that vertical (business – as opposed to horizontal technology DSLs like SQL or RegEx’s) DSLs are designed to solve. They allow for clean separation of business logic from application code, allow Subject Matter Experts/business analysts to read (not necessarily write) the DSLs and allow for business rules to have their own lifecycle independent of the usual re-build, re-deploy lifecycle required when the business logic is encoded in Java.

He mentioned that there are a range of possible notations for DSLs – from the “e4 – e5″ chess notations to the notations used to describe solutions for rubix cubes and sheet music notation. He then also introduced some real world examples of business DSLs such as anti malaria drug resistance simulation, hr employee skill representation, insurance policies risk calculation engine, loan acceptance roles engine for a financial platform, mathematica like lingua for nuclear safety and market data feeds evolution scenarios.

Groovy and DSLs
Groovy has a number of capabilities that make it nicer than Java for implementing business user readable internal DSLs.
– There is no need to write full blown classes – you can use scripts
– Optional typing (def) – cut down on visual noise – in scripts can even omit def
– Native syntax constructs (lists, maps and ranges – can create own custom ranges e.g. monday..friday)
– Optional params (for top level statements) and semicolons so “move(left);” becomes “move left”
– Named arguments: Can mix named and uunnamed – named params are put in a map parameter.
E.g. take 1.pill, of: Chloro after: 6.hours
==     def take(Map m , MedicideQuantity mq)

– Custom control structures: when closures are last they can be put “out” of the parenthesus surrounding parameters
unless (account.balance > 100.euros , {account.debit 100 euros})
== unless (account.balance > 100.euros) {account.debit 100 euros}

Signature “def unless (boolean b , Closure c)”
- Operator overloading: -15.euros + 10.dollars, -10.kilomaters – 10.meters, taskA | taskB & taskC
e.g. a + b – just put a.plus(b) method
e.g. a – b – just put a.minus(b) method
e.g. a * b – just put a.multiply(b) method
etc.

Options for crediting an  account:
account << 10.dollars
account += 10.dollars
account.credit.10.dollars
depends on users which syntax they prefer . . .

Groovy’s dynamic heart: the MOP – The MetaObject Protocol
All accesses to methods, properties, constructuors, operators, etc can be intercepted thanks to the MOP. While Javas behavior is hard wired at compile time in the class, with groovy, behavior is adaptable at runtime through the metaclass.

Different hooks for changing the runtime behavior:

GroovyObject
getProperty() , setProperty , invokeMethod() , getMetaClass() , setMetaClass()
A GO can have “pretend” methods and properties

MetaClass
Core of the Groovy MOP system
– invokeConstructor
– invokeMethpd
– invokeStaticMethod
– invokeMissingMethod
– getProperty
– setProperty
– getAttribute
– setAttribute
– respondsTo
– hasProperty
– Metaclasses can change the behavior of existing third party classes – even java one.

ExpandoMetaClass
- A DSL for metaclasses!
MoneyAbount.metaclass.constructor = { . . }

Note: 10.euros == 10.getEuros()

Class CurrencyAmount {
Number value
String currency
String toString() { “$value $currency”}
}

Number.metaClass.getEuros = { ->
new CurrencyAmount(value: delegate, currency: “EUR”)
}

10.euros
The delegate variable in closure represents the current instance, and “it” the default parameter

The Builder pattern
This is a great pattern for certain classes of DSLs. You’re probably familiar with the markup builder for XML/HTML, but how about having a builder for HR?
softskills {
ideas {
capture 2
formulate 3
}
. . .
}
knowhow {
languages {
java 4
groovy 5
}
. . .
}

Builders are a mechanism, for creating any tree structured graph – a realization of the GoF builder pattern. It uses hooks like GroovyObject#invokeMethod() to catch all non-existing method calls

Adding properties to  Numbers
One of the common approaches when creating a fluent API/DSL in a dynamic language is to add properties to numbers. There are three ways of implementing this in Groovy: create a category, create a custom metaclass or use the ExpandoMetaClass.
– Create a category: A kind of decorator for default MCs. Interesting scope – thread bound and lexical, but doesn’t work across hierarchy of classes (doesn’t work for subclasses).
– Create a custom MetaClass: A full blown MC class to implement and to set on the POGO instance.
– With an expandometaclass: Works for class hierarchy for POJOs and a flag exists to make it work for POGOs too, but the catch is it’s really a global change so beware collisions with other libraries.

Compile time metaprogramming:
Groovy 1.6 now support compile-time metaprogramming via AST transformations. They are compile time, so there is no runtime performance penalty.

There are two kinds of AST transformations available:
– Global – applicable to all compilation units
– Local – applicable to marked (annotated) program elements, using specific market annotations
E.g. added @Singleton and @Delegate

To create a global transformation:
Implement ASTTransformation
Annotate the transformation specifying a compilation phrase

For discovery, create the file META-INF/services/org.codehaus.groovy.transform.ASTTransformation
Add the fully qualified name of the class to that file

Local is same as global, but don’t need to add to meta-inf – just create annotation to specify on which element the transformation should apply.

For example, the Spock framework does this using syntax highjacking with AST transformations to create a BDD framework.

You can pre-compile pogos like pojos in a spring app, but can also load on the fly to decouple the lifecycle of the business rules form that of the application. Also have eval, GroovyShell, or GroovyClassLoaader – most powerful mechanism. Could also visit or change the AST. Scripts and classes can be loaded elsewhere
Groovy DSLs CAN be embedded in groovy classes, but should store elsewhere – database, xml file, etc

Considerations to remember when designing DSL
- Start small with key concepts – beware of over engineering!
– Grow the language progressively, get hands dirty, play with end users
– Let DSL fly – theirs, not yours!
– Tight feedback loop – iterative process
– Stay humble – can’t get it right first time, don’t design alone at your desk – involve the end users from the start!

And if I might add something, check out Eric Evans book on Domain Driven Design. I did an presentation and an interview at ddd.org on using DSM for DDD’ers. I’d also argue that the DSM/DSL community could learn a lot from Erics work on eliciting and developing Ubiquitous Languages – many of which can be executable (making them DSLs).

Maybe play it safe in a sandbox
– Groovy supports usual java security model
– Use metaprogramming tricks to prevent calling or instantiating certain classes
– Create a special GroovyClasLoader AST code visitor to filter only the nodes of the AST you want to keep – e.g. the ArithmeticShell in Groovy’s sample.

- Don’t just test for nominal cases – explicitly test for errors!
– Ensure end users get meaningful error messages

Groovy is often used for mission critical DSLs . . .

That’s the notes I managed to capture from the session. I’d thoroughly recommend catching any of Guillaume’s presentations as in addition to his deep knowledge about Groovy he clearly has a robust understanding of DSM and the practical uses of DSLs. It was a great session both as an intro to DSLs and with lots of detailed information about using Groovy for implementing those languages. I certainly can’t wait to play with Groovy DSLs!

About these ads

Written by peterbell

May 21, 2009 at 10:31 am

Posted in DSLs, gr8, Groovy

5 Responses

Subscribe to comments with RSS.

  1. Great notes Peter!!

    I am a big fan of dsl’s!!

    Luis Majano

    May 21, 2009 at 2:46 pm

  2. [...] Peter Bell’s write-up on Guillaume LaForge’s talk on creating DSLs with Groovy has inspired me to chime in with my [...]

  3. [...] combines Groovy with Swing,  is at here’s a Twitter client in Griffon. Guillaume’s DSL talk was reviewed in detail, and there was lots of [...]

  4. [...] будет Twitter клиент, использующий Griffon. Заметка Guillaume о DSL была досконально изучена, и вызвала бурную дискуссию в [...]

  5. [...] » Last year I posted a fairly comprehensive series of articles on the blog (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) summarizing the content from Gr8 in Copenhagen. This year I opted instead to [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: