This document discusses domain specific languages (DSLs). It defines a DSL as a computer programming language with limited expressiveness focused on a particular domain to improve communication. The document discusses why DSLs are used to improve communication and maintainability. It also covers different types of DSLs, including internal and external DSLs. Examples of DSLs like Hibernate queries, jMock, and lambdaj are provided to illustrate DSL design patterns.
React Native vs Ionic - The Best Mobile App Framework
Technical and business people speaking the same language with DSL
1. Real world
DSL
making technical
and business
people speaking
the same language
by Mario Fusco
Red Hat – Senior Software Engineer
mario.fusco@gmail.com
twitter: @mariofusco
2. What is a
Domain Specific Language?
A
computer programming language
of
limited expressiveness
focused on a
particular domain
3. Why use a
Domain Specific Language?
2 principles driving toward
DSL development
4. Communication is king
The only purpose of
languages,
even programming ones
IS COMMUNICATION
5.
6. 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
7. "Any fool can write code
that a computer can
understand.
Good programmers
write code that humans
can understand“
Martin Fowler
8. Pros & Cons of DSLs
+ Expressivity 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 adeguate tool support
̶ Yet-another-language-to-learn syndrome
9. 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
10. DSL Types Comparison
+ learning curve ̶ syntactic noise
+ cost of building ̶ needs to be recompiled
Internal DSL + programmers familiarity (if host language is static)
+ IDE support (autocompletion …)
+ composability
+ flexibility ̶ need to learn of grammars
+ readability and language parsing
External DSL + clear separation between ̶ boundary between DSL
business (DSL) and host language and host language
+ helpful when business code is ̶ easier to grow out of
written by a separate team control
(domain experts)
Language + visual ̶ tools immaturity
Workbench + rapid development ̶ vendor lock-in
+ IDE support for external DSL
11. What is an internal DSL?
A (business) internal DSL is a
fluent interface
built on top of a clearly defined
Command & Query API
12. 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);
}
13. 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);
14. Quite good …
… but you don't expect
a (non-technical)
domain expert to read
this, don't you?
15. "Domain users shouldn't
be writing code in our DSL
but it must be designed
for them to understand
and validate“
Debasish Ghosh
16. Object Initialization
new CarImpl() {{
color(Color.WHITE); + clear hierarchic structure
engine(new EngineImpl {{
type(Engine.Type.FUEL);
power(73); ̶ syntactial noise
cylinder(4);
}});
engine(new EngineImpl {{ ̶ explicit use of constructors
type(Engine.Type.FUEL);
power(60);
}});
transmission(new TransmissionImpl {{
type(Transmission.Type.CONTINOUSLY_VARIABLE);
}});
}}; + small implementation effort
̶ unclear separation between Command API and DSL
17. Functions Sequence
car();
color(Color.WHITE);
+ lowest possible syntactic noise
engine();
type(Engine.Type.FUEL);
power(73); ̶ impossible to enforce right sequence
cylinder(4); of global function invocation
engine();
type(Engine.Type.ELECTRIC);
power(60); ̶ use of global context variable(s)
transmission();
type(Transmission.Type.CONTINOUSLY_VARIABLE);
end();
+ works well for defining the items of a (top level) list
̶ hierarchy defined only by identation convention
18. Methods Chaining
car()
.color(Color.WHITE) + object scoping
.engine()
.type(Engine.Type.FUEL)
.power(73)
.cylinder(4) + method names act as keyword argument
.engine()
.type(Engine.Type.ELECTRIC)
.power(60)
.transmission()
+ works good with optional parameter
.type(Transmission.Type.CONTINOUSLY_VARIABLE)
.end();
̶ hierarchy defined only by identation convention
19. Nested Functions
car(
color(Color.WHITE), + no need for context variables
transmission(
type(Transmission.Type.CONTINOUSLY_VARIABLE),
),
engine( ̶ higher punctuation noise
type(Engine.Type.FUEL),
power(73), ̶ arguments defined by position
cylinder(4) rather than name
),
engine(
type(Engine.Type.ELECTRIC), ̶ rigid list of arguments or
power(60) need of methods overloading
)
); ̶ inverted evaluation order
+ hierarchic structure is echoed by function nesting
20. Is my DSL good
(concise, expressive, readable)
enough?
You cooked the meal …
… now eat it!
DSL design is an iterative process
21. Mixed Strategy
car( nested function for top level object creation
color(Color.WHITE),
transmission()
.type(Transmission.Type.CONTINOUSLY_VARIABLE),
engine()
.type(Engine.Type.FUEL)
.power(73)
.cylinder(4), method chaining for arguments definition
engine()
.type(Engine.Type.ELECTRIC)
.power(60)
);
function sequence for top level lists
car(
...
);
24. 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();
25. lambdaj
Plain Java version:
List<Car> automaticCars = new ArrayList<Car>();
for (Car car : cars) {
if (car.getTransmission().getType() ==
Transmission.TYPE.AUTOMATIC)
automaticCars.add(car);
}
lambdaj version:
List<Sale> salesOfAFerrari = select(cars, having(
on(Car.class).getTransmission().getType(),
equalTo(Transmission.TYPE.AUTOMATIC)
));
26. Q A
Mario Fusco mario.fusco@gmail.com
Red Hat – Senior Software Engineer twitter: @mariofusco