Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
436 lines (288 sloc) 7.54 KB
title tags
構文ノイズ
language feature
domain specific language

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

ドメイン特化言語について話していると(DSLに限らずあらゆるコンピュータ言語でそうなんだけど)、構文にノイズがあるって話をよく聞く。 RubyはJavaよりもノイズが少ないとか、外部DSLは内部DSLよりノイズが少ないとか。構文ノイズっていうのは、言語としての記述には必要だけど、プログラマがやりたいことには関係のない文字のことだ。ノイズ文字はプログラムの意図をぼかしてしまうため、プログラムの動作を読み解かなければならなくなってしまう。

「構文ノイズ」という言葉も意味があいまいで主観的な言葉なので、ちょっと使いにくかったりする。ちょっと前にGilhad BrahaがJAOOで構文ノイズについて説明しようとしていたが、私も同じようにやってみたいと思う。DSL本のイントロダクションで使ったDSLに適用してみたいと思う(ここの誌面を考えて、状態マシンの例の一部分だけを使っている)。

彼は自分がノイズだと思う文字に色をつけていた。ここで問題となるのは、何をもってノイズ文字とするかである。しかし、ここではそれを定義することは避け、違った分け方をしようと思う。それぞれ「ドメインテキスト」と「句読点」と呼びたい。ここで使っているDSLスクリプトは状態マシンを定義したものなので、 states、events、commandsが存在している。この状態マシンについての情報を記述するもの(状態名など)は、ドメインテキストで定義することにした。それ以外は句読点であり、赤字にしてある。

外部DSLのカスタム構文から始めよう。

events

  doorClosed  D1CL
  drawOpened  D2OP
  lightOn     L1ON

end

   

commands

  unlockDoor D1UL
  lockPanel   PNLK

end

   

state
 idle
  
actions
 
{
unlockDoor lockPanel
}

  doorClosed 
=>
 active

end

   

state
 active
  drawOpened 
=>
 waitingForLight
  lightOn    
=>
 waitingForDraw

end

カスタム構文はノイズを最小化できるので、ここでは句読点があまり見られない。このテキストでは、必要な句読点がはっきりと分かる。 eventsとcommandsは、その名前とコードで定義されている——それぞれを区別するために句読点が必要である。句読点はノイズと等価ではない。間違った句読点や多すぎる句読点がノイズなのだと言えよう。句読点の絶対数を最小にすればいいというわけではない。句読点が少なすぎると、DSLが理解しにくくなる。

次は同じドメイン情報の内部DSLをRubyで書いたものである。

event :
doorClosed
, "
D1CL
"
  

event :
drawOpened
,  "
D2OP
"
  

event :
lightOn
, "
L1ON
"
  


command  :
lockPanel
,   "
PNLK
"
 

command  :
unlockDoor
,  "
D1UL
"
 


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

end
 


state :
active
 do
 
 
 transitions :
drawOpened
 => :
waitingForLight
,
 
              
:
lightOn
 => :
waitingForDraw

end

句読点が増えたのが分かるだろう。句読点をもっと減らすこともできるかもしれないが、カスタム構文よりRubyで書いたDSLのほうが句読点が多くなることは理解していただけるのではないだろうか。ノイズ(私にとってのノイズ)はそれほどない。シンボルを示す「:」、引数を区切る「,」、文字列の引用符「"」くらいだ。

私は、DSLとはフレームワークに息を吹き込む術だと考えている。ここでは、フレームワークは状態マシンを記述している。 DSLだけでなく、プッシュボタン式のAPIを使うこともできる。それでは、句読点を色づけしてみよう。

Event doorClosed = new Event("
doorClosed
", "
D1CL
");
 

Event drawOpened = new Event("
drawOpened
", "
D2OP
");
 

Event lightOn = new Event("
lightOn
", "
L1ON
");
 
 

Command lockPanelCmd = new Command("
lockPanel
", "
PNLK
");
 

Command unlockDoorCmd = new Command("
unlockDoo
r", "
D1UL
");
 


State idle = new State("
idle
");
 

State activeState = new State("
active
");
 
 

StateMachine machine = new StateMachine(
idle
);
 

idle
.addTransition(
doorClosed
,
 activeState
);

idle
.addCommand(
unlockDoorCmd
);

idle
.addCommand(
lockPanelCmd
);


activeState
.addTransition(
drawOpened
, 
waitingForLightState
);

activeState
.addTransition(
lightOn
, 
waitingForDrawState
);

句読点が多くなった。引用符や括弧以外にも、メソッドキーワードやローカル変数の宣言が見られる。後者の分類は興味深い。ローカル変数は宣言の部分では句読点にカウントされているが、あとでドメインテキストとしてカウントされている(名前は同じなのに)。

Javaでも流れるように記述できる。以下はDSL本の流れるバージョンだ。

public class BasicStateMachine extends StateMachineBuilder {
 
  
Events
 doorClosed
, 
drawOpened
,
 lightOn
;
 
  
Commands
 lockPanel
,
 unlockDoor
;
 
  
States 
idle
,
 active
;
 

 
 protected void defineStateMachine() {
 
    doorClosed
. code("
D1CL
");
 
    drawOpened
. code("
D2OP
");
 
    lightOn
.    code("
L1ON
");
 

    lockPanel
.  code("
PNLK
");
 
    unlockDoor
. code("
D1UL
");
 
 
    idle 
       
 .actions(
unlockDoor
,
 lockPanel
)
 
       
 .transition(
doorClosed
).to(
active
)
 
        
;
 
 
    active 
       
 .transition(
drawOpened
).to(
waitingForLight
)
 
       
 .transition(
lightOn
).   to(
waitingForDraw
)
 
 
       ; 
 }

例をいくつか集めたら、必ずやってくるのはXMLだ。

<stateMachine start = "
idle
">
 

    <event name="
doorClosed
" code="
D1CL
"/> 
 

    <event name="
drawOpened
" code="
D2OP
"/>
 

    <event name="
lightOn
" code="
L1ON
"/>
 


    <command name="
lockPanel
" code="
PNLK
"/>
 

    <command 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>
</stateMachine>

この例だと、あまり深いところまでは読み取れないかもしれない。だけど、何らかの思考の糧にはなるんじゃないだろうか。私は、句読点とノイズを明確に分けられるとは思っていない。しかし、ドメインテキストと句読点を区別することで、句読点に集中できるようになるし、句読点の効用についても気づくことができるだろうと思う。 DSLのなかにドメインテキストよりも句読点の文字の方が多いと、それは不吉な臭いだということも付け加えておこう。

(Mikael Jansson がlispバージョンを作ってくれた。Mihailo LalevicがJavaScriptバージョンを作ってくれた。)

You can’t perform that action at this time.