43
09/15/2008 Internal Domain-Specific Languages with Groovy Guillaume Laforge

Writing Domain-Specific Languages in Groovy

Embed Size (px)

DESCRIPTION

Presentation on DSLs in Groovy given at JavaZone 2008

Citation preview

Page 1: Writing Domain-Specific Languages in Groovy

09/15/2008

Internal Domain-Specific Languageswith Groovy

Guillaume Laforge

Page 2: Writing Domain-Specific Languages in Groovy

09/15/2008 2

Guillaume Laforge

• Groovy Project Manager• JSR-241 Spec Lead• VP Technology

• Initiator of the Grails framework• Co-author of Groovy in Action

• Speaker at numerous conferences–JavaOne, QCon, JavaDay, Sun TechDays, JavaPolis,

The Spring Experience, JAX, Dynamic Language World...

Page 3: Writing Domain-Specific Languages in Groovy

09/15/2008 3

Agenda

• Introduction to DSLs– Definition, characteristics, motivation

• What Groovy offers– The “MOP”, and Groovy tricks

• Integrating a DSL in your application– JSR-223, GroovyShell, GroovyClassLoader

• Considerations to keep in mind

• Summary• Questions & Answers

Page 4: Writing Domain-Specific Languages in Groovy

09/15/2008

Introduction to DSLs

Page 5: Writing Domain-Specific Languages in Groovy

09/15/2008 5

What’s a DSL?

• DSL: a Domain-Specific Language– Also called a “little language”

• Wikipedia: “A Domain-Specific Language is a programming language designed to be useful for a specific set of tasks”

• A DSL is a language that closely models a certain domain of knowledge or expertise, where the concepts are tied to the constructs of the language

Page 6: Writing Domain-Specific Languages in Groovy

09/15/2008 6

Characteristics of a DSL

• A DSL is a language– not necessarily Turing-complete

• Covers a particular domain of knowledge• Has a form: textual or graphical• Produces a result

– Configures objects, represents data structures, etc.

• Can be internal or external– Embedded in a host language (E-DSL)– Or standalone (usually a custom parser)

• Has certain quality attributes– Readability, writability, usability, testability, extensibility

Page 7: Writing Domain-Specific Languages in Groovy

09/15/2008 7

Examples of DSLs

• Technical– SELECT * FROM USER WHERE NAME LIKE ‘Guil%’– ^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$

• Notation– 1. e4 e5 2. Nf3 Nc6 3. Bb5 a6.– U R' U2 R U R' U R–

• Business– Risk calculation for insurance policies– Bank accounting rules– Human Resources: representation of employees skill set– Anti-malaria drug resistance simulation

Page 8: Writing Domain-Specific Languages in Groovy

09/15/2008 8

Towards more readable code? (1/2)

Page 9: Writing Domain-Specific Languages in Groovy

09/15/2008 8

Towards more readable code? (1/2)

Page 10: Writing Domain-Specific Languages in Groovy

09/15/2008 8

20%

Towards more readable code? (1/2)

Page 11: Writing Domain-Specific Languages in Groovy

09/15/2008 9

Towards more readable code? (1/2)

Page 12: Writing Domain-Specific Languages in Groovy

09/15/2008 9

Towards more readable code? (1/2)

Page 13: Writing Domain-Specific Languages in Groovy

09/15/2008 9

80%

Towards more readable code? (1/2)

Page 14: Writing Domain-Specific Languages in Groovy

09/15/2008 10

Why creating your own DSL?

• Use a more expressive language than a general programming language

• Share a common metaphore between developers and subject matter experts

• Have domain experts help design the business logic of an application

• Avoid cluttering business code with too much boilerplate technical code

• Cleanly seperate business logic from application code

• Let business rules have their own lifecycle

Page 15: Writing Domain-Specific Languages in Groovy

09/15/2008 11

Why Groovy?

• Why Groovy?– It allows you to create Internal / Embedded DSLs– Internal DSLs can be embedded easily

in your Java applications– Groovy lets you use more complex constructs

when you face the limits of your DSL

• Why not a custom parser?– A lexer/parser is complex to implement, maintain & use– It is harder to evolve

• Difficult to implement more complex constructs

Page 16: Writing Domain-Specific Languages in Groovy

09/15/2008

What Groovy offers

Page 17: Writing Domain-Specific Languages in Groovy

09/15/2008 13

Java vs Groovy

• Java– Class behaviour– The compiler knows all about behavior– Behavior hard-wired in the bytecode

• Groovy– Class and MetaClass behaviour

• Dynamic language

– The compiler doesn’t know much about behavior– Behaviour completely dynamic at runtime

Page 18: Writing Domain-Specific Languages in Groovy

09/15/2008 14

Groovy’s MOP to the rescue

• Meta Object Protocol

• Everything’s routed through the MOP– Method calls, property access, operators…– That’s why Groovy is a “dynamic language”

• You can completely customize the runtime behaviour of your Groovy code– Even 1+1=1? Yes! Really?

Page 19: Writing Domain-Specific Languages in Groovy

09/15/2008 15

Hooks into the runtime system

• GroovyObject– invokeMethod()– get/setProperty()

• Categories

• MetaClass– invokeConstructor() / method() / staticMethod()– invokeMissingMethod() / invokeMissingProperty()– get/setProperty()

• ExpandoMetaClass– Integer.metaClass.plus = { Integer i -> 1 }

Page 20: Writing Domain-Specific Languages in Groovy

09/15/2008 16

Operator overloading

• Simply implement certain methods:

– + a.plus(b)– - a.minus(b)– * a.multiply(b)– / a.divide(b)– % a.modulo(b)– | a.or(b)– & a.and(b)– a[b] a.getAt(b)– a << b a.leftShift(b)

– Currency arithmetics– 30.euros + 15.pounds

– Distances– 12.kilo.meters + 3.meters

– Parallelism, workflow– taskA & taskB | taskC

– Credit an account– account << 10.euros– account += 10.dollars

Page 21: Writing Domain-Specific Languages in Groovy

09/15/2008 17

Adding properties to numbers

• Through a category we can add methods & properties on numbers

class MyCategory { static Distance getMeters(Integer n) { new Distance(n, Distance.METER) } }

use (MyCategory) { println 3.meters}

Page 22: Writing Domain-Specific Languages in Groovy

09/15/2008 18

Same thing with EMC

• Grails contributed ExpandoMetaClass back to the Groovy code base

Integer.metaClass.getMeters = { -> new Distance(delegate, Distance.METER) }

println 3.meters

Page 23: Writing Domain-Specific Languages in Groovy

09/15/2008 19

The malleable syntax…

• Optional parentheses– move left– monster.move x: 3.meters, y: 4.meters– compare indicator: ‘NIKEI’, withFund: ‘XYZ’– account.debit amount: 30.euros, in: 3.days

• Native syntax for list and map literals– Lists: [1, 2, 3, 4]– Maps: [a: 1, b: 2, c: 3]– Ranges: Monday..Friday

Page 24: Writing Domain-Specific Languages in Groovy

09/15/2008 20

Builders for tree-structures

• Tree-structured data can be created with chained method calls taking closures as last argument

– new MarkupBuider().invoices { invoice(id: "4") { line "product 1" line "product 2" }}

• You can easily invent your own builder!

Page 25: Writing Domain-Specific Languages in Groovy

09/15/2008 21

BuilderSupport

• Implement BuilderSupport

• Methods to implement– createNode(name)– createNode(name, map)– createNode(name, value)– createNode(name, map, value)

• A value or a closure– nodeCompleted(parent, node)– postNodeCompletion(parent, node)

Page 26: Writing Domain-Specific Languages in Groovy

09/15/2008

A Human Resources DSL

• Skills of employees can be represented hierarchically, under various categories

• etre { idees { capture 2 formule 3 produit 4 }}faire { build { J2EE 4 }}

22

Page 27: Writing Domain-Specific Languages in Groovy

09/15/2008 23

Custom control structures

• You can create your own control structures by passing a closure as last parameter of a method:– unless(account.balance<0, {account.debit 10.dollars})

• Fortunately, there’s a shortcut notation:– unless ( account.balance < 0 ) {

account.debit 10.dollars}

• Creativity is your limit!– withLock (aLock) {…}– transactional { … }– async { … }– execute( within: 50.seconds ) { … }

Page 28: Writing Domain-Specific Languages in Groovy

09/15/2008

Integrating a DSLin your Application

Page 29: Writing Domain-Specific Languages in Groovy

09/15/2008 25

Integration mechanisms

• Java 6: JSR-223 / javax.script.*

• Groovy’s own mechanisms–GroovyShell–GroovyClassLoader

• Spring 2.0 dynamic language beans–Lang namespace–POGO customizer

Page 30: Writing Domain-Specific Languages in Groovy

09/15/2008 26

Java 6’s scripting APIs

• One API to rule them all!

• Scripting.dev.java.net provides a dedicated Groovy engine JAR– Drop it in your classpath!

• Example– ScriptEngineManager manager =

new ScriptEngineManager();ScriptEngine gEngine = manager.getEngineByName("groovy");String result = (String) gEngine.eval("’Foo’ * 2");

Page 31: Writing Domain-Specific Languages in Groovy

09/15/2008 27

Groovy’s own mechanisms

• Groovy offers various means of integrationfrom simple to more complex use cases

–GroovyShell: to evaluate more complex scripts and to let you use most of the Groovy DSL tricks

–GroovyClassLoader: a special class loader which gives you the full power of Groovy

Page 32: Writing Domain-Specific Languages in Groovy

09/15/2008 28

GroovyShell

• Evaluate expressions and scripts

• Pass values in and out through the binding

• Evaluated scripts can have a base class containing global functions or variables

• Method and property access can be intercepted with a base class for evaluated scripts or using a custom MetaClass

Page 33: Writing Domain-Specific Languages in Groovy

09/15/2008 29

GroovyShell example

def binding = new Binding()binding.mass = 22.3binding.velocity = 10.6def shell = new GroovyShell( binding )def expression = "mass * velocity ** 2 / 2" assert shell.evaluate(expression) == 1252.814

Page 34: Writing Domain-Specific Languages in Groovy

09/15/2008 30

GCL example

GroovyClassLoader gcl = new GroovyClassLoader();Class greetingClass = gcl.parseClass( new File("DSL.groovy"));

GroovyObject dsl = (GroovyObject)greetingClass.newInstance();

dsl.setMetaClass(myCustomDSLMetaClass);

Page 35: Writing Domain-Specific Languages in Groovy

09/15/2008 31

Spring 2.x integration

• Spring 2.x provides support for alternative language bean definitions and configuration– A POGO can be wired the like a POJO and be proxied– You can mix languages in your Spring application– POGO and POJO can be injected within each other– You can have Groovy beans “refreshed”!

• useful for DSLs with their own lifecycle

• Configuration of a POGO bean with the specific lang namespace, and a custom MetaClass

– <lang:groovy id="events" script-source="classpath:dsl/eventsChart.groovy" customizer-ref="eventsMetaClass" />

Page 36: Writing Domain-Specific Languages in Groovy

09/15/2008

Considerations to keep in mind

Page 37: Writing Domain-Specific Languages in Groovy

09/15/2008 33

Ensure DSL adoption

• Don’t force adoption!

• But...– Make users build their own DSL!

• Don’t create it alone at your desk• Involve end users regularly• Study how they use the DSL

– Guide users through what’s possible or not• Valid Groovy code

Page 38: Writing Domain-Specific Languages in Groovy

09/15/2008 34

Wash, rinse, repeat

• Iterative process

– Start simple

– Remember you can’t get it right the first time

– Go back brainstorming with subject matter experts, and improve it over time!

Page 39: Writing Domain-Specific Languages in Groovy

09/15/2008 35

Defensive programming

• A DSL should be run in a sandbox– Make sure users can’t crash the app!

• You can use Java’s security!–System.exit(1) anyone?

• Test, test, test!– Fail gracefully– Not just for valid cases: test for errors!– Give meaningful error messages

Page 40: Writing Domain-Specific Languages in Groovy

09/15/2008

Summary

Page 41: Writing Domain-Specific Languages in Groovy

09/15/2008 37

Summary

• DSLs are a great tool for sharing a common metaphor between experts and developers

• DSLs express the domain concepts without the usual boilerplate code

• Groovy’s maleable syntax and dynamic features makes it the perfect choice for creating DSLs and integrating them in a Java application

• Ensure adoption, work iteratively, and use defensive programming to ensure quality

Page 42: Writing Domain-Specific Languages in Groovy

09/15/2008 38

Resources

• Groovy: http://groovy.codehaus.org• Grails: http://grails.org

• Groovy blogs: http://groovyblogs.org• AboutGroovy: http://aboutgroovy.com

• G2One: http://www.g2one.com

Page 43: Writing Domain-Specific Languages in Groovy

09/15/2008

Question & Answers