DSLがモデル上のファサードであるということ

Martin Fowler氏のDSL本では、DSLコード自体より、意味モデル(Semantic Model)の重要性を繰り返し述べている。それは、「Hence the DSL is merely a thin facade over the model.(ゆえに、DSLはモデル上の薄いファサードに過ぎない)」といった文章にも現れている。

ちなみに、DSL本では、意味モデルは以下のように定義されている。

The domain model that’s populated by a DSL

(意味モデルは)DSLによって生成されるドメイン・モデル

Semantic Model is realy just a Domain Model that is populated by the DSL. As with any Domain Model it contains the heart of the behavior for the domain. The the Semantic Model of a DSL is usually a subset of the overal Domain Model for an application. From the Domain Model’s point of view, the DSL is just a fancy alternative way of creating its objects and hooking them together. From the DSL’s point of view the Semantic Model is the output of the overall parsing operation.

意味モデルは単に、DSLによって生成されるドメイン・モデルでしかない。いかなるドメイン・モデルとも同様に、意味モデルは、ドメインの中心となる振る舞いを含んでいる。DSLの意味モデルは、通常、アプリケーションにおける全ドメイン・モデルのサブセットとなる。ドメイン・モデルの観点から、DSLは単にドメイン・モデルのオブジェクトを生成し、結びつける、風変わりな代替手段に過ぎない。DSLの観点からは、意味モデルは全パース処理の出力結果となる。

つまり、アプリケーションとしての本質は(ドメイン・モデルのサブセットである)意味モデルであり、DSLはそれを生成するための「手段の1つ」に過ぎないということである。

以下、サンプルのアプリケーションを用いて、意味モデルとDSLの関係について考えてみる。

サンプル・アプリケーションの概要

サンプルとして、クリティカル・パスを算出するアプリケーションを用いる。

クリティカル・パスとは、プロジェクトにおける各タスクの所要時間と、タスク間の関連が定義された場合に算出できる、「プロジェクト完了までにかかる最長の経路」である。

例えば、SlideShareで公開されている例を見てみる。プロジェクトにおける各タスクとタスク間の関係は、以下のとおり定義されている。

タスク 期間 先行タスク
A 3 -
B 4 A
C 3 B
D 10 B
E 8 D
F 4 D
G 6 D
H 8 C,E,F,G
I 5 H
J 5 H
K 4 I
L 2 J
M 4 K,L

上記から算出される、このプロジェクトにおけるクリティカル・パスは、A→B→D→E→H→I→K→Mとなる(算出アルゴリズムは、SlideShareを参照)。

f:id:GOLEM-XIV:20110103132420p:image

当然ながら、クリティカル・パスを求めるアプリケーションに、DSLは必須ではない。しかしながら、用途によっては、DSLの実装が望ましい場合がある。例えば、プロジェクトにおいてクリティカル・パスが必要になるのは、通常、プロジェクト・マネージャーである。よって、彼のためにDSLを準備してあげるのは、ありうる話である。

DSLのアプリケーションを作成するための順序は、以下のようにするのが一般的だろう。*1

  1. 問題領域に対する、適切なモデルを考える
  2. モデルを生成するDSLを定義する

つまり、重要な意味モデルの検討からはじめ、その後、その意味モデルに対するDSLを定義する。今回のサンプルでも、この順番で検討する。

1. 問題領域に対する、適切なモデルを考える

まずは、この問題を解くためのモデルを考える。この問題領域で扱うのは、スケジュールである。上の図で表現されているとおり、この場合、有向グラフとして扱うのが適切である。つまり、意味モデル(各プロジェクトのスケジュールを表すモデル)は、例えばNodeクラスや、Edgeクラスなどのオブジェクトの関連として、表されることとなる。

ちなみに、DSL本では、アプリケーションの構造を表すモデル(NodeクラスやEdgeクラスなど)を適用モデル(Adaptive Model)、具体的な個々のアプリケーションを、オブジェクト間の関連として表すモデルを、意味モデルと呼んでいる。

後は、この意味モデル上で、クリティカル・パスを計算するアルゴリズムを、コードとして記述するだけである。ここまでで、アプリケーションのコア(スケジュールをモデルとして表し、クリティカル・パスを算出する)は、ほぼ完成したことになる。

2. モデルを生成するDSLを定義する

次に、どのようなDSLを定義するかを検討する。DSLの設計において重要なのは、「誰がそのDSLを使うか」である。その人にとって、そのアプリケーションがどう見えたら自然か、を考えてDSLを定義する。

今回のサンプルでは、例えば以下のような形で、各タスクを定義するDSLを考えることができる。

task
name: A
duration: 3
end
task
name: B
duration: 4
predecessors: A
end
...

あとは、このDSLを解釈し、意味モデルを生成するパーサーを作れば、アプリケーションは完成である。parser generatorを使う場合、DSLを表す文法ファイルを定義し、パーサーを記述することになる。

もう1つのDSL

先ほどのDSLの文法は、プロジェクト・マネージャーにとって、わかりやすいものでは無いかもしれない。例えば、以下のようなDSLコードで、表形式でタスクを定義する方が、わかりやすいかもしれない。

#ID    time predecessors
|A    |3   |-          |
|B    |4   |A          |
|C    |3   |B          |
|D    |10  |B          |
|E    |8   |D          |
|F    |4   |D          |
|G    |6   |D          |
|H    |8   |C,E,F,G    |
|I    |5   |H          |
|J    |5   |H          |
|K    |4   |I          |
|L    |2   |J          |
|M    |4   |K,L        |

このDSLの変更において、意味モデルの変更は一切不要である。必要なのは、DSLから意味モデルを生成するパーサーのみである。つまりアプリケーションの本質である意味モデルは、DSLコードをどのような記法にするかには左右されない。DSLは、意味モデルを生成するための、一手段である。これが、「DSLはモデル上の薄いファサードに過ぎない」という言葉の意味である。

f:id:GOLEM-XIV:20110103235512p:image

また、このようなことができるのも、意味モデルをしっかりと定義しておいたからである。アプリケーションのコア(意味モデル)と、インターフェース(DSLコード)の部分を明確に分けることで、アプリケーションの変更容易性を高めることができる。

まとめ

アプリケーションのコアは、あくまでも意味モデルであり、DSLは、意味モデルへのインターフェースである。インターフェースであるので、用途に応じて変更が可能となる。

ただし、これはDSLがつまらないもの、ということではないことには留意する必要がある。画面UIと同様、DSLも、アプリケーションの使い勝手を決めうる、大事な要素である。

*1:もちろん、意味モデルからではなく、まずDSLのサンプルを作ってみる、という方法もあり。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です