Slide 1

Slide 1 text

by Mario Fusco twitter: @mariofusco Real world DSL making technical and business people speaking the same language

Slide 2

Slide 2 text

What is a Domain Specific Language? A computer programming language of limited expressiveness focused on a particular domain computer programming language limited expressiveness particular domain

Slide 3

Slide 3 text

2 principles driving toward DSL development Why use a Domain Specific Language?

Slide 4

Slide 4 text

The only purpose of languages, even programming ones IS COMMUNICATION Communication is king

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Written once, read many times Always code as if the person who will maintain your code is a maniac serial killer that knows where you live

Slide 7

Slide 7 text

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand“ Martin Fowler

Slide 8

Slide 8 text

Pros & Cons of DSLs + Expressiveness  Communicativity + Conciseness + Readability  Maintainability  Modificability + Higher level of abstraction + Higher productivity in the specific problem domain ̶ Language design is hard ̶ Upfront cost ̶ Additional indirection layer  Performance concerns ̶ Lack of adequate tool support ̶ Yet-another-language-to-learn syndrome

Slide 9

Slide 9 text

DSL taxonomy External DSL  a language having custom syntactical rules separate from the main language of the application it works with Internal DSL  a particular way of employing a general-purpose language, using only a small subset of the language's features Language workbench  a specialized IDE for defining and building DSL, usually in a visual way, used both to determine the structure of the DSL and to provide an editing environment for people using it

Slide 10

Slide 10 text

Internal DSL External DSL Language Workbench DSL Types Comparison + learning curve + cost of building + programmers familiarity + IDE support (autocompletion …) + composability + flexibility + readability + clear separation between business (DSL) and host language + helpful when business code is written by a separate team (domain experts) ̶ syntactic noise ̶ needs to be recompiled (if host language is static) ̶ need to learn of grammars and language parsing ̶ boundary between DSL and host language ̶ easier to grow out of control + visual + rapid development + IDE support for external DSL ̶ tools immaturity ̶̶ vendor lock-in

Slide 11

Slide 11 text

What is an internal DSL? A (business) internal DSL is a fluent interface built on top of a clearly defined Command & Query API

Slide 12

Slide 12 text

The Command & Query API public interface Car { void setColor(Color color); void addEngine(Engine engine); void add Transmission(Transmission transmission); } public interface Engine { enum Type { FUEL, DIESEL, ELECTRIC, HYDROGEN, METHANE } void setType(Type type); void setPower(int power); void setCylinder(int cylinder); } public interface Transmission { enum Type { MANUAL, AUTOMATIC, CONTINOUSLY_VARIABLE } void setType(Type type); void setNumberOfGears(int gears); }

Slide 13

Slide 13 text

Let's build a car Car car = new CarImpl(); Car.setColor(Color.WHITE); Engine engine1 = new EngineImpl(); engine1.setType(Engine.Type.FUEL); engine1.setPower(73); engine1.setCylinder(4); car.addEngine(engine1); Engine engine2 = new EngineImpl(); engine2.setType(Engine.Type.ELECTRIC); engine2.setPower(60); car.addEngine(engine2); Transmission transmission = new TransmissionImpl(); transmission.setType(Transmission.Type.CONTINOUSLY_VARIABLE); car.setTransmission(transmission);

Slide 14

Slide 14 text

… but you don't expect a (non-technical) domain expert to read this, don't you? Quite good …

Slide 15

Slide 15 text

"Domain users shouldn't be writing code in our DSL but it must be designed for them to understand and validate“ Debasish Ghosh

Slide 16

Slide 16 text

Object Initialization new CarImpl() {{ color(Color.WHITE); engine(new EngineImpl {{ type(Engine.Type.FUEL); power(73); cylinder(4); }}); engine(new EngineImpl {{ type(Engine.Type.FUEL); power(60); }}); transmission(new TransmissionImpl {{ type(Transmission.Type.CONTINOUSLY_VARIABLE); }}); }}; ̶ syntactial noise ̶ explicit use of constructors + clear hierarchic structure + small implementation effort ̶ unclear separation between Command API and DSL

Slide 17

Slide 17 text

Functions Sequence car(); color(Color.WHITE); engine(); type(Engine.Type.FUEL); power(73); cylinder(4); engine(); type(Engine.Type.ELECTRIC); power(60); transmission(); type(Transmission.Type.CONTINOUSLY_VARIABLE); end(); + works well for defining the items of a (top level) list ̶ use of global context variable(s) ̶ hierarchy defined only by identation convention + lowest possible syntactic noise ̶ impossible to enforce right sequence of global function invocation

Slide 18

Slide 18 text

Methods Chaining car() .color(Color.WHITE) .engine() .type(Engine.Type.FUEL) .power(73) .cylinder(4) .engine() .type(Engine.Type.ELECTRIC) .power(60) .transmission() .type(Transmission.Type.CONTINOUSLY_VARIABLE) .end(); + method names act as keyword argument ̶ hierarchy defined only by identation convention + object scoping + works good with optional parameter

Slide 19

Slide 19 text

Nested Functions car( color(Color.WHITE), transmission( type(Transmission.Type.CONTINOUSLY_VARIABLE), ), engine( type(Engine.Type.FUEL), power(73), cylinder(4) ), engine( type(Engine.Type.ELECTRIC), power(60) ) ); + no need for context variables ̶ higher punctuation noise + hierarchic structure is echoed by function nesting ̶ inverted evaluation order ̶ arguments defined by position rather than name ̶ rigid list of arguments or need of methods overloading

Slide 20

Slide 20 text

Is my DSL good (concise, expressive, readable) enough? You cooked the meal … … now eat it! DSL design is an iterative process

Slide 21

Slide 21 text

Mixed Strategy car( color(Color.WHITE), transmission() .type(Transmission.Type.CONTINOUSLY_VARIABLE), engine() .type(Engine.Type.FUEL) .power(73) .cylinder(4), engine() .type(Engine.Type.ELECTRIC) .power(60) ); car( ... ); function sequence for top level lists method chaining for arguments definition nested function for top level object creation

Slide 22

Slide 22 text

Advanced DSL examples

Slide 23

Slide 23 text

Hibernate Criteria Queries List cats = session .createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.between("weight", min, max) ) .addOrder( Order.desc("age") ) .setMaxResults(50) .list();

Slide 24

Slide 24 text

jMock Turtle turtle = context.mock(Turtle.class); // The turtle will be told to turn 45 degrees once only oneOf(turtle).turn(45); // The turtle can be told to flash its LEDs any number // of times or not at all allowing(turtle).flashLEDs(); // The turtle can be asked about its pen any number of times // and will always return PEN_DOWN allowing(turtle).queryPen(); will(returnValue(PEN_DOWN)); // The turtle will be told to stop at least once. atLeast(1).of(turtle).stop();

Slide 25

Slide 25 text

lambdaj Plain Java version: List automaticCars = new ArrayList(); for (Car car : cars) { if (car.getTransmission().getType() == Transmission.TYPE.AUTOMATIC) automaticCars.add(car); } lambdaj version: List salesOfAFerrari = select(cars, having( on(Car.class).getTransmission().getType(), equalTo(Transmission.TYPE.AUTOMATIC) ));

Slide 26

Slide 26 text

Mario Fusco Red Hat – Senior Software Engineer mario.fusco@gmail.com twitter: @mariofusco Q A