Вы находитесь на странице: 1из 24

Introducing Domain Specic Languages

MARTIN FOWLER
http://martinfowler.com

Tuesday, April 7, 2009

DSLs are everywhere


graphviz CSS ant rake LINQ Hibernate Query Language make FIT

rails validations regular expressions SQL struts-cong.xml

JMock expectations
2

Tuesday, April 7, 2009

Should they be used more often?

Can they be done better?

Tuesday, April 7, 2009

Opening my Secret Panel


Close the door Open the second draw down Turn on the bedside light

Opening the door resets the system and locks the panel

Tuesday, April 7, 2009

Tuesday, April 7, 2009

Abstract Event name code State Machine !

1 start
State name ! action ! Command

source

1 target

! Transition

! ! trigger Event

reset events !

Tuesday, April 7, 2009

Event Event Event Event Event

doorClosed = new Event("doorClosed", "D1CL"); drawOpened = new Event("drawOpened", "D2OP"); lightOn = new Event("lightOn", "L1ON"); doorOpened = new Event("doorOpened", "D1OP"); panelClosed = new Event("panelClosed", "PNCL"); unlockPanelCmd = new Command("unlockPanel", "PNUL"); lockPanelCmd = new Command("lockPanel", "PNLK"); lockDoorCmd = new Command("lockDoor", "D1LK"); unlockDoorCmd = new Command("unlockDoor", "D1UL");

Command Command Command Command

machine.addResetEvents(doorOpened); State State State State State idle = new State("idle"); activeState = new State("active"); waitingForLightState = new State("waitingForLight"); waitingForDrawState = new State("waitingForDraw"); unlockedPanelState = new State("unlockedPanel");

StateMachine machine = new StateMachine(idle); idle.addTransition(doorClosed, activeState); idle.addAction(unlockDoorCmd); idle.addAction(lockPanelCmd); activeState.addTransition(drawOpened, waitingForLightState); activeState.addTransition(lightOn, waitingForDrawState); waitingForLightState.addTransition(lightOn, unlockedPanelState); waitingForDrawState.addTransition(drawOpened, unlockedPanelState); unlockedPanelState.addAction(unlockPanelCmd); unlockedPanelState.addAction(lockDoorCmd); unlockedPanelState.addTransition(panelClosed, idle);

Tuesday, April 7, 2009

<stateMachine start = "idle"> <event name="doorClosed" code="D1CL"/> <event name="drawOpened" code="D2OP"/> <event name="lightOn" code="L1ON"/> <event name="doorOpened" code="D1OP"/> <event name="panelClosed" code="PNCL"/> <command <command <command <command name="unlockPanel" code="PNUL"/> name="lockPanel" code="PNLK"/> name="lockDoor" code="D1LK"/> name="unlockDoor" code="D1UL"/>

<state name="idle"> <transition event="doorClosed" target="active"/> <action command="unlockDoor"/> <action command="lockPanel"/> </state> <state name="active"> <transition event="drawOpened" target="waitingForLight"/> <transition event="lightOn" target="waitingForDraw"/> </state> <state name="waitingForLight"> <transition event="lightOn" target="unlockedPanel"/> </state> <state name="waitingForDraw"> <transition event="drawOpened" target="unlockedPanel"/> </state> <state name="unlockedPanel"> <action command="unlockPanel"/> <action command="lockDoor"/> <transition event="panelClosed" target="idle"/> </state> </stateMachine>

<resetEvent name = "doorOpened"/>

Tuesday, April 7, 2009

events doorClosed drawOpened lightOn doorOpened panelClosed end resetEvents doorOpened end commands unlockPanel lockPanel lockDoor unlockDoor end

D1CL D2OP L1ON D1OP PNCL

state idle actions {unlockDoor lockPanel} doorClosed => active end state active drawOpened => waitingForLight lightOn => waitingForDraw end state waitingForLight lightOn => unlockedPanel end

PNUL PNLK D1LK D1UL

state waitingForDraw drawOpened => unlockedPanel end state unlockedPanel actions {unlockPanel lockDoor} panelClosed => idle end

Tuesday, April 7, 2009

event event event event event

:doorClosed, "D1CL" :drawOpened, "D2OP" :lightOn, "L1ON" :doorOpened, "D1OP" :panelClosed, "PNCL" :unlockPanel, :lockPanel, :lockDoor, :unlockDoor, "PNUL" "PNLK" "D1LK" "D1UL"

state :idle do actions :unlockDoor, :lockPanel transitions :doorClosed => :active end state :active do transitions :drawOpened => :waitingForLight, :lightOn => :waitingForDraw end state :waitingForLight do transitions :lightOn => :unlockedPanel end state :waitingForDraw do transitions :drawOpened => :unlockedPanel end state :unlockedPanel do actions :unlockPanel, :lockDoor transitions :panelClosed => :idle end

command command command command

resetEvents :doorOpened

Tuesday, April 7, 2009

10

External DSL

Internal DSL
(aka Embedded DSL)

state idle actions {unlockDoor lockPanel} doorClosed => active end

state :idle do actions :unlockDoor, :lockPanel transitions :doorClosed => :active end

<state name="idle"> <transition event="doorClosed" target="active"/> <action command="unlockDoor"/> <action command="lockPanel"/> </state>

XML as carrier syntax


11

Tuesday, April 7, 2009

Event Event Event Event Event

doorClosed = new Event("doorClosed", "D1CL"); drawOpened = new Event("drawOpened", "D2OP"); lightOn = new Event("lightOn", "L1ON"); doorOpened = new Event("doorOpened", "D1OP"); panelClosed = new Event("panelClosed", "PNCL");

Is this a DSL?

Command Command Command Command

unlockPanelCmd = new Command("unlockPanel", "PNUL"); lockPanelCmd = new Command("lockPanel", "PNLK"); lockDoorCmd = new Command("lockDoor", "D1LK"); unlockDoorCmd = new Command("unlockDoor", "D1UL");

machine.addResetEvents(doorOpened); State State State State State idle = new State("idle"); activeState = new State("active"); waitingForLightState = new State("waitingForLight"); waitingForDrawState = new State("waitingForDraw"); unlockedPanelState = new State("unlockedPanel");

StateMachine machine = new StateMachine(idle); idle.addTransition(doorClosed, activeState); idle.addAction(unlockDoorCmd); idle.addAction(lockPanelCmd); activeState.addTransition(drawOpened, waitingForLightState); activeState.addTransition(lightOn, waitingForDrawState); waitingForLightState.addTransition(lightOn, unlockedPanelState); waitingForDrawState.addTransition(drawOpened, unlockedPanelState); unlockedPanelState.addAction(unlockPanelCmd); unlockedPanelState.addAction(lockDoorCmd); unlockedPanelState.addTransition(panelClosed, idle);

Tuesday, April 7, 2009

12

public class BasicStateMachine extends StateMachineBuilder { Events doorClosed, drawOpened, lightOn, panelClosed; Commands unlockPanel, lockPanel, lockDoor, unlockDoor; States idle, active, waitingForLight, waitingForDraw, unlockedPanel; ResetEvents doorOpened; protected void defineStateMachine() { doorClosed. code("D1CL"); drawOpened. code("D2OP"); lightOn. code("L1ON"); panelClosed.code("PNCL"); doorOpened. code("D1OP"); unlockPanel.code("PNUL"); lockPanel. code("PNLK"); lockDoor. code("D1LK"); unlockDoor. code("D1UL"); idle .actions(unlockDoor, lockPanel) .transition(doorClosed).to(active) ; active .transition(drawOpened).to(waitingForLight) .transition(lightOn). to(waitingForDraw) ; waitingForLight .transition(lightOn).to(unlockedPanel) ; waitingForDraw .transition(drawOpened).to(unlockedPanel) ; unlockedPanel .actions(unlockPanel, lockDoor) .transition(panelClosed).to(idle) ; } }
Tuesday, April 7, 2009 13

Command-Query API
State idle = new State("idle"); State activeState = new State("active"); idle.addTransition(doorClosed, activeState); idle.addAction(unlockDoorCmd); idle.addAction(lockPanelCmd); activeState.addTransition(drawOpened, waitingForLightState); activeState.addTransition(lightOn, waitingForDrawState);

Fluent API

idle .actions(unlockDoor, lockPanel) .transition(doorClosed).to(active) ; active .transition(drawOpened).to(waitingForLight) .transition(lightOn). to(waitingForDraw) ;

Tuesday, April 7, 2009

14

Domain Specic Language (noun) a computer programming language of limited expressiveness focused on a particular domain

language computer programming focused on a particular domain limited expressiveness


Tuesday, April 7, 2009 15

Execute
DSL Script

optional
Parse

Generate
Semantic Model

Code

Tuesday, April 7, 2009

16

Charles Simonyi Oslo

Language Workbenches
open source eclipse mature made IntelliJ and ReSharper
Tuesday, April 7, 2009

DSL Tools
17

Source Editing
string sentence = I am completely operational, and all + my circuits are functioning perfectly; voice.speak (sentence);

javac hal.java

Tuesday, April 7, 2009

18

Projectional Editing
Model Repository

projections

editor images from metacase


Tuesday, April 7, 2009

generate
19

Source

Projectional

Structured Text
Oslo

Diagrams

DSL Tools
Tuesday, April 7, 2009 20

input =~ /\d{3}-\d{3}-\d{4}/

Tuesday, April 7, 2009

21

p.question { font-style: italic; font-weight: bold; } p.answer { padding: 0 0 0 1em }

Tuesday, April 7, 2009

22

write read
Tuesday, April 7, 2009 23

For more information...


http://www.martinfowler.com/bliki/DomainSpecicLanguage.html

MARTIN FOWLER

http://martinfowler.com

Tuesday, April 7, 2009

24

Вам также может понравиться