2024: Domino Containers - The Next Step. News from the Domino Container commu...
Practical Groovy Domain-Specific Languages - SpringOne Europe 2009
1. Practical Domain-Specific
Languages with Groovy
All the techniques to create your own DSLs
Guillaume Laforge
Head of Groovy Development
Copyright 2009 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
2. Guillaume Laforge
• Groovy Project Manager
• JSR-241 Spec Lead
• Head of Groovy Development
at SpringSource
• Initiator of the Grails framework
• Co-author of Groovy in Action
• Speaker: JavaOne, QCon, JavaZone, Sun TechDays,
Devoxx, The Spring Experience, JAX, Dynamic
Language World, IJTC, and more...
2
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
3. A few words about Groovy
• Groovy is a dynamic language for the JVM
– with a Meta Object Protocol
– compiles directly to bytecode, seamless Java interop
• Open Source ASL 2 project hosted at Codehaus
• Relaxed grammar derived from Java 5
– + borrowed good ideas from Ruby, Python, Smalltalk
• Fast... for a dynlang on the JVM
• Closures, properties, optional typing, BigDecimal
by default, nice wrapper APIs, and more...
3
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
4. a
d
n
e
g
A
• The context and
the usual issues we face
• Some real-life examples of
Domain-Specific Languages
• Groovy’s DSL capabilities
• Integrating a DSL
in your application
• Considerations to remember
when designing your own DSL
4
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
7. Developer producing
LOLCODE
HAI
CAN HAS STDIO?
I HAS A VAR
IM IN YR LOOP
UP VAR!!1
VISIBLE VAR
IZ VAR BIGGER THAN 10?
KTHXBYE
IM OUTTA YR LOOP
KTHXBYE
9. And in the end...
...nobody understands each other
10. Expressing requirements...
10
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
11. DSL: a potential solution?
• Use a more expressive language than a general purpose one
• Share a common metaphore of understanding between
developers and subject matter experts
• Have domain experts help with the design of the business
logic of an application
• Avoid cluttering business code with too much boilerplate
technical code
• Cleanly separate business logic from application code
• Let business rules have their own lifecycle
11
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
12. Towards more readibility (1)
12
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
13. Towards more readibility (1)
12
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
14. Towards more readibility (1)
20%
12
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
15. Towards more readibility (2)
13
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
16. Towards more readibility (2)
13
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
17. Towards more readibility (2)
80%
13
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
18. a
d
n
e
g
A
• The context and
the usual issues we face
• Some real-life examples of
Domain-Specific Languages
• Groovy’s DSL capabilities
• Integrating a DSL
in your application
• Considerations to remember
when designing your own DSL
14
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
19. A collection of DSLs
• In our everyday life, we’re surrounded by DSLs
– Technical dialects
– Notations
– Business languages
15
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
20. Technical dialects
16
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
27. Business languages
23
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
28. Real-life Groovy examples
• Anti-malaria drug resistance simulation
• Human Resources employee skills representation
• Insurance policies risk calculation engine
• Loan acceptance rules engine for a financial
platform
• Mathematica-like lingua for nuclear safety
simulations
• Market data feeds evolution scenarios
• and more...
24
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
29. a
d
n
e
g
A
• The context and
the usual issues we face
• Some real-life examples of
Domain-Specific Languages
• Groovy’s DSL capabilities
• Integrating a DSL
in your application
• Considerations to remember
when designing your own DSL
25
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
30. A flexible & malleable syntax
• No need to write full-blown classes, use scripts
• Optional typing (def)
– in scripts, you can even omit the def keyword
• Native syntax constructs
• Parentheses & semi-colons are optional
• Named arguments
• BigDecimal by default for decimal numbers
• Closures for custom control structures
• Operator overloading
26
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
31. Scripts vs classes
• Hide all the boilerplate technical code
– an end-user doesn’t need to know about classes
– public class Rule {
public static void main(String[] args) {
System.out.println(“Hello”);
}
}
– println “Hello”
27
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
32. Optional typing
• No need to bother with types or even generics
– unless you want to!
• Imagine an interest rate lookup table method
returning some generified type:
–Rate<LoanType, Duration, BigDecimal>[]
lookupTable() { ... }
def table = lookupTable()
• No need to repeat the horrible generics type info!
28
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
33. Native syntax constructs
• Lists
– [Monday, Tuesday, Wednesday]
• Maps
– [CA: ‘California’, TX: ‘Texas’]
• Ranges
– def bizDays = Monday..Friday
– def allowedAge = 18..65
– You can create your own custom ranges
29
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
34. Optional parens & semis
• Make statements and expressions
look more like natural languages
– move(left);
– move left
30
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
35. Named arguments
• In Groovy you can mix named and unnamed
arguments for method parameters
– named params are actually put in a map parameter
– plus optional parens & semis
• take 1.pill,
of: Chloroquinine,
after: 6.hours
• Corresponds to a method signature like:
–def take(Map m, MedicineQuantity mq)
31
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
36. BigDecimal by default
• Main reason why financial institutions often decide
to use Groovy for their business rules!
– Although these days rounding issues are overrated!
• Java vs Groovy for a simple interpolation equation
• BigDecimal uMinusv = c.subtract(a);
BigDecimal vMinusl = b.subtract(c);
BigDecimal uMinusl = a.subtract(b);
return e.multiply(uMinusv)
.add(d.multiply(vMinusl))
.divide(uMinusl, 10, BigDecimal.ROUND_HALF_UP);
• (d * (b - c) + e * (c - a)) / (a - b)
32
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
37. Custom control structures,
thanks to closures
• When closures are last, they can be put “out” of the
parentheses 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)
33
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
38. Operator overloading
• Currency amounts
a+b a.plus(b)
a-b a.minus(b)
–15.euros + 10.dollars
a*b a.multiply(b)
a/b a.divide(b)
• Distance handling
a%b a.modulo(b)
–10.kilometers - 10.meters
a ** b a.power(b)
a|b a.or(b)
• Workflow, concurrency
a&b a.and(b)
a^b a.xor(b)
–taskA | taskB & taskC
a[b] a.getAt(b)
a << b a.leftShift(b)
• Credit an account
a >> b a.rightShift(b)
–account << 10.dollars
+a a.positive()
account += 10.dollars
-a a.negative()
account.credit 10.dollars
~a a.bitwiseNegate()
34
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
40. Groovy’s MOP
• All the accesses to methods, properties,
constructors, operators, etc. can be intercepted
thanks to the MOP
• While Java’s behavior is hard-wired at compile-
time in the class
• Groovy’s runtime behavior is adaptable at
runtime through the metaclass.
• Different hooks for changing the runtime behavior
– GroovyObject, custom MetaClass implementation,
categories, ExpandoMetaClass
36
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
41. GroovyObject
• All instances of classes created in Groovy
implement the GroovyObject interface:
–getProperty(String name)
–setProperty(String name, Object value)
–invokeMethod(String name, Object[]
params)
–getMetaClass()
–setMetaClass(MetaClass mc)
• A GO can have “pretended” methods and properties
37
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
42. MetaClass
• The core of Groovy’s MOP system
–invokeConstructor()
–invokeMethod() and invokeStaticMethod()
–invokeMissingMethod()
–getProperty() and setProperty()
–getAttribute() and setAttribute()
–respondsTo() and hasProperty()
• MetaClasses can change the behavior of existing
third-party classes — even from the JDK
38
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
43. ExpandoMetaClass
• A DSL for MetaClasses!
• MoneyAmount.metaClass.constructor = { ... }
Number.metaClass.getDollars = { ... }
Distance.metaClass.toMeters = { ... }
Distance.metaClass.static.create = { ... }
• To avoid repetition of Type.metaClass, you can pass
a closure to metaClass { ... }
• The delegate variable in closure represents the
current instance, and it the default parameter
39
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
45. The Groovy MarkupBuilder
• def mkp = new MarkupBuilder()
mkp.html {
head {
title “Groovy in Action”
}
body {
div(width: ‘100’) {
p(class: ‘para) {
span “Best book ever!”
}
}
}
}
41
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
46. A builder for HR
• softskills {
ideas {
capture 2
formulate 3
}
...
}
knowhow {
languages {
java 4
groovy 5
}
...
}
42
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
47. A builder for HR
• softskills {
ideas {
capture 2
formulate 3
}
...
}
knowhow {
languages {
java 4
groovy 5
}
...
}
42
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
48. Builders
• Builders are...
– a mechanism for creating any tree-structered graph
– the realization of the GoF builder pattern at the syntax level
in Groovy
– simply a clever use of chained method invocation, closures,
parentheses omission, and use of the GroovyObject methods
• Existing builders
– XML, Object graph, Swing, Ant, JMX, and more...
43
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
49. The clever trick
• GroovyObject#invokeMethod() is used to catch all
non-existing method calls in the context of the
builder
• The nesting of closures visually shows the level of
nesting / depth in the tree
• builder.m1(attr1:1, attr2:2, { builder.m2(...,
{...}) } becomes equivalent to
builder.m1(attr1:1, attr2:2) { m2(...) {...} }
thanks to parens omission
44
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
50. Adding properties to numbers
• Three possible approaches
– create a Category
•a category is a kind of decorator for default MCs
– create a custom MetaClass
•a full-blown MC class to implement and to set on the
POGO instance
– use ExpandoMetaClass
•friendlier DSL approach but with a catch
45
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
51. With a Category
• class DistanceCategory {
static Distance getMeters(Integer self) {
new Distance(self, Unit.METERS)
}
}
use(DistanceCategory) {
100.meters
}
• Interesting scope: thread-bound & lexical
• But doesn’t work across the hierarchy of classes
– ie. subclasses won’t benefit from the new property
46
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
52. With an ExpandoMetaClass
• Number.metaClass.getMeters = {->
new Distance(delegate, Unit.METERS)
}
100.meters
• Works for the 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 EMC enhancements collisions
47
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
53. Compile-time
metaprogramming
• Groovy 1.6 introduced AST Transformations
• Compile-time == No runtime performance penalty!
Transformation
48
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
54. AST Transformations
• Two kinds of transformations
– Global transformations
•applicable to all compilation units
– Local transformations
•applicable to marked program elements
•using specific marker annotations
49
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
55. Example #1: @Singleton
• Let’s revisit this evil (anti-)pattern
public class Evil {
!
public static final Evil instance = new Evil ();
private Evil () {}
Evil getInstance() { return instance; }
}
• In Groovy
@Singleton class Evil {}
!
• Also a “lazy” version
@Singleton(lazy = true) class Evil {}
!
50
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
56. Example #2: @Delegate
Not just for Managers
• You can delegate to fields of your classes
– class Employee {
def doTheWork() { “done” }
}
class Manager {
@Delegate
Employee slave = new Employee()
}
def god = new Manager()
assert god.doTheWork() == “done”
• Damn manager who will get all the praiser...
51
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
57. Global transformations
• Implement ASTTransformation
• Annotate the transfo specifying a compilation phase
• @GroovyASTTransformation(phase=CompilePhase.CONVERSION)
public class MyTransformation
implements ASTTransformation {
public void visit(ASTNode[] nodes, SourceUnit unit)
{ ... }
}
• For discovery, create the file META-INF/services/
org.codehaus.groovy.transform.ASTTransformation
• Add the fully qualified name of the class in that file
52
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
58. Local transformations
• Same approach as Globale transformations
• But you don’t need the META-INF file
• Instead create an annotation to specify on which
element the transformation should apply
• @Retention(RetentionPolicy.SOURCE)
@Target([ElementType.METHOD])
@GroovyASTTransformationClass(
[quot;fqn.MyTransformationquot;])
public @interface WithLogging {...}
53
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
59. Example: the Spock
framework
• Changing the semantics of the original code
• But keeping a valid Groovy syntax
• @Speck
class HelloSpock {
def quot;can you figure out what I'm up to?quot;() {
expect:
name.size() == size
where:
name << [quot;Kirkquot;, quot;Spockquot;, quot;Scottyquot;]
size << [4, 5, 6]
}
}
54
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
60. a
d
n
e
g
A
• The context and
the usual issues we face
• Some real-life examples of
Domain-Specific Languages
• Groovy’s DSL capabilities
• Integrating a DSL
in your application
• Considerations to remember
when designing your own DSL
55
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
61. Various integration
mechanisms
• Java 6’s javax.script.* APIs (aka JSR-223)
• Spring’s language namespace
• Groovy’s own mechanisms
• But a key idea is to externalize those DSL programs
– DSL programs can have their own lifecycle
– no need to redeploy an application because of a rule
change
– business people won’t see the technical code
56
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
62. Java 6’s javax.script.* API
• Groovy 1.6 provides its own implementation of the
javax.script.* API
• ScriptEngineManager mgr =
new ScriptEngineManager();
ScriptEngine engine =
mgr.getEngineByName(“Groovy”);
String result = (String)engine.eval(“2+3”);
57
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
63. Spring’s lang namespace
• POGOs (Plain Old Groovy Objects) can be pre-
compiled as any POJO and used interchangeably
with POJOs in a Spring application
• But Groovy scripts & classes can be loaded at
runtime through the <lang:groovy/> namespace
and tag
• Reloadable on change
• Customizable through a custom MetaClass
• <lang:groovy id=quot;eventsquot;
script-source=quot;classpath:dsl/
eventsChart.groovyquot;
customizer-ref=quot;eventsMetaClassquot; />
58
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
64. Groovy’s own mechanisms
• Eval
– for evaluating simple expressions
• GroovyShell
– for more complex scripts and DSLs
• GroovyClassLoader
– the most powerful mechanism
59
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
65. Eval
• Simple mechanism to evaluate math-like formulas
• Eval.me ( ‘3*4’)
Eval.x (1, ‘3*x + 4’)
Eval.xy (1, 2, ‘x + y’)
Eval.xyz(1, 2, 3, ‘x * y - z’)
60
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
66. GroovyShell
• A Binding provides a context of execution
– can implement lazy evaluation if needed
• A base script class can be specified
• def binding = new Binding()
binding.mass = 22.3
binding.velocity = 10.6
def shell = new GroovyShell(binding)
shell.evaluate(“mass * velocity ** 2 / 2”)
61
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
67. GroovyClassLoader
• Most powerful mechanism
– could also visit or change the AST
– scripts & classes can be loaded from elsewhere
– more control on compilation
• GroovyClassLoader gcl =
new GroovyClassLoader();
Class clazz = gcl.parseClass(
new File(“f.groovy”));
GroovyObject instance =
(GroovyObject)clazz.newInstance();
instance.setMetaClass(customMC);
62
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
68. Externalize business rules
• Although Groovy DSLs can be embedded in normal
Groovy classes, you should externalize them
• Store them elsewhere
– in a database, an XML file, etc.
• Benefits
– Business rules are not entangled
in technical application code
– Business rules can have their own lifecycle, without
requiring application redeployments
63
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
69. a
d
n
e
g
A
• The context and
the usual issues we face
• Some real-life examples of
Domain-Specific Languages
• Groovy’s DSL capabilities
• Integrating a DSL
in your application
• Considerations to remember
when designing your own DSL
64
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
77. Various levels of
sandboxing
• Groovy supports the usual Java Security Managers
• Use metaprogramming tricks to prevent calling /
instanciating certain classes
• Create a special GroovyClassLoader AST code
visitor to filter only the nodes of the AST you want
to keep
– ArithmeticShell in Groovy’s samples
72
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
78. Test, test, test!
• Don’t just test for nominal cases
– Explicitely test for errors!
• Ensure end-users get meaninful error messages
73
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
79. a
d
n
e
g
A
• Summary
• Questions & Answers
74
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
80. Summary
• Groovy’s a great fit for Domain-Specific Languages
– Malleable & flexible syntax
– Full object-orientation
• Metaprogramming capabilities
– Runtime metaprogramming
– Compile-time metaprogramming
• Groovy’s very often used for mission-critical DSLs
75
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
81. GR8 Conference
• If you wish to learn more about
Groovy, Grails and Griffon, register
for the GR8 Conference
• A conference dedicated to Groovy,
Grails, Griffon and other Groovy
related technologies
• Co-organized by SpringSource and the
Danish JUG (Javagruppen)
• Takes place in Copenhagen,
Denmark, on May 18th and 19th
• Use the code SPRING to get a
discount ;-)
76
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
82. ?
I kan haz my cheezburgr naw?
Or do ya reely haz keshtionz?
83. Appendix
78
Copyright 2008 SpringSource. Copying, publishing or distributing without express written permission is prohibited.