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

Writing Domain-Specific Languages in Groovy

Dec 18, 2014

Download

Technology

Presentation on DSLs in Groovy given at JavaZone 2008
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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