DSL's with Groovy

Post on 07-Nov-2014

848 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

DSL's with Groovy presentation (OpenCredo 2011)

Transcript

DSL’s With GroovyPaul Bowler

Senior Consultant, OpenCredo

“Domain-Specific”Languages?

Domain?

–nouna field of action, thought,

influence, etc.

Domains, domains, domains...!

Domain Language?

• Narrow, specialised focus

• Contains syntax and grammar to interact with the domain

• Few, if any, control structures (not ‘Turing Complete’)

• Communicates instructions and configuration

So, like these?

...or these?

yes, ... and no!

What then?

“...most DSL’s are merely a thin facade over a library or framework.”

Martin Fowler, ThoughtWorks

OS

PlatformFramework

DSL

What’s wrong with code?

DeveloperDomain Expert

Cognitive Gap

How do DSL’s help?

• Expressive - Well-designed abstractions

• Simple - Reduce cognitive overhead

• Focussed - Deliver clarity of intent

• Inclusive - Empower the domain expert

What’s wrong with code?

DeveloperDomain Expert

Cognitive Gap

Close the Cognitive Gap

DeveloperDomain Expert

How?

• External DSL - Separate from the ‘main’ languagee.g. SQL, XML, JSON

• Internal DSL - Valid code in the ‘main’ language

• Language Workbench - Specialised ‘IDE’ as editing environment with ‘human-centric’ graphical representation

Why Groovy?

Less noise More sugar

How?

• Builders

• Categories

• Meta-Object Protocol (MOP)

• Abstract Syntax Tree (AST) Transformations

Builders

• Great for hierarchical structures, such as trees, collections of collections, etc.

• Built in support for XML, HTML, Swing, etc

• Roll your own by extending ‘BuilderSupport’ class

Using buildersdef writer = new StringWriter()def xml = new MarkupBuilder(writer)

xml.team(nickname:'DreamTeam') { member(name:'John Smith', age:'32') { nationality('British') job(type:'full-time', 'Java Developer') } member(name:'Sue Perb', age:'25') { nationality('Australian') job(type:'full-time', 'Tester') } member(name:'Fred Bloggs', age:'30') { nationality('Irish') job(type:'contract', 'Build Guru') }}

Builder Methodsclass MyBuilder extends BuilderSupport {

public void setParent(Object parent, Object child) { }

public createNode(Object name) { } public createNode(Object name, Object value) { } public createNode(Object name, Map attributes) { } public createNode(Object name, Map attributes, Object value) { }}

Categories• Allow syntax extensions, e.g:

def nextWeek = today + 7.days

• Any public static method is a candidate to be a category method

• The type of the first parameter is the target type that may have the new methods ‘injected’

• No need to extend a particular class or implement an interface

• Gotcha! Methods added to classes for limited time using ThreadLocal. Also requires wrapping with use() method.

Category Exampleimport org.apache.commons.lang.StringUtils

class StringCategory { static capitalize( String self ){ StringUtils.capitalize(self) }

static normalize( String self ){ self.split("_").collect { word -> word.toLowerCase().capitalize() }.join("") }}

use( StringCategory ) { assert "Groovy" == "groovy".capitalize() assert "CamelCase" == "CAMEL_CASE".normalize()} 

MOP

• Every object inherits from groovy.lang.GroovyObject which contains MetaClass

• ExpandoMetaClass extensions and hooks:invokeMethod(),getProperty(), methodMissing()and propertyMissing()

• Used extensively in Grails - Dynamic Finders (e.g. book.findAllByAuthor)

• Less code and cleaner implementation than categories

• Uses closures and delegates

• Can add or update/overload existing methods

• No need for Use()

• Can overload static methods

• Has longer lifespan than categories

• Inheritance not enabled by default for performance reasons

MOP vs Categories

MOP Example

import org.apache.commons.lang.StringUtils

String.metaClass.capitalize = { StringUtils.capitalize(delegate)}

String.metaClass.normalize = { delegate.split("_").collect { word -> word.toLowerCase().capitalize() }.join("")}

assert "Groovy" == "groovy".capitalize()assert "CamelCase" == "CAMEL_CASE".normalize()

Abstract Syntax Tree

• Compile-time Meta Programming allowing developers to hook into the compilation process

• No runtime performance penalty

• Global transformations using service locator file

• Local transformations using annotations

• Built using... builders!

• Transformations must be performed in one of the nine defined compiler phases

Compilation Phases1. Initialization: source files are opened and environment

configured2. Parsing: the grammar is used to to produce tree of tokens

representing the source code3. Conversion: An abstract syntax tree (AST) is created from

token trees.4. Semantic Analysis: Performs consistency and validity checks that

the grammar can't check for, and resolves classes.5. Canonicalization: Complete building the AST6. Instruction Selection: instruction set is chosen, for example java5

or pre java57. Class Generation: creates the binary output in memory8. Output: write the binary output to the file system9. Finalisation: Perform any last cleanup

It all looks so complicated!

Case Study - Grint‘Groovier Integration!’

Grint

• Groovy DSL for Integration Patterns

• Deployable as a Grails plugin

• Baked for our DSL course

• Already in production...

A Groovier Approach to Integration

• Events cause messages

• EDA 

• See Event-driven IO to get an idea

• Node.js

• Akka

• Even Spring Integration...

Thank you

top related