ドメイン駆動設計を実践するために

ドメイン駆動設計の実践に向けて、DDD本では明示的に語られていない視点からドメイン駆動設計をとらえ直す。

導入

ドメイン駆動設計入門では、かなり抽象的なレベルでDDD本の根底にある思想を概観しました。一言で要約すれば「ドメインエキスパートの頭の中にあるドメインをとらえるモデルを共有し、オブジェクト指向パラダイムを用いて、それをソフトウェアの実装に落とし込む」という構想であると言えるでしょう。これを踏まえて今回は、実践のためには何が必要なのか、という問題意識からドメイン駆動設計をとらえ直してみたいと思います。


今回のポイントはプロセスです。DDD本ではほのめかされているにすぎない「モデリングのために行われているもの」に焦点を合わせて、設計とプロセスをどのように融合させていけばよいのかを考えていきたいと思います。ここでの目的はDDD本を批判することではなく、語られない点からとらえ直すことで、ドメイン駆動設計全体に対する理解を深めることにあります。

DDDにおけるプロセス

プロセスとデザインの関係は序文でも語られていますが、そこでのプロセスを見る視点は「イテレーティブ」という開発の性質や、「ドメインエキスパートと開発者との間のインタラクション」という要素にフォーカスされています。ただし、これらについては「アジャイル」と一言で片付けるべきではありません。


イテレーティブなプロセスに関しては、第三部においてモデルの進化はリニアなものではなく、ドメインに対する洞察が深まった時に、突然ブレイクスルーが起きるのだと説明されています。「深いモデル」という概念を使って、モデルレベルのリファクタリングの重要性が説かれているのは大きな特徴と言えるでしょう。また、インタラクションに関しても、モデルを構成する概念を整えていく上で、「会話すること」の重要性が挙げられます。これは会話の中で使うことで、言語としての不十分な部分が際立つことになり、自然と改善されていくという構想です。


こうしたことが、DDD本で語られているプロセスについての考え方と言えます。それでは、いくつか補助線を引くことで語られていないことからDDDの思想を浮かび上がらせていきましょう。

内側と外側

Trygve ReenskaugとJames Coplienは、Doug Engelbartの「コンピュータとは人間の精神を拡張したものである」という思想に端を発する潮流が現在に残したものについて、「インタラクティブでグラフィカルなユーザインタフェースと、世の中のプログラミングにおけるオブジェクト指向言語の隆盛である」とします*1。これはつまり、「ユーザのメンタルモデルを表現するためのパラダイムとしてのオブジェクト指向」と「ソフトウェアの内部に持ち込まれたモデルを操作するためのインタフェース」ということになるのですが、この2つは、実はソフトウェアにおける「外側」と「内側」という2つの側面を端的に表したものであるとも言えます。


このような区別をした場合、ドメイン駆動設計は徹底して「内側」を指向していると言えます。通常であればユーザがシステムについて考える際のインタフェースになるのは、画面や帳票といった文字通りのユーザインタフェースです。したがって、ユーザとのやり取りも、画面や帳票を見せて「この画面ってこういう作りでいいですか?」と確認するものになりがちですが、ドメイン駆動設計においては、ドメインモデルの構造をダイレクトにユーザに見せた上で「ここってこういう考え方でいいんでしょうか?」というやり取りをしようとします。だからこそ、手続き型の実装が嫌われ、表現力のあるモデル/設計が求められることになるのです。


逆に画面/帳票イメージはほぼ登場しません。強いて言えば、第6章の中で集約(AGGREGATE)とロックの関係について議論する際に、画面か帳票のようなもののイメージを使っているくらいで、ユーザと仕様を確認するためのインタフェースという意味での画面/帳票は一切ありません。ただ、実際のソフトウェアを作る上ではユーザインタフェースなしで済ますことはできませんので、ユーザインタフェースをどう設計するか、あるいはユーザインタフェース層とアプリケーション層に対して、ドメイン層をどう組み込んでいくか、ということは、別途考えなければならないことになります。


こうした観点から見直すと、DDD本の中に「クライアント開発者」というロールが見え隠れしていることに気づきます。ドメインモデルが活動する空間となるドメイン層の手前に、アプリケーション層が存在するのと同じように、ドメインモデルを使用してアプリケーションの機能を実現する役割を担った開発者がどうやら存在しているようなのです。一例を示しましょう。

INTENTION-REVEALING INTERFACE
Name classes and operations to describe their effect and purpose, without reference to the means by which they do what they promise. This relieves the client developer of the need to understand the internals.


意図の明白なインタフェース
クラスと操作の名前をつける際には、効果と目的を記述すること。やると約束したことを行う手段には言及してはならない。こうすることで、クライアント開発者はインタフェースの内部を理解しなくてよくなる。
DDD p.247


こうしたクライアント開発者は実装されたモデルを使用しつつ、アプリケーションとしてのふるまいを実装する責任を担っているのであろうと推測されます。

構造とふるまい

同じことを、少し視点を変えて考えてみましょう。ReenskaugとCoplienの両氏はオブジェクト指向について、構造を表現することには長けていたが、ふるまいについてはうまくとらえることができていないと批判し、そこからDCIアーキテクチャの構想を展開していきます。この構造とふるまいという二項対立はドメイン駆動設計においてどう考えるべきでしょうか。


ドメイン駆動設計のモデルが表現しようとしているものが構造だけかと問われれば、それはやはり違うと答えるべきでしょう。しかし、「ふるまいも表現しようとしている」と言い切ってしまうとおそらく語弊があります。ドメインモデルにおいて表現されるふるまいは、そのモデルもしくはそのモデルを構成する概念にとって本質的なふるまいです。逆に言えば、ユーザインタフェースからの入力に対するユーザインタフェースを使った出力という、いわゆる「アプリケーションとしてのふるまい」には言及されていないのです。しかし、実は普段私たちがソフトウェア開発に際して考えているのは、こうした「外側から見たふるまい」なのではないでしょうか。


ドメインモデル設計が「内側」における「ドメインモデルとしてのふるまい」にこだわっている一方で、なんらか「外側」から見た「アプリケーションとしてのふるまい」も考えなければいけないのだとすれば、この両者を統合する視点が必要になるでしょう。

「実験」

DDD本の中に頻出する概念の一つに「実験」(experiment)があります。これが外側と内側を統合する上での鍵を握っています。この実験という概念が分かりやすく使われている箇所をDDD本の中から引用します。

The language, combined with sketches and a brainstorming attitude, turned our discussions into laboratories of the model, in which hundreds of experimental variations could be excersized, tried, and judged. As the team went through senarios, the spoken expressions themselves provided a quick viability test of a proposed model,...


言語をスケッチやブレインストーミングと組み合わせることで、我々の議論の場はモデルの実験室に変わった。そこではモデルの実験用バリエーションを数多く使用し、試し、使えるかどうかを判断することができた。チームがシナリオを詳細に検討する際には、口にする表現自体が、提案されたモデルが実現できるかを調べる簡易的なテストになった。
DDD p.13

つまり、モデルを作成し、共有することはできますが、そのモデルが正しいかどうかを検証することは、モデルだけではできません。モデルの検証は「外側」から、具体的にはシナリオを使って実現されます。実際のシナリオに対して、モデルがどうふるまうかを考えることにより、モデルを検証することができるのです。


こうしたウォークスルーで使用されるシナリオの具体例は、第7章をはじめとして、何ヶ所かで登場します。しかし、そういったシナリオをどういう観点から作成するべきか、あるいはどういうプロセスで作成できるのかということは語られません。したがって、この部分はDDDを実践する際に、自分で橋渡しをするべき場所であると言えます。


こうした観点から見た時に1つのヒントになるのが「ふるまい駆動開発(BDD:Behaviour Driven Development)*2」です。BDDとは、要約すれば、これはテスト駆動の視点を「テスト」から、顧客にとっての価値をもたらす「ふるまい」にシフトさせた考え方であると言えるでしょう。ここで重要なのは、「顧客にとっての価値」という視点です。顧客にとって価値をもたらす、外側から見たときのふるまいが記述できるのであれば、Given/When/Then形式のユーザストーリーであっても、より詳細なユースケース記述であっても、適切なものを選択すればよいと思います。ただ、その仕様が実行可能な形式で記述できていればより好ましいということです。こうしたソフトウェアに対する外側からの記述と、ユーザのメンタルモデルを忠実に表現した内側の実装が疎通した状態を、常に保ち続けること、それはソフトウェア開発における理想型と呼べるものでしょう。

まとめ

内側と外側、およびその疎通という観点から、DDDについて整理してみました。メンタルモデルの実装に関してDDD本では実に深いレベルで記述されていますし、ここでいう外側についても豊かな示唆に富んでいます。顧客の価値を実現可能な形に記述しつつ、効率的にソフトウェアとして実装していくという価値の流れの中に、ドメイン駆動設計を適切に位置づけることは、私たちに与えられた宿題なのかもしれません。




Domain-Driven Design: Tackling Complexity in the Heart of Software

Domain-Driven Design: Tackling Complexity in the Heart of Software

The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends (The Facets of Ruby Series)

The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends (The Facets of Ruby Series)

DCIアーキテクチャの理論とGrailsによる実装

第12回G*ワークショップにて行った講演のスライドと発表原稿

はじめに

11/9にJGGUG様主催にて第12回G*ワークショップが開催されました。そこで、「Model On Grails - DCIアーキテクチャへの道すじ-」と題しまして、DCIアーキテクチャについて講演させて頂きましたので、その際のスライドと発表原稿を公開します。


スライドはこちら


アジェンダは以下の通りです。



導入

今回のテーマは「DCIアーキテクチャ」です。日本では、2010年の1月にJames O. Coplien氏が来日して講演したことで知られるようになりました。Googleグループのメーリングリストを見る限りは未だ黎明期にありますが、何か大きく化けそうな気配を漂わせていると言えるのではないでしょうか。


このDCIアーキテクチャを提唱したのは、Trygve Reenskaug氏です。日本ではそれほど知名度が高くないような気もしますが、実は彼はMVCの提唱者でもあります。モデル・ビュー・コントローラと題された原稿が書かれたのは、1979年のことですから、MVCから30年を経て、今新しいアーキテクチャが生まれようとしている、と言うことができるでしょう。このDCIアーキテクチャの普及にあたって、先頭に立っているのが、James O. Coplien氏です。角谷さんをはじめとした方々の積極的な活動によって、やっと日本でも彼の名前が知られるようになって来ましたが、アジャイルの適用に関する「組織パターン」などを書いている、アジャイル業界ではかなり重要な人物の一人です。


両氏の著作についてはこのブログでもいくつか翻訳していますので、ここでご紹介します。


それでは両氏によって推進されているDCIアーキテクチャとは一体どのようなものなのか、それを生み出した問題意識から始めて、その特徴を確認し、実際にGrails上に乗せるとどのようなコードになるのかを見ていきます。

先駆者たちが遺したもの

まずは、以下の年表を見て下さい。

  • 1963年 Doug Englebart 氏によるマウスの発明
  • 1972年 Alan Kay氏によるダイナブック構想
    • A Personal Computer for Children of All Agesの発表
  • 1979年 Trygve Reenskaug氏によるMVCの提唱

いささか奇異な組み合わせに見えるかもしれませんが、これらの流れの根底には、マウスの発明者であるDoug Engelbart氏の「コンピュータとは人間の精神を拡張したものである」という思想が流れています。Reenskaug氏とCoplien氏によれば、こうした潮流が現在に残してくれたのが、「インタラクティブでグラフィカルなユーザインタフェースと、世の中のプログラミングにおけるオブジェクト指向言語の隆盛である」[Reenskaug & Coplien 2009]とされます。


GUI」と「オブジェクト指向」- これはどういう組み合わせなのでしょうか?モデル・ビュー・コントローラの構想は、ユーザのメンタルモデルをコンピュータの内部に写しとることを意図されたものでした。メンタルモデルとはユーザの世界のとらえ方、ユーザにとっての世界を写し取った精神の構造です*1。この精神のあり方は、概念とその構造を写しとるというオブジェクト指向パラダイムを用いてソフトウェアの中に組み込まれます。


こうしてソフトウェアの内部に組み込まれたモデルをユーザが操作するにあたり、ソフトウェアが提供するインタフェースを使用することになります。この時、ユーザに対してソフトウェアの内部にある自分のメンタルモデルを直接操作しているような感覚を与えるべきだ、という考え方が「直接操作メタファ」と呼ばれるものですが、それを実現する手段が、グラフィカルでインタラクティブユーザインタフェースである、ということになります。


ここまではきわめてシンプルで分かりやすいモデルだと思うのですが、実はこの時、1つ前提とされているものがあります。それが、構造によって思考をとらえるというオブジェクト指向パラダイムであり、さらに言えばその背後にある、人間の思考は構造によってとらえられるという仮説、あるいは、とらえようという戦略です。

オブジェクト指向の死角

Reenskaug氏は「オブジェクト指向の常識」と題された論文の中で、GoFデザインパターンに書かれているある示唆に着目しています[Reenskaug 2008 p.5]。その示唆とは、「システムがどのように動作するのかということについて、コードがすべてを明らかにしているわけではない」[Gamma et al 1995 813-24]というものです。少し文脈を補足する必要があるでしょう。これはオブジェクト指向プログラミングにおいて、実行時の構成がコードの構成とは異なっていることに起因します。コードの構成は「固定化された継承関係」から成り立っており、コンパイル時に確定するのに対して、実行時の構成は「コミュニケーションするオブジェクトという急速に変化するネットワーク」から成り立っています [Gamma et al 1995 788-99]。こうした実行時の構成を見渡せる場所はコードの中にはなく、むしろ、設計者によって規定されるのです[Gamma et al 1995 813-24]。


こうしたオブジェクト指向の性質から生じる帰結について、Reenskaug氏とCoplien氏は、人間の「思考」と「行動」、およびシステムの「構造」と「ふるまい」とを区別した上で、オブジェクト指向は後者をとらえることができていないと指摘します。すなわち、構造をとらえ、表現することはできたが、全体としてのふるまいをとらえることはできなかったというのです。その結果、現在の私たちが置かれているのは、アルゴリズムが各オブジェクトの間に断片化されてしまっており、可変性を担保するのに継承を使わなければならないという状況だとされます[Reenskaug & Coplien 2009]。こうしたとらえ方については批判的すぎるという見方もあるでしょうし、実際に継承を濫用することを戒める風潮はオブジェクト指向プログラミングの内部からも上がっています。Joshua Block氏による「継承よりもコンポジションを好め」という指摘が好例でしょう[Block 2008 p.81]。しかしここでは、オブジェクト指向のプラクティスとして、何が好ましいのかを考えるのではなく、そうした問題をReenskaug氏らがどう乗り越えようとしているのかを見ていきたいと思います。

DCIアーキテクチャ

DCIアーキテクチャの構想の根底には、すべてをクラスで表現することに対する疑問があります。システムがどのようなものであるのか、すなわちシステムに対する「思考」と、システムが何をするのか、というユーザの「行動」を分けて考えれば、これらは重なり合いながらも異なる位相に存在するものであり、同時に異なる境界を引くべきものとなります。ここで、クラスという概念は既に構造を表現するのに使われてしまっているため、別の概念を導入する必要が出てきます。こうしてDCIアーキテクチャの構成要素が登場してきます。


1つめの要素は「データ」です。これは従来のオブジェクト指向と同様にシステムの構造を表現するものです。ただし、ここにはリッチなふるまいが与えられることはなく、基本的な属性とそれに対するアクセッサを持つだけの純粋な構造となります。


次に、肝心のふるまいを表現するにあたっては、新しい概念が導入されます。それが「ロール(役割)」です。前述の記事「新しい構想」では、これを説明するのに「振込」が例として挙げられます。ある口座から別の口座に振り込む際、ユーザのメンタルモデル上はある口座が普通預金口座なのか、定期預金口座なのかということはあまり意識されず、むしろ、「振込元口座から振込先口座へ」というその行為において果たす役割に焦点が合わせられているというのです。こうしてロール間のインタラクションによってシステムとしてのふるまいが実現されることになるのですが、データは自分がどのようなロールを演じる可能性があるかを全て知っている必要はなく、ロールを演じる上で必要な「能力」を持ってさえいれば良いことになります。


これで、データとロールという形でシステムの構造とふるまいを表現する手段が手に入ったことになります。これによって異なる境界が表現できるようになった訳ですが、実行時にはこの2つはあるオブジェクトにおいて重ね合わせることができなければなりません。この、データとロールを紐づけるものが、「コンテキスト(文脈)」であるとされます。あるデータがどのロールを演じるかはコンテキストが決定する、ということですね。


こうしてDCIアーキテクチャの構成要素が出そろったことになります[Reenskaug 2008 p.5]。

  • DはDataを意味しています。データはシステムの構造あるいは状態を表現します。
  • CはContextを意味しています。コンテキストは必要なふるまいを実現するのに必要なオブジェクトのネットワークを構成します。
  • IはInteractionを意味しています。これはシステムのふるまいを表現するためのオブジェクト同士の相互作用です。この相互作用はロールメソッドとして実装されます。


次の課題は、このアーキテクチャの実現方法でしょう。データとロールはコンパイル時には分離されており、実行時に融合しなければなりません。これを実現するための手段としてCoplien氏が提示しているのは”Trait”という概念です。これはまさにScalaの言語仕様に与えられた名前そのものでもあるのですが、もちろんScalaでなければ実装できないということはなく、Groovyであれば、mixinを使って実現することができます。


それでは実際にGrailsを使ったアプリケーションにDCIアーキテクチャを組み込んでみましょう。

サンプル

今回使用するサンプルは給与計算システムです。仕様は以下の通りです。

  • 基本は時給制
  • 商品が売れれば、値段に応じてインセンティブが付く
  • インセンティブの割合は従業員ごとに定められたランクによって決まる
    • SENIOR → 3%
    • MEMBER → 2%
    • NOVICE → 1%
  • 給与計算は月単位で行う。

以下に示す通り、データ構造はかなりシンプルです。

ここに示した基本的なエンティティに対するCRUDは、Grailsが持つscaffoldの機能を使うことで苦労せずに作成できます。DCIアーキテクチャは、給与計算ロジックに登場します。時給とインセンティブを計算するには、以下のようなHQLを使って従業員ごとの労働時間合計および売り上げ合計を集計する必要があります。

SELECT 
    sum(salesReceipt.item.price), salesReceipt.employee.id 
FROM 
    SalesReceipt salesReceipt
WHERE 
    date >= :startOfMonth and :endOfMonth >= date
GROUP BY 
    salesReceipt.employee.id

通常であればこの結果として得られるリストをメソッド間で受け渡して処理をすることになると思いますが、今回はDCIアーキテクチャの思想に従い、このデータ構造に対して「○○合計取得(XxxTotalizer)」というロールを与えることにします。そうすることで、ふるまいは次のように表現できます。


各従業員ごとの給与計算ロジックを集約しているクラスを見ると、ふるまいが一目で分かる状態になっていることが見てとれると思います。

class PaymentCalculator {

    def calculate(workingHoursTotalizer, salesAmountTotalizer) {
        int totalWorkingHours = workingHoursTotalizer.workingHoursOf(id)
        int monthlyBase = hourlyRate * totalWorkingHours
        int totalSalesAmount = salesAmountTotalizer.salesAmountOf(id)
        int incentive = totalSalesAmount * incentivePercentage()
        monthlyBase + incentive
    }

    private def incentivePercentage() {
        switch(rank) {
            case Rank.SENIOR:
                return 0.03
            case Rank.MEMBER:
                return 0.02
            case Rank.NOVICE:
                return 0.01
        }
    }
}


使用したサンプルはこちらで公開しています。

最後に

mixinというやや特殊な言語仕様を必要とするため、DCIアーキテクチャは新しいギミックのように見えるかもしれませんが、実際にはより普遍的なモデリングパラダイムという文脈からとらえるべきです。すなわち、システムを「構造」と「ふるまい」の2つに分解して考える視点は、可変なものを安定したものと切り離すことによって全体の構造を安定させるというアーキテクチャの考え方に基づくものです。また、個別のオブジェクトのふるまいを見るのではなく、それが組み合わされた時のシステムとしてのふるまいに目を向けようという意図や、人間のメンタルモデルに関する深い洞察などがここには含まれているのです。


こうした思想を生み出した根底にある「メンタルモデルをどう捉えるべきか」という探求からは、学ぶべきものが多いと言えるのではないでしょうか。

参考文献一覧

補足

空のリストにmixinを行い、asTypeでmixinしたクラスにキャストすると、元のリストが持っているメソッドが使えなくなってしまうようです。サンプルではこの問題を回避するため、ロールメソッドの先頭にエラーハンドリング処理を入れています。

*1:このあたりについては、ドメイン駆動設計入門において詳しく説明しています

ドメイン駆動設計入門

"Beautiful Develpment"(10/27 DevLOVE)の講演資料と原稿

はじめに

本日(10/27)、DevLOVE様主催で、"Beautiful Develoment"と題されたイベントが開催されました。これは「ドメイン駆動設計("DDD:Domain-Driven Design")」を題材に、入門から実践までを語り尽くすというコンセプトのものです。このイベントにおける講演のトップバッターとして、ドメイン駆動設計の根底にある基本的な考え方についてお話しさせて頂きましたので、講演資料と原稿を公開いたします*1


スライドはこちら


アジェンダは以下の通りです。

  • 導入
  • オブジェクトとは?
  • モデルとは?
  • ドメイン駆動設計とは?

まずは、ドメイン駆動設計のベースとなっている、「オブジェクト指向」や「モデル」について整理した上で、実際にドメイン駆動設計とはどういうものかを見ていきます。「言葉」を軸にドメイン駆動設計の読み方について1つの方向性を示すことができたらと思っています。

導入

オブジェクト指向業界では、最重要著作の一冊に位置づけられながらも、500ページ以上という厚さ、そして、決して平易とは言えない文体によって多くの読者を苦しませてきた書籍、それが「ドメイン駆動設計」です。出版されたのは2004年とPofEAAなどとほぼ同時期ですが、Yahoo!グループDDDメーリングリストは現在でもなお活発に活動が続いており、この本の影響力の高さを物語っています。このメーリングリストにおける最近のホットな話題としては、CQRSなどが挙げられるでしょう。また、著者のEric Evans氏は、"Time and Money"ライブラリの開発などを経て、現在Cassandraの開発に携わっています現在も、domainlanguageにて、コンサルティングや教育などを行っています。

オブジェクトとは?

オブジェクト指向」についてご存知の方は多いと思いますが、改めて「オブジェクトとは何か?」と説明を求められると戸惑うこともあるのではないでしょうか。「デザインパターンを使った実装をするための言語」というのは誤解で、デザインパターンとは、累積された問題解決のパターンであり、つまりオブジェクト指向言語を使う中で生まれたものです。もう1つ「現実世界のモノを表現したもの」という説明もあります。入門としては分かりやすいかもしれませんが、実はこれも正確ではありません。それではいったい何が違うのか、古典的ではありますが「虹」を例にして考えたいと思います。


さて、虹はいくつの色からできているでしょうか?


僕が子供の頃には「7色」と習ったような気がします。上から順に「赤・橙・黄・緑・青・藍・紫」で7色ですね。でも本当ですか?色の実体は光の波長ですから、実際には境目のないグラデーションです。そのグラデーションに対して誰かが境界線を引き、大体この辺が「赤」と名前を付けただけです。大げさな表現をすれば、「僕らは言葉によって世界を切り分け、そこに名前を与え、意味に囲まれて生きている」ということですね。あるモノに意味を見出し、他のモノと切り分け、そこに名前を与えることで自分たちの世界を構築しているのが人間だ、ということです。オブジェクト指向において、オブジェクトに表現させようとしたのも、実はモノ自体ではなく、「概念」すなわち「名付けられ、意味を与えられたユニット」なのです。

モデルとは?

これも、よく聞くわりに改めて意味を問われると困るものと言えるでしょう。私がこの業界に入って「モデル」という単語を最初に聞いたのは、MVCの説明においてだったように記憶しています。「モデルは業務処理を書く場所」と覚えて、アプリケーションの実装に入った方がほとんどだと思うのですが、そこで実際に書いているコードは、if/forを駆使してList/Mapを操作するというスタイルが多いのではないでしょうか。


このように、リクエストに対する処理を手続き型に記述するスタイルが、いわゆる「トランザクションスクリプト」です。オブジェクト指向の愛好家にとっては許し難い罪悪に見えるこのスタイルも、実は悪い面ばかりではなく、どういう処理が行われるのか、とにかくメソッドの中を最初から順に読んでいけば分かる安心感や、実装の簡単さ、作業分担の容易さなどからも、ウォーターフォール型大規模開発との相性は悪くありません。しかし、もともとトランザクションスクリプトで書くことを想定していたならば、わざわざMVC(Model-View-Controller)という名前がつけられたでしょうか?SVC(Script-View-Controller)や、PVC(Proceure-View-Controller)の方が良かったのではないでしょうか?


こういう時は、原典に戻りましょう。1979年(30年前!)に書かれたMVCの原典では、モデルは「知識の表象」とされています。ユーザの頭の中にある知識/メンタルモデルを写し取るものだと考えられていたんですね。「メンタルモデル」とは、私たちの世界のとらえ方、言葉によって頭の中に構築された世界の像です。それをコンピュータの中に写し取るために登場するのが、オブジェクト指向というパラダイムです。メンタルモデルを構成する概念をクラスとして表現することで、メンタルモデルを写し取ろうとしたのです。


こうした、概念を表現するオブジェクト指向というパラダイムと、オブジェクト指向を用いてメンタルモデルをコンピュータの中に持ち込もうという発想がドメイン駆動設計の出発点となります。

ドメイン駆動設計とは?

ドメイン("domain")とは、ユーザが知識を持ち、 影響を与え、 活動する領域であると説明されます。"domain"という単語は日本語にしにくいのですが、もともとは「領土」「支配領域」という意味を持つもので、「対象領域」と訳されることもあります。要するに「業務領域」「事業対象」などと考えれば分かりやすいでしょうか。一方、ドメインモデルとは「ドメインについてのモデル」です。こう書いてしまうとそのままなのですが、重要なのは「そのドメインの専門家は、ドメインをとらえるための、適切に抽象化されたモデルを持っている」ということなのです。


それを踏まえて、ドメイン駆動設計の主張は以下の2点です。

  1. ソフトウェアの開発においては、まず、ドメインドメインロジックに焦点を合わせる
  2. 複雑なドメインの設計はモデルをベースにする

1.は「要素技術やアーキテクチャよりもドメインの方が重要だ」ということです。2.は「専門家が持つドメインモデルをベースにしてドメインを設計せよ」ということです。したがって、ドメイン駆動設計の第1歩は、そうしたドメインモデルを専門家と開発者との間で共有することとなります。


前述した通り、私たちのメンタルモデルは「言葉」あるいは「概念」によって構築されているものでした。これは専門家が持つドメインモデルに関しても同じことが言えるため、ドメインモデルを共有する上での武器もやはり言葉ということになります。その時に重要なのが、同じ言葉を使った時に、確実に同じ概念をイメージするということです。言葉は実体を持つものではなく、世界を切り分けるものでした。この境界線の引き方は人によって異なりますから、ある単語を聞いた時に自分が想起するイメージが、その単語を話している人のイメージと同じである保証はどこにもありません。したがって、ある概念は単独で理解することはできず、他の概念との関係において理解する必要があるということになります。


こうしたモデルを構成する言葉は、会話やドキュメントなど、プロジェクト内のあらゆる場所で使われるべきだと考えられています。このプロジェクト内にあまねく行き渡った言葉が、ユビキタス言語("Ubiquitous Language")というパターンとして説明されます。さて、このあらゆる場所という表現には、当然コードも含まれています。ユビキタス言語によって構成されたドメインモデルを、文字通り「反映」させてソフトウェアを作ること、それがモデル駆動開発("Model Driven Development")です。このユビキタス言語とモデル駆動開発ドメイン駆動設計においてもっとも重要な2つのパターンと言えるでしょう。


要約すれば、ドメインの専門家が持つドメインについてのモデルを、ユビキタス言語をベースとしつつ開発者と共有し、さらにその共有されたドメインモデルを反映させてソフトウェアを作るというダイナミズムがドメイン駆動設計の根幹だということになります。


こうした思想をどうやって実現していけば良いのか、ということについて、「アーキテクチャ」と「プロセス」という2つの観点から考えていきましょう。

アーキテクチャ

アーキテクチャとは何か、ということについては諸説ありますが、ここでは「構造を規定しつつ、可変性を支える戦略」と考えることにします。ソフトウェアにおいて、無制限な柔軟性はあり得ません。ほとんど変化することのない安定した構造をベースにしつつ、変化する可能性がある場所に対して、選択的に柔軟性を与えることが必要になるのですが、こうした固定化と柔軟性を決定する戦略こそがアーキテクチャであるということです。


こうしたアーキテクチャについて、ドメイン駆動設計では、レイヤ型アーキテクチャ("Layered Architecture")が提唱されます。これは、以下の4階層から構成されています。

これは単に階層を分けましょうということではなく、ここで重要なのは、ドメインモデルのための空間を「ドメインレイヤ」として他のレイヤから分離するということです。これによってドメインモデルが独立し、柔軟に設計することができるようになります。


さらに、こうして独立したドメインモデルが、どのような要素によって構成されるかということについても、ドメイン駆動設計の中では説明されています。主要な要素としては以下のものが挙げられます。

  • エンティティ("Entity")/バリューオブジェクト("Value Object")
    • データモデルを表現するもの。識別子を持ち状態変化がおこるエンティティと、そうではないバリューオブジェクトが区別される。
  • サービス("Service")
    • データとしてよりも、アクションや処理として表現される方が適切なもの。
プロセス

ドメインモデルの共有と構築を軸としたドメイン駆動設計にとって、その開発プロセスアップフロントなものではなく、イテレーティブなものとなります。まず開発者は、ドメインの専門家が持っているモデルを共有するため、頻繁にコミュニケーションをとる必要がありますし、専門家にしてみても、頭の中に描いているモデル自体が実は完成されたものではなく、フィードバックを受けて変化する可能性があるものなのです。こうしたモデルの変化について、Evansは深さ("deep")という言葉で表現しています。モデルが深みを増していくんですね。


こうしたモデルの深化において主要な役割を果たすのも、やはり言葉です。うまく表現できなかったもの、あいまいだったものが、それを示すある言葉を与えられることで、一気に明確になるということは少なからず経験があるのではないでしょうか。これについて、Evansは「より深い洞察」と表現しています。こうしたモデルの変化は直線的に起こるだけではなく、ある日突然大きく変化することもあります。こうしたブレイクスルーは日々モデルを洗練させていく行為の先に突然訪れるものだとされています。


ドメインモデルとそれを反映させたソフトウェアは、こうした変化を受け入れることができるものでなければなりません。これは、1つには前述のレイヤ型アーキテクチャによって実現されるドメインの独立性によって支えられますが、さらに、ドメインモデル自体もそうした変化に対応できるよう柔軟に設計されている必要があります。こうしたドメインモデル自体の設計手法については、意図が明確なインタフェース("Intention-Revealing Interface")や副作用のない関数("Side-Effect-Free Function")といった、オブジェクト指向のプラクティスとも言えるものが説明されています。

戦略的設計

ここまで、あるドメインモデルをどうやってソフトウェアに組み込むかということについて考えてきましたが、ドメイン駆動設計にはさらに先があります。それが「システムが複雑化/巨大化した際にもモデルとの整合性を保つためにはどうすればよいのか」を考える、戦略的設計("Strategic Design")です。


戦略的設計は、文脈("Context")、抽出("Distillation")、大局的構造("Large-Scale Structure")という3つの観点から説明されます。これらの観点について概要を示します。


文脈
ある言葉は他の言葉との関係において一定の意味を持ちますが、この意味の同一性は無制限に保証されるわけではありません。例えば、「受注」という言葉が示す内容は、業務によって少しずつ異なっているでしょう。これは言葉に意味を与えている文脈が異なることに起因しています。そして、ある文脈には有効範囲が存在します。Evansは境界づけられた文脈("Bounded Context")という概念を用いて、文脈が持つそうした有効範囲を明確にするよう促します。さらに、企業レベルでシステムが統合される場合には、異なる文脈が共存することになりますので、それら文脈間の関係を文脈の地図("Context Map")として描き出すことが重要であるとされています。


抽出
"Distillation"は「抽出」の他、「蒸留」や「精製」とも訳されることがある単語で、つまり、「純粋なもの/本質」("essence")を取り出すことを意味しています。ドメインモデルを作り上げる行為もある意味で専門家の目から見た本質を抽出する行為でしたが、同じことはより広大なコンテキストマップに対しても実施することができます。こうして最も価値のあるコアドメイン("Core Domain")を識別し、それを共有した上で、重要度に適した投資を行うことが必要になるのです。


大局的構造
システムが複雑化・巨大化するに伴い、開発をスムーズに行うためにモジュール("Module")に分解することによる分割統治が行われるようになります。しかし、そうした分割統治はシステムの全体像を見えにくくしてしまいます。そのような全体像を見渡す大局観を失ってはならないということが、大局的構造として語られています。具体的なプラクティスとしては、システムをとらえるメタファー("System Metaphor")をメンバの間で共有し、それをユビキタス言語に吸い上げていくといったことが説明されています。

まとめ

ドメインの専門家が持つドメインモデルを共有すること。それを反映させたソフトウェアを作ること。そのために繰り返される、終わらない営み。さらにそのソフトウェアがスケールアウトしてもモデルとの整合性を保つこと。ドメイン駆動設計で語られるこうした思想について概観してきました。実際の本の中では具体的なプラクティスについても詳細に語られていますが、こうしたプラクティスを実践するのは決して容易ではないとEvans自身も言っています。しかし、本の最後でEvansが送ってくれるのは、言葉を大切にしつつ、常にモデルを意識しながら、つまづくことがあっても、立ち上がって進んでいけ、という力強いメッセージです。

最後に

ドメイン駆動設計を読んでいると、自分が今置かれている環境とのギャップにうんざりすることもあると思います。例えば、ウォーターフォールであったり、トランザクションスクリプトであったり、ということですね。しかし、あきらめる理由を見つけて満足するのではなく、Evansから学んだことを活かす方法を探すことはできるでしょう。


「要件定義の時にどこまで顧客のメンタルモデルに迫れているか」「クラス名、せめてメソッド名や変数名は業務を適切に反映したものになっているか」「トランザクションスクリプトであっても、許された範囲でクリーンなコードが書けているか」- プログラマとして自分の書いたコードに誇りを持てるよう、できることからやっていきましょう。


大きなブレイクスルーを生み出すのは、小さなプラクティスを積み重ねる日々に他ならないのですから。



関連記事



Domain-Driven Design: Tackling Complexity in the Heart of Software

Domain-Driven Design: Tackling Complexity in the Heart of Software

DDDの日本語版が出版されます(2011/03/24追記)
エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

*1:話の内容には一部相違があるかもしれませんが、ご了承下さい

組織パターン トップ10 - James Coplien

この記事はJames Coplien氏の記事「Organizational Patterns: Building on the Agile Pattern Foundations」を、氏の許可を得て翻訳したものです(元の記事が長いため抄訳としています)。(原文最終更新日:2006年7月9日)




  1. 目的の統一性("Unity of Purpose")
  2. 顧客の参画 ("Engage Customers")
  3. ドメイン専門家という役割 ("Domain Expertise in Roles")
  4. アーキテクトがプロダクトをコントロールする ("Architect controls Product")
  5. 作業の均等な分配("Distribute Work Evenly")
  6. 関数の所有者とコンポーネントの所有者 ("Function Owner and Component Owner")
  7. 雇われアナリスト ("Mercenary Analyst")
  8. 実装するアーキテクト ("Architect also implements")
  9. ファイアウォール ("Firewalls")
  10. 開発者がプロセスをコントロールする ("Developer controls Process")

目的の統一性("Unity of Purpose")


...チームがまさに共同作業を始めようとしているとします。チームメンバは異なるバックグラウンドを持ち、全く別の経験をしてきているかもしれません。


* * *


多くのプロジェクトは始まりでつまづきます。メンバが一緒に作業するために苦労するからです。


最終的なプロダクトがどうあるべきかということについて、メンバが異なる考え方をしているということはよくあります。実際、最終的なプロダクトがきわめてあいまいな概念であることもよくあるのです。しかし、そのプロダクトを実現する望みがわずかでもあるならば、メンバはプロダクトに関する一貫したイメージを持たなければなりません。


人はそれぞれ違い、異なるとらえ方と意見を持っています。異なる背景と経験を持っているのです。そういう人たちが一緒に働くことを学ばなければなりません。


いいスタートを切ることは重要です。第一印象はいいものであっても悪いものであっても、続いてしまうものだからです。


したがって、


プロジェクトのリーダは共通のビジョンと目的を、チームのメンバ全員にインストールしなければなりません。この「リーダ」はマネージャや「後援者というロール("Patron Role")」、顧客の支援者などであるかもしれませんが、チームから尊敬され、チームの思考に対して影響を与えられる人物であるべきです。これは意図して行われる行為であり、自然に起きることを期待することはできません。リーダは、次のことについて全員を合意させる必要があります。すなわち、「このプロジェクトは何をするべきなのか」ということについてです。顧客が誰で、このプロジェクトがどう役に立つのか。スケジュールはどうなっているのか。また、スケジュールについては全員が個人的にコミットするものでなければなりません。さらに、誰と競合するのか。


この活動において重要なのは、チームの強みを認識し、それをチームの求心力として使うことです。これは、課題と競争相手とを認識し、課題を克服して競争相手を上回るために団結することにもつながります。


時間が経つにつれて、この目的の統一性("Unity Of Purpose")は、チーム内の対話や、顧客やその他のステークホルダとの対話においても登場し続けます。チームリーダはこれを推進しますが、チームのダイナミクスがこれを引き受け、進めていくことになります。


顧客の参画("Engage Customers")


店員が洋服を仕立てるために、顧客の採寸をしている。テキサス州サンアントニオ


著者の友人の一人が以前、巨大なシステムのためのユーザインタフェースを設計、実装したことがあります。使いやすくするためにどうすればいいのかということについて、友人は顧客からのインプットをもらいました。残念なことに、要件を記述していた人はそれとは別の考えを持っており、顧客が望んだ機能を削除させました。しかし、後でこの削った機能を顧客が要求し、この要件を記述していた人は折れざるを得ませんでした。友人と要件を記述していた人との仲は悪くなったのではないかと思います。


組織が整ってくると、品質保証("QA")の機能も徐々に整備され、特権を与えられます。品質保証の機能はその仕事を進めるにあたって、インプットを必要とします。企業内の多くの人が、品質について気にかけます。


* * *


開発組織内で主要な役割を担う人と顧客との間のコミュニケーションを促進することによって、開発組織が顧客満足度を高め、維持することは重要です。これはどこか一つの「顧客満足度」組織に課すべきものではなく、組織構造全体で担うべきものです。ほとんどの組織は、開発者と顧客との直接的な交渉を嫌いますが、これは開発者が「何をしでかすか分からない危険人物」で、仕事の範囲をこえたものを作ると約束してしまうことを恐れてのことです。


しかし、全ての要件をアップフロントに知ることはできないため、開発者はより多くの情報を得るために顧客の所へ戻って行く必要があります。また顧客も自分たちが持つ洞察を携えて開発者の所に戻って行かなければなりません。これは特に開発者が「プロトタイプを作る("Build Prototypes")」時には言えることです。要件の変更は設計のレビューが完了し、実装が始まった後にも起こるのです。


多くの組織では、要件と要求を引き出すにあたって、マーケティング組織に依存しています。しかし、マーケティングは設計情報を提供しません。マーケティングができる(あるいはすべき)なのは、せいぜい、何が売れ、どうしてそれが買われるのかを理解することです。一方で、設計する人は、そのプロダクトが、どうやってユーザに取っての価値を生むような仕方で使われるのかを理解しなければなりません。優れた価値は、時に優れたマーケット上の可能性につながります。しかしマーケティングは設計者があまり気にしない要素に目を向けるものなのです(ブランド名の認知度、製品名、アピールなど)。


顧客の要件が失われてしまうことは重要な問題です。ソフトウェアシステムにおける問題のほとんどが、要件の問題に端を発するからです。しかし、この問題を引きずり出すのは大変な労力です。市場に出すことができるものを直接生み出す仕事ではないため、無駄な仕事を作るオーバーヘッドに見えてしまいます。


伝統的に、顧客は開発の主流に関わってきませんでした。そのために、顧客が持つ洞察を発見し、取り込むことが難しかったのです。しかし、顧客との結びつきはプロジェクトの成功と関係しています。


マネージャとコーダとの信頼関係はしばしばぎくしゃくするものです。したがって、それを開発者と顧客との関係に持ち込みたくはないでしょう。


したがって、


顧客というロールを開発者やアーキテクトと密接に関係づけなさい。QAやマーケティングとだけではいけません。一言で言えば、開発者やアーキテクトは顧客と自由に、そして頻繁に話すことができなければならないのです。可能であれば、顧客にあなたたちの環境に来てもらうのではなく、向こうの環境で参画してもらいなさい。


このために必要なものが2つあります。それがチャンスと文化です。開発者は顧客とコミュニケーションする機会(と方法)を持たなければなりません。開発者は顧客の信頼を得て、自由にコミュニケーションするために、個人的に会わなければならないのです。


しかし、もし組織の文化が顧客と開発者との間に見えない壁を作っていたら、こうした訪問は表層的なものになるでしょう。特に、システムの要件が承認されるために、時間のかかる正式なプロセスを踏まなければならないのだとしたら、開発者は顧客の要求に応えることができず、身動きがとれなくなるでしょう。したがって、組織は開発者が顧客の要求にある程度自由に応えられるような文化を育てる必要があります。だからといって、要件のコントロールをすべて開発者に明け渡さなければならないということではありません。秩序は必要です。


Bayer氏とHoltzblatt氏は「顧客と一緒に仕事をする一般的な方法の多くが、顧客をその仕事から遠ざけてしまう」と語っています。これを解消する方法の一つに「設計する人とエンジニアを直接顧客が仕事をするコンテキストに放り込む」というものがあります。これは、既存の仕事を改善するのではなく、全く新しい市場の方向性を企業のために生み出そうとして顧客に参画してもらっている場合には、特に重要になります。開発者を顧客が仕事をする環境に放り込むことは、優れた設計、優れたヒューマンインタフェースに関する開発者の直感を鍛えます。そしてこの直感によって、はっきりとした詳細な要求が得られない時にそれを埋めることができるようになります。


言語はこうした文化における主要な要素で、適切に扱われれば顧客の参画をスムーズにすることができますし、間違って扱えばうまく行かなくなります。顧客にUMLやその他の技術的な記法を学ばせようとするのはやめなさい。顧客の言語を学び、顧客の文化が持っている用語でコミュニケーションすることに最善を尽くしなさい。


品質保証はこの関係を監視し、進む方向が契約に関わる業務上の制限を超えないように保つことができます。こうしたコミュニケーションは妨げられることなく行われがちですが、これについては「門番("GateKeeper")」パターンを参照して下さい。


このパターンが人間関係と文化に関わるものであることには注意が必要です。コミュニケーションを効果的にするのは、顧客に対する尊敬と顧客とのコミュニケーションを持った文化です。例えば、「参加型の聴衆("Participating Audience")」において説明されているように、ユースケースを書いている時のコミュニケーションが考えられます。


ドメイン専門家という役割("Domain Expertise in Roles")


テキサス州コーパスクリスティ、海軍航空基地。一流のメカニックであるMary Josephine Farley氏が飛行機のエンジンを巧みに組み立てている。まだ20歳だが、彼女はプライベートなパイロットの免許を持っており、都市の横断飛行を何度か行った経験がある。


...開発者という役割を特徴づけることを含む、アトミックなプロセス内での主要な役割(「型は機能に従う("Form Follows Function")」)について、あなた方は知っているはずです。


* * *


成長するダイナミックな組織において、色々な役割にスタッフを割り当てることは、最も難しい課題の一つです。あらゆる役割にはスタッフが割り当てられる必要がありますし、さらに言えば、あらゆる役割には適切な個人が割り当てられなければいけないのです。演劇と同じように、数人の役者("actor")にはある1つの役が与えられますが、それ以外の役者はいくつかの役を演じるかもしれません。


ある人がその仕事に対して適任かどうかを判断する上で、ドメインに特化しない基準を使いたいと思うかもしれません。たとえば、大学の成績や、経験年数などです。こうしたアプローチを取ることで、プロジェクトはスタッフを柔軟に割り当てることができるようになります。つまり、個人のスキルセットと経験に過度に依存することを避けられるのです。こうした基準がうまく働くだろうと期待することで、プロジェクトマネージャは、プロジェクトが特定の個人に過度に依存しないようにするための基盤を手に入れられます。特定の個人は、会社を辞めてしまうかもしれませんし、給料アップを求めて組織を人質にとるかもしれません。また、独自のポリシーを一方的に実装してしまうかもしれません。しかし、成功したプロジェクトは、成功したプロジェクトで仕事をしたことがある人から構成される傾向にあるのです。


専門知識が複数の役割に散らばってしまうと、コミュニケーションパターンが複雑になります。これによって、ドメインに特化した要求や設計上の疑問について誰が答えるべきかということが、開発者やその他のプロジェクトメンバから分かりにくくなってしまうのです。

したがって、


実績のあるドメインエキスパートを雇い、役割に組み込まれた専門知識を軸にスタッフを割り当てなさい。そうすることで、ドメインに対する共通の関心や焦点の領域を取り巻いて、チームやグループが形作られるようになるのです。複数の役割を果たす役者は何人いてもかまいません。多くの場合、複数の役者がある特定の役割を演じることもあるでしょう。

ドメインのトレーニングはプロセスのトレーニングよりも重要です。


ローカルなグルを作ることは良いことです。このことはアプリケーションの専門家から、手法や言語の専門家に至るまで、あらゆる領域について当てはまります。


アーキテクトがプロダクトをコントロールする("Architect controls Product")


...開発者の組織がある以上、技術的に向かうべき方向を決める戦略が必要です。


* * *


プロダクトが多くの個人によって設計されていたとしても、プロダクトが正確で一貫したものになるように、プロジェクトは努力しなければなりません。これを中央集権によって実現しようとする人もいるかもしれませんが、全体主義的なコントロールは多くの開発チームから見ると厳格すぎる手法です。1人がすべてを行うことはできませんし、先のことが完全に読める人も存在しません。しかし、正しい情報は適切な役割を持った人のところを流れなければなりません。コンピテンシーや専門性といった個人的な領域が相変わらず必要だとしてもです。


さらに、一定のレベルでアーキテクチャ的なビジョンも必要です。ドメインに関する専門知識がいくつかの開発者チームで分散されたとしても(「ドメイン専門家という役割」)、システムの見方、特に対話と構築に関する共通の文化を生み出すような設計の原則は、概念的な統一性("conceptual integrity")がとれていることでうまく行きます。こうした概念的な統一性を、私たちは特定の人や小さいグループと関係づけます。


したがって、


アーキテクトという役割を作りなさい。その役割はプロジェクトのアーキテクチャスタイルを定義するアーキテクチャ上の原則と、そうしたスタイルを正当化するような、ドメインに対する広い専門知識が埋め込まれたものとしなさい。アーキテクトという役割は、開発者という役割に対してアドバイスと影響を与えるものでなければなりません。また開発者と密接にコミュニケーションを取らなければなりません。アーキテクトはインタフェースに関して命令はしません(調停が必要な時は別ですが)。そのかわり、アーキテクトは各開発者やサブチーム、また必要であれば全開発スタッフと、アーキテクチャスタイルに関するコンセンサスを形成します。アーキテクトは、開発チームメンバ間の主要な橋渡し役です。


また、アーキテクトはドメインに関する専門知識が、最新かつ詳細で整合性が取れたものになっているよう、顧客とも密接に関わらなければなりません。


作業の均等な分配("Distribute Work Evenly")


20頭のラバで構成されたチームが作業とコミュニケーションを均等に分配している。


...組織は、人的資源を有効活用するため、可能な限り楽しい環境をつくるよう努力しています。


* * *


組織内の負荷の多くを、数人に負わせるのは容易です。マネージャがこれを好むのは、管理しなければならないインタフェースの数を最小化できるからです。さらに、従業員によっては、こうしたヒロイックな責任という勘違いから、できる限りのことをやろうと苦労します。実際、「プロデューサという役割("Producer Roles")」がそれを支援する他の役割よりも強いコミュニケーションネットワークを構成しがちだということも分かっています。


しかし、この不平等が続けば、負荷の強い役割を負う人にとって、企業全体として健全に機能するのに必要なコミュニケーションネットワークを維持するのが難しくなります。組織の活動の中心にいると感じない従業員の間で、ねたみのような感情が生まれるでしょう。そして、中心となる人々も簡単に疲れ切ってしまうかもしれません。


役割当たりの平均的なコミュニケーションパスの数に対する、最も強い役割が持つコミュニケーションパスの数の比率をコミュニケーション強度比率として定義しなさい。経験的には、この比率が大きくなり過ぎる場合、組織は何らかの不健康さという問題を抱えているようです。


したがって


コミュニケーション強度比率を2以下に保つようにしなさい。(2を大きく下回るのは容易ではないことも分かっています。)そのための最も簡単な方法は、「役割の数を少なくすること("FewRoles")」です。また、「プロデューサという役割("Producer Roles")」を識別し、疲弊した役割を無くすことも役立ちます。最も中心的な役割へのコミュニケーションを識別し、本当に必要なものは何かを確認することも同じように役に立ちます。


コミュニケーションオーバーヘッドは些細なものではなく、こうしたことが起こっていることを識別するのは容易です。シンプルで直接的な方法により、冗長で誤ったコミュニケーションを無くすことができます。この場合、深い構造や組織の原則といった深いレベルに行く必要はありません。


これ以外の状況はより巧妙で多発的であり、このパターンランゲージにおける別のパターンで検討します。


関数の所有者とコンポーネントの所有者("Function Owner and Component Owner")

プロジェクトにおける関数は、コンポーネントをまたいで使用される傾向にあります。プロジェクトのアーキテクチャ(「コンウェイの法則("ConwaysLaw")」)にしたがって組織化することの重要性は認識しているでしょうが、事はそう単純ではありません。


* * *


コンポーネントによってチームを組織すれば、関数が被害を受けますし、逆もまた然りです。


コンポーネントの所有者を決めなければ、関数かユースケースによってチームが編成されるでしょう。あるいは、関数やユースケースの所有者を決めなければ、クラスかコンポーネントによってチームが編成されるでしょう。どちらの場合でも、同じ疑問を持つことになります。「2人が同時に同じ関数をプログラミングしたいと思った場合には何が起こるのだろうか?」と。


関数についての所有権と一貫性が求められますし、コンポーネントについても同じ事が言えます。そして、コンポーネントはチームをまたいで共有されなければなりません。


関数の所有者しか割り当てなければ、コンポーネントが複数人で共有され、一意性と一貫性が失われてしまいます。しかし、コンポーネントの所有者しかいなければ、関数は親を失ってしまいます。関数が完成したことを誰が保証するのでしょうか?

したがって、


全ての関数が確実に所有者を持ち、全てのコンポーネントも確実に所有者を持つようにしなさい。


全てのコンポーネントに責任を持った所有者がいること、そして、全ての関数に責任を持った所有者がいることを保証して下さい。コンポーネントの所有者はコンポーネントの一貫性と品質に関する質問に答えますし、関数の所有者は関数が完成することを保証します。コンポーネントの所有者が皆、末端の機能に必要な何かを組み込むことを断った場合には、関数の所有者は必要なコードを関数に特化した場所に置くことになります。


雇われアナリスト("Mercenary Analyst")


各国をまわって民謡を収集しているJohn Jacob Niles氏は、アパラチア山脈へ何度も旅したうちのある時、ある女性が特別に美しい歌を歌っているのを聞きました。Niles氏は自分で覚えるまで彼女にその歌を繰り返してもらいました。それが今は有名なクリスマスソングの「I Wonder as I Wander」です。Niles氏は後にこう語りました。「その後、もう一度彼女に会うことはありませんでした。」


...組織のために役割を整理しているとしましょう。その組織が置かれているコンテキストでは、外部のレビューア、顧客、内部の開発者がシステムのアーキテクチャを理解するためにプロジェクトの文書を使おうと期待しています。(ユーザマニュアルは別とします。)設計の記法やそれに関連するプロジェクトのドキュメントを支えるのは、プロダクトの成果物に直接的に貢献している人にとってはあまりに退屈な仕事です。


* * *


技術ドキュメントの作成は、どのプロジェクトもやらなければならない汚れ仕事です。優れたドキュメントを作り、さらにそれをメンテナンスして、そのプロジェクトが後で使えるようにすることは、重要なことです。しかし、こうしたドキュメントを誰が書くのでしょうか。


開発者が自分たちでドキュメントを書こうとすれば、「本当の」仕事の妨げになります。ソフトウェアの納期を守ることは組織にとってお金を意味します。そこで、技術ドキュメントはしかるべき時まで作るのを先延ばしできるものと考えがちです。しかし、「しかるべき時」が来ることは滅多になく、組織がシステムについての優れた技術ドキュメントを内部で持っていなければ、それは重大なハンデになります。


ドキュメントは、書かれるだけで読まれないこともよくあります。


また、エンジニアが優れたコミュニケーションスキルを持っていないこともよくあります。


多くのプロジェクトは設計をするのに、Roseのようなきれいな絵が描けるツールを使用します。優れた絵は優れた設計にとって必要ではありませんが、アーキテクトは巧く描かなければと悩んでしまう可能性があります。


したがって、


必要なドメインについて詳しいテクニカルライターを雇いなさい。しかし、設計自体には関与させないようにしなさい。


この人は適切な記法を用いて設計をとらえ、レビューや利用のために設計を整形して公開してくれるでしょう。


実装するアーキテクト("Architect also implements")


現地で作業する、住宅開発の建築家、1942年


...ある組織が、1つまたは複数のマーケットに仕えるため(「組織はマーケットに従う("Organization Follows Market")」)に作られたとしましょう。時間が経つにつれて、プロジェクトはそのマーケットをカバーし、スムーズな進化を保証するのに必要なアーキテクチャ上の広がりを求めますが、そうしたものは、実践的なエンジニアリングや実装の関心に目をつぶることができません。さらに言えば、概念的な一貫性を保とうとすれば、プロジェクトは実装を理解した上で、アーキテクチャ上のビジョンを実行する必要があります。


* * *


ソフトウェアプロジェクトは、深みや実践的な注意を犠牲にすることなくリーダーシップのスコープを広げなければなりません。開発者は個別の設計や実装上の意思決定を行うことは得意かもしれませんが、プロジェクトには全体を導くような技術的方向性に関する戦略が必要です。これは通常アーキテクトによってもたらされます。しかし、あまりに多くのソフトウェアアーキテクトは、自身の思考や方向性を抽象的なものに限定してしまいます。しかし、抽象的なものというのは、無知の訓練された形式にすぎません。あまりに多くのプロジェクトはパフォーマンスやAPIの巧拙、コンポーネント間の相互作用といった「詳細」で失敗するのですし、良くてもこうした問題を後になって見つけるのです。

もし、計画で全て分かっていれば、こうした問題を全体主義的なコントロールによって解決できるでしょう。しかし、もしそれが可能であったとしても、全体主義的コントロールは、ほとんどの開発チームから過酷すぎる手法と見られています。


正しい情報が適切な役割を持った人の間を流れなければなりません。特に、開発者は戦略的なビジョンを理解し、実装に関する責任を持たなければならないのです。アーキテクトはアプリケーションの必要性を理解し、さらに長い目で見た時に、システムの構造に対してそれが何をもたらすかを理解しなければなりません。同じことはある程度開発者にも言えます。しかし、戦略的な方向性という中心的な軸がなければなりません。それによってプロジェクトが停滞するのを防いだり、必要な詳細に手が入れられることを保証したり、あらゆるピースを全体へと統合するような「調和」が現れてくるのを追跡できなければならないのです。この「調和」には、コンポーネント間の相互作用やプロトコルAPI、性能、信頼性への関心といった低水準の詳細を理解することが必要であることもあります。


したがって、


アーキテクトは開発者にアドバイスしたり、コミュニケーションしたりするだけでなく、実装に参加しなければなりません。

アーキテクトは組織的に開発者と結びつき、自分自身でコードを書かなければなりません。開発者に混じって「ペアプログラミング("Developing in Pairs")」をするのもよいでしょう。


ファイアウォール("Firewalls")


私の許可なしには、誰もここを通しませんよ!


「マネージャは、カーリングにおけるスイーパのようなものでなければなりません。スイーパは石の前を走り、石が妨げられず、スムーズに進めるように進路からゴミを取り除くのです。あなたのマネージャはこういうことをやっていますか?」


残念ながら、これと同じ領域で人間を酷使すると、困った人と普通の人が干渉し合って普通の人が傷つき、マネージメントは困った人に対してアクションを取らなければなりません。-- ボールダーマウンテンパーク入り口でのサイン、コロラド州ボールダー


...開発者の組織が、社内や社会的コンテキストの内部で形成されたとしましょう。そこで開発者は同僚や出資者、顧客、その他「外部の人」によってあれこれ見られます。プロジェクトの実装者はインプットを与えたり批判したりしなければならないと感じる外部の人によって、よく妨害されます。


* * *


プロジェクトにおける低水準の場所に関係することによって「手伝う」必要があると感じているステークホルダをなだめることが重要です。それによってプロジェクトの完成に向けて動いている開発者やその他の人の邪魔になることを防げます。

孤立していてはうまく行きません。したがって情報の流れは重要です。しかし、コミュニケーションオーバーヘッドは外部の協力者が増えるに従って加速的に上昇します。

多くの中断はノイズになります。


成熟と進捗は、効果的にコントロールされていることよりも、コントロールしていることと強く関係します。


したがって、


外部の役割から個人的に干渉されないよう、開発している個人を守る「マネージャという役割("ManagerRole")」を作りなさい。このロールが持つ責任は「害虫を寄せ付けないこと」です。


開発者がプロセスをコントロールする("Developer controls Process")


熟練した職人がワンタッチ式燃料タンクを作るための効果的で効率的なプロセスを考案している。第二次世界大戦


...まだ成熟していないドメインに、ある新しいマーケットのためのソフトウェアを構築しようと、組織がつくられたとします。進捗は「非形式的な労働計画("InformalLaborPlan")」によって、指標化されます。必要な役割が定義され、最初にスタッフが割り当てられます。


* * *


開発文化は、他の文化と同様、プロジェクトの方向性とコミュニケーションに関する焦点を認識することで恩恵を受けます。うまく行っている組織は中央集権化されたコントロールを最小限にして、有機的なやり方で機能しています。しかし、役割に埋め込まれた重要な焦点は存在します。これは考え方、要件、制約を相互に結びつけ、テスト、パッケージング、マーケティングしてユーザの元に届く成果物を作り出すものです。


全体主義的コントロールは、ほとんどの開発チームから厳格すぎる手法だと考えられます。正しい情報が適切な役割の間を流れなければなりません。分析、設計、実装を通じて情報の流れをサポートする必要があるのです。


開発者はエンドユーザから見える成果物に直接貢献しますので、プロダクトに責任を持つのに最適な地位にいます。あらゆる役割の中で、開発者はプロダクト開発における最大の利害を、他のどんな役割よりも多くのフェーズにおいて持っているのです。そして、コントロールなしに責任はありません。同じように「マネージャという役割("Manager Role")」にも、ある程度の責任がありますが、それはユーザから見える成果物を届けるのを間接的に支援するという役割の程度に応じたものです。これらはプロセスの課題となります。


したがって、


開発者をプロセスに関する情報の焦点としなさい。「組織がマーケットに従う("Organization Follows Market")」の精神に基いて与えられた機能について、開発者をプロセスのハブに置きなさい。機能というものはシステムの機能性(ソフトウェアにおいて広く実装されたもの)を構成する単位であり、個別にマーケティングされ、顧客が買おうと思うものです。開発者が担うべき責任には、要件を理解し、ソリューションの構造とアルゴリズムについて同僚とレビューし、実装を構築し、ユニットテストを行うというものです。


このエンドツーエンドのソフトウェア開発プロセスにおいて、開発者は全活動の中心となっているのです。


「マネージャという役割("Manager Role")」のような、別のハブも存在しますが、開発者ほどには中心的な役割を果たさないということを付記しておきます。




この組織パターンのJames O. Coplien氏は、DCIアーキテクチャでも有名な方です。そのCoplien氏によるScrumのセミナーが今年12月に予定されています。

このセミナーについては、以下のブログに詳しい情報が紹介されています。

Lean Architecture: for Agile Software Development

Lean Architecture: for Agile Software Development

ドメイン特化言語とモデル駆動エンジニアリング - Johan den Haan

この記事はJohan den Haan氏の記事「DSL and MDE, necessary assets for Model-Driven approaches - by Johan Den Haan」を、氏の許可を得て翻訳したものです。(原文公開日:2008年8月11日)




私はこれまで、モデル駆動エンジニアリング(MDE)について、多くの記事を書いてきました。MDEはモデル駆動アーキテクチャ(MDA)よりも広い概念で、モデリングのさまざまな切り口とソフトウェアエンジニアリングプロセスの考え方を付け加えるものです。MDAが注力するのは技術的な可変性です。これは、プラットフォームから独立したモデルとそうでないモデルとを区別し、こうしたモデル間での相互変換を定義することで達成されます。一方、MDEが注力するのは、アプリケーションドメインの可変性です。これは、主題領域("subject area")に関するモデリングの切り口と、アーキテクチャアスペクトをつけ加えることで実現されます。


モデル駆動ソフトウエア開発の文脈において、ドメイン特化言語DSL:Domain-Specific Language)という用語がしばしば言及されます。これは時としてMDAに対する代理品である場合もあります。私は以前、メタモデルを使ったDSLの実装に焦点を合わせた記事を書いており、そこでMDEとDSLの組み合わせという主題には多少触れました。この記事では、MDEとDSLが相補的であり、モデル駆動アプローチを成功させるには両方が必要であることを示したいと思います。


対象読者:ドメインエキスパート、プログラマ

DSLと結びつけるためのフレームワークとしてのMDE

モデル駆動エンジニアリング(MDE)は、モデル駆動アーキテクチャMDA)において定義される、抽象/具象という切り口に加え、それ以外に複数の切り口を定義します。


Kent [1]はMDEにおいて追加で必要となる切り口のカテゴリを2つ定義しました。最初のカテゴリは関心事についてのさまざまな切り口を含むものです。これは異なる主題領域や、異なるシステムアスペクトのようなものです。2つめのカテゴリはシステムの技術的な側面にはあまり関連しません。かわりに、組織的な問題に関わります。例えば、作成者やバージョン(バージョンやコンフィグレーションコントロールに見られるようなもの)、位置(システム開発が複数の場所に分散している場合には)、ステークホルダ(ビジネスエキスパートやプログラマ)などが挙げられます。


ソフトウエア開発プロジェクトにおいては、そのプロジェクトにとっての重要な切り口が何かを決定する必要があります。ほとんどのプロジェクトにおいて、作成者やバージョン管理は重要になるでしょう。しかし他の切り口は興味のポイントを特定する必要があります。どの主題領域が影響を与え、システムのどのアスペクトが重要なのか、といったようにです。重要な決定はもう一つあります。それはプロセスにおいて用いられる抽象化のレベルです。ここにはステークホルダも関与します(だからこそ、理解可能なモデルを作らなければならないのですが)。ソフトウェア開発プロセスにおいてモデルを構築する際に、各モデルは各切り口が交わる場所におかれる可能性があります。


議論を具体的にするため、切り口の例と考えられる値について、表1に示します。


切り口 考えられる値
抽象/具象

CIM, PIM, PSM

主題領域

受注、カスタマポータル、バックエンドの管理、など

アスペクト

データ、プレゼンテーション、セキュリティ、業務ルール、ワークフロー、など

ステークホルダ

対象読者:ドメインエキスパート、プログラマ

表1 - MDEプロジェクトにおける切り口の例



表1に示された切り口に対するモデルの例は以下のようになります。

  • ソフトウェアにおいて受注を受け持つ場所のワークフローに関する、処理から独立したモデル(CIM:Computation Independent Model)。ドメインエキスパート向け。
  • ソフトウェアにおいてバックエンドで管理を行う場所のデータに関する、プラットフォームから独立したモデル(PIM:Platform Independent Model)。ドメインエキスパート向け。
  • ソフトウェアにおいてカスタマポータルのセキュリティに関する、プラットフォームに特化したモデル("PSM:Platform Specific Model")。プログラマ向け。

交点における様々な切り口は、特定のモデルに対するモデリング言語を選択する上で重要な役割を果たします。例えば、モデリング言語は主題領域、ステークホルダ、抽象化のレベルによって影響を受けます。こうした言語は、主にドメイン特化言語("DSL")として提示されます。



しかし、モデリング言語のためのDSLだからと言って、視覚的であったり、グラフィカルであったりする必要はありません。モデルは現実の抽象的な表象にすぎず、テキスト形式のDSLを用いて表現することもできるのです。


要約すれば、MDEの方法論は諸々の切り口とその交点に関するフレームワークを定義し、それによって、あるソフトウェアアプリケーションを記述するために必要な、別々のモデルを定義しているのです。このことは、多少なりとも形式的な仕方で、求められるDSLについて議論する機会を与えてくれます。これは重要なことですが、MDEの方法論もまたソフトウェアエンジニアリングとメンテナンスのプロセスについて説明しています。それによって、モデルが生み出される順序、それぞれが(可能であれば)どう変換されるのか、モデルを使って既存のソフトウェアシステムをどう変更するのかを定義します。

ドメイン特化言語

DSLは次のように定義されます [2]

DSLとは、プログラミング言語ないし実行可能な仕様記述言語であり、適切な記法と抽象化によって、特定の問題ドメインに集中した(多くの場合は、同時にそこに限定された)表現力を提供するものです。


言語がドメインに対してどこまで特化しているかは、程度の問題です。どんな言語も、その適用可能性に関する何らかのスコープを持っています。しかし、他と比べて焦点がより絞られているものもあります。一般的に、あるDSLが対象とすることができるドメインは、2種類に分けることができます。

  • ナレッジドメイン:その分野において実践する人が理解できる一連の概念と用語法によって特徴づけられる知識ないし活動の領域。
  • システムファミリー:類似した機能を持つ、一連のソフトウェアシステム。このドメインはナレッジドメインの特殊な形と考えることができる。

原則として、ナレッジドメインはMDEが持つアスペクトの切り口と比較することができます。一方、システムファミリードメインは主題領域の切り口と比較することができます。MDEの方法論を設計する一方で、どういう種類のDSLが定義されるべきかを決定するのは重要なことです。表1に示した切り口の例を思い出せば、切り口の各交点のため(つまり、各モデルのため)にDSLを定義することで、90の異なるDSLが作られることになります(つまり、抽象/具象という切り口で3つ値があり、主題領域で×3、アスペクトで×5、ステークホルダで×2)が、これではあまりに多すぎます。以下に続く考察は、必要なDSLを減らす上で考慮に入れることができます。

  • 特定のプラットフォーム上で直接実行できるようにDSLを実装する。別のプラットフォーム上で実行できるようにするには、ジェネレータないしインタプリタを書き換えなければならない。これによって、抽象/具象の切り口が取り去られる。
  • 既存の汎用言語によって拡張可能なようにDSLを作成する。それによってプログラマは知っている言語を使って必要なものを追加することができる。これによってステークホルダという切り口が取り去られる。
  • アスペクトの次元に集中する。つまりDSLを各アスペクトに対して定義する。主題領域がきわめて特殊な場合のみ(例えば、特定の金融システムの一部)、そのためのDSLを定義する。

こうした提言を例に当てはめれば、DSLの数を90から5に減らすことができます。DSLが必要なのは、アスペクト、すなわちデータ、プレゼンテーション、セキュリティ、業務ルール、ワークフローなどに対してのみなのです。確かに、多くのモデルは定義しなければなりませんが、これは巨大なソフトウェアシステムでは普通のことであり、言語としては5つ用いれば良いのです。

なぜドメイン特化言語を使わなければならないのか?

言語は、ファンクションポイントを実装するために必要なコードの量を基準として比較することができます。これにより、自然言語マシン語アセンブリ言語のような低級言語から、特定のドメインを対象とした高級言語へと至る表ができあがります(SPRプログラミング言語表を参照)。汎用言語とDSLの違いは程度の問題ですが、DSLとして考えるべきはより焦点が絞られた言語、例えばBNF、HTML、SQLなどだと思います。


DSLは汎用言語に対して、いくつか重要な利点があります。[3]

  • ドメイン特化抽象化:DSLはアプリケーションドメインの概念を直接表象するための抽象化をあらかじめ定義する。結果として、ドメインエキスパート自身もDSLプログラムを理解し、検証し、時には開発することもできる [2]。
  • ドメイン特化シンタックスDSLは与えられたドメインに対する自然な記法を提供し、汎用言語を使った時にしばしば発生するような構文上の混乱が回避される。
  • ドメイン特化エラーチェック:DSLにより静的アナライザを構築することができるようになる。それによって汎用言語に対する類似のアナライザよりも多くのエラーを見つけることができ、ドメインエキスパートにより親しみ深い言語でそのエラーを報告することができるようになる。
  • ドメイン特化最適化:DSLにより、ドメインに特化した知識に関する最適化されたコードベースを生成する機会が生まれる。これは、通常汎用言語のコンパイラからは得られないものである。
  • ドメイン特化ツールサポート:DSLによって開発環境におけるツール面を改善する機会が生まれる。ここでいうツールには、エディタ、デバッガ、バージョンコントロールなどが含まれまる。DSLによって明確に把握されるドメイン特化の知識は、開発者に向けてより高度なツールを提供するのに使うことができる。

Deursen氏らは[2] DSLドメインの知識を具現化するもので、会話と知識の再利用を可能にすると付け加えています。Eric Evans氏 [4] もソフトウェア開発における複雑さに取り組むためには、言葉が開発者にとってもドメインエキスパートにとっても理解できるものでなければならないということを強調しています。


しかし、DSLは諸刃の剣でもあります。DSLの開発は困難で、ドメイン開発と言語開発の両方に対する知見を持たなければなりません。しかし、これを両方持つ人はわずかです。それに加え、ユーザコミュニティの規模に応じて、トレーニング素材の発達程度、言語サポート、標準化、メンテナンスなどが深刻で時間のかかる問題になります。

結論

MDAのアプローチもDSLのアプローチもソフトウェア開発における抽象化のレベルを引き上げることに焦点を合わせていますが、両者は異なるアプローチか、もしくは正反対のアプローチと考えられています。私自身はMDAが豊かになり、私がMDEと定義するものになるべきだと考えています。その場合、MDEとDSLのアプローチは、モデル駆動のアプローチを補完する、不可欠なものとなります。


MDEは、ソフトウェアアプリケーションを記述するのに必要な種類のモデルを定義する上で必要であり、またエンジニアリングとメンテナンスのプロセスを定義する上でも必要です。これはつまり、モデルを使ってどうソフトウェアを構築し、どう保守するのかを定義するということです。


DSLのアプローチはモデルを表現するための言語を定義するのに必要です。MDEのモデリングという切り口を使うことで、DSLのアプローチのスコープがより正確に定義されるのです。これはきわめて重要です。DSL設計における最も大きな落とし穴の一つに、要件の変化に伴ってスコープがどんどん拡大し、その結果ある種の汎用言語に帰結するというものがあるからです。


MDAとMDEはしばしばグラフィカルなモデルと関連づけられますが、これはOMGがUML標準に注力しているためです。思うに、あるモデルを表現するのに使用する言語は、できる限りそのモデルに適合したものであるべきなのです。これはセマンティックにおいてだけでなく、シンタックスにおいてもそうです。したがって、テキスト形式のDSLもMDEの一部になれなければならないのですなるべきなのです。




[1] S. Kent, "Model driven engineering," in IFM '02: Proceedings of the Third International Conference on Integrated Formal Methods. London, UK: Springer-Verlag, 2002, pp. 286-298.

[2] A. v. Deursen, P. Klint, and J. Visser, "Domain-specific languages: An annotated bibliography." ACM SIGPLAN Notices, vol. 35, no. 6, pp. 26-36, Jun. 2000.
[3] K. Czarnecki, "Overview of generative software development," in UPP, 2004, pp. 326-341.
[4] E. Evans, Domain Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2004.

アーキテクチャを支える言語

FowlerDSL本のAlternative Computational Modelを足がかりとして、ソフトウェアアーキテクチャにおけるDSLの役割について考察する。

導入

Martin Fowler氏はWeb版DSL本の中で、「DSLにおいて重要なのは、言語それ自体ではなく、DSLによって構築される意味モデル("Semantic Model")である」ということを繰り返し述べています(意味モデルについては、以前こちらのエントリで紹介しました)。その上で、この意味モデルが持ちうる、ある性質について「もう一つの処理モデル("Alternative Computational Models")」と題された章で説明されています。


ここで「もう一つの」("alternative")とされているのは、命令的な("imperative")処理に対する宣言的な("declarative")処理です。こうした宣言的な処理を支える意味モデルとして、適応型モデル("Adaptive Model";場所によってアクティブモデルとも呼ばれています)が想定されています。この適応型モデルとは、デシジョンテーブルやステートマシンのように、要素間の関係によってふるまいを規定するような抽象モデルのことです。Fowlerにとっては、こうした適応型モデルこそがDSLを使う意義の一つとなります。

Alternative computational models are also one of the compelling reasons for using a DSL, which is why I've spent a big chunk of time on them in this book. If your problem can be easily expressed using imperative code, then a regular programming language works just fine. The key benefits of a DSL, greater productivity and communication with domain experts, really kick in when you are using an alternative compuational model. Domain experts often think about their problems in a non-imperative way, such as a decision table. An active model allows you to capture their way of thinking more directly in a program and the DSL allows you to communicate that representation more clearly to them (and yourself).


もう一つの処理モデルもDSLを使用する上で説得力のある理由になります。これこそ私がこの本の中で多くの紙面を割いてきた理由でもあります。もし、命令型のコードを用いて容易に表現できる問題であれば、通常のプログラミング言語でうまく行くでしょう。DSLの主要なメリット、すなわち生産性を向上させ、ドメインエキスパートとのコミュニケーションをより良いものにするというメリットは、このもう一つの処理モデルを使った場合に効いてくるものなのです。ドメインエキスパートは、彼らが持つ問題について、デシジョンテーブルのように命令的ではないやり方で考えています。アクティブモデルを使えば、彼らの考え方をプログラムにおいて直接的にとらえることができますし、DSLを使えばこうした表象について、ドメインエキスパートと(そしてあなた自身と)より明確にコミュニケーションすることができるようになります。
http://martinfowler.com/dslwip/AlternativeComputationalModels.html

Fowlerのこの説明がこのエントリの出発点になります。FowlerのDSL本は適応型モデルについて、具体例としてデシジョンテーブル依存関係のネットワークルールシステムステートマシンといったものが例として挙げられるのみで、ソフトウェアを作成する上でどう考えるべきかについては言及されません。しかし、この点についての理解をもう少し深める(広げる)ことは、DSL全体についての理解を深める上でも重要なのではないかと思うのです。

EvansのDSL

まずは、DDDで有名なEric Evans氏のDSLに関する議論を、InfoQで紹介されているJAOOでのプレゼンテーションから見てみましょう。DDDにおけるEric Evansの考え方は「ユビキタス言語」という概念に集約されています。これは、モデルへと流れ込む情報に含まれる「言葉」に注目し、その言葉を用いてドメインモデルを構成することはもちろん、その言葉をプロジェクト内でのコミュニケーションから実装まで一貫して使用するというものです。


モデル自体よりは「モデルを構成する概念」を軸に考えているEvansが提示しているのが「細かいDSLを積み重ねることでソフトウェアを構成する」という発想です。具体例としては、「時間」という低次の概念をDSLを用いて表現できるようにするライブラリが示されます。

CalendarDate workDate = CalendarDate.of(2006,9,20)
CalendarDate dueDate = workDate.month().end().plus(Duration.days(30));

概念をレイヤに分解し、それぞれについて宣言的にプログラミングするためのライブラリを作るというやり方は、時間はかかるかもしれませんが、一度形になってしまえば可読性においても、生産性においても有効なものと考えられます。また、低次の概念ほど汎用性が高くなるため、全く別のプロジェクトにおいても再利用できるというメリットもあるでしょう。


ただし、ここではCalendarDateが宣言的に構築できるようになっているのみで、モデル自体は適応型ではない、単なるデータ構造にすぎません。DSLの意義がソースコードの可読性を向上させる点にも見出すことができることの一例ではないでしょうか。

適応型モデリング

「適応型」と訳語を当てていますが、この"adaptive"は「状況に合わせて変化することができる」といった意味ととらえるべきです。たとえば、「デシジョンテーブル」を表現したモデルはそれ自体ではふるまいを持たず、特定のルールを与えられて初めてルールに応じたふるまいができるようになります。ここからも分かる通り、適応型モデルの最大の意義はオブジェクトを組み替えることでふるまいを変えることができる点にあります。さらに言えば、この「ふるまいの定義」を実行時に行える点が大きなメリットであると言えるでしょう。アプリケーションの設計において、こうした可変性を整理しておくことは重要です。


Johan Den Haan氏は、モデル駆動ソフトウェア開発(MDSD)について説明しているエントリにおいて、可変性を次の3つのレベルで考えています。

  • レベル0: 特定のドメインにおける、アプリケーションの静的な部分
  • レベル1: DSLを用いてアプリケーションの開発もしくは設計時に定義される可変な部分
  • レベル2: 実行時に設定される、あるいは変化するアプリケーションの場所

その上で、レベル2の可変性を実現する方法として、何らかのエンジンを使う方法と適応型モデリングを使う方法が提示されます。エントリのテーマであるMDSDのスピードアップという観点から、適応型モデリングの長所と課題についてそれぞれ次のように説明されています。

長所:

  • 変化に適応するのが早く、容易である。
  • 保守期間を必要とせず、実行時に変更できる。
  • 変更が制御されたものだけである、つまり、レベル2の変更だけが実行時に可能である。
  • 変更が抑制され制御されていれば、テストの手間は少なくなる。


課題:

  • MDDのメリットはできる限り特化した言語を使うことにある。適応型モデリングが意味するのは、モデルとツールによるサポートがより抽象的で特殊性が低いということだ。
  • どこまでやるのか?つまり、何をレベル1とし、何をレベル2とするべきなのか?
  • 適応型モデリングにおいて、編集は難しくない。一方で、テストやデバッグツールをどう使うのか?どう品質を保証するのか?この点に関する課題はエンジンを使った場合の方が強い。

つまり、適応型モデルは、こうした課題を考慮し、またエンジンの使用も検討した上でメリットが出る場合に採用するべきだと考えるべきでしょう。

まとめ

DSLを考える上でまず重要なのが、モデルと言語を区別することだということには変わりありません。その上でモデルの設計をする際に、どういうレイヤを積み重ねるのか、各パートの可変性をどのレベルで考えるべきなのかということについて、アップフロントに考えておく必要があるということになりそうです。開発/設計のレベルで可変性(というより柔軟性)を保持するのであれば、通常のドメインモデルを構築し、それを操作するためのFluentなAPIを準備するという流れが基本になるでしょうし、ランタイムの可変性が求められるのであれば、適応型モデルが必要になるでしょうし、DSLのタイプも必然的に外部DSLにならざるを得ないでしょう。


また、今回は可読性可変性という観点から、DSLについて考えてきましたが、それとは逆の方向で言語が持つ規定性についても、意識しておく必要があるでしょう。コンパイル言語である限りランタイムの可変性→外部DSLが必須ですが、逆に外部DSL→ランタイムという訳ではありません。例えば、Webフレームワークの画面遷移などは定義ファイルに書かれることが多いですが、実際に変更してしまえば正常に動作はしません。そういう意味では、ホスト言語を超えた表現力を獲得するために外部DSLが選択されているとも言えますが、一方でクライアントコードから直接オブジェクトを操作することができないため、予め想定されていない操作をされてしまう可能性を抑えることもできるようになります。こうした規定性はアーキテクチャを安定させる上で大いに役に立ちます。


つまり、ドメイン=ビジネスドメインと考える必要はなく、適切なレイヤリングを行うことでレイヤごとにそれぞれのドメインが定められることになります。その上で、ソフトウェア全体として「固定する所はがっちりと規定し、可変にするべき所はその性質に応じてどこまでも柔軟にする」という、アーキテクチャ策定上の基本戦略を支えてくれるのがDSLだということになるのではないでしょうか。

モデル・ビュー・コントローラ - Trygve Reenskaug

この記事はTrygve Reenskaug氏の記事「MODELS - VIEWS - CONTROLLERS」を、氏の許可を得て翻訳したものです。(原文公開日:1979年12月10日)


モデル

モデルは知識の表象です。モデルは1つのオブジェクトであるかもしれませし(あまり面白くはありませんが)、複数のオブジェクトからなる構造かもしれません。


モデルとその一部には一対一の対応関係がある一方で、モデルとその所有者によって知覚された世界の表象との間にも一対一の対応関係があります。したがって、モデルの各ノードはその問題における識別可能な一部分を表象しているのです。


モデルの各ノードは、同一水準の問題を扱うものでなければなりません。問題指向の各ノード(例えば、カレンダーの予定)を実装の詳細(例えば、パラグラフ)と一緒にすることは混乱を招きますし、良くない形式と考えられます。

ビュー

ビューはモデルの(視覚的な)表象です。普通は、モデルが持つ特定の属性を強調し、それ以外のものを抑制します。このように、ビューはプレゼンテーションフィルタとして機能するのです。


ビューはモデル(あるいはその一部)に付随し、プレゼンテーションに必要なデータを、モデルに問い合わせることで取得します。同様に、適切なメッセージを送信することでモデルを更新することもあります。こうした問い合わせとメッセージはすべて、モデルを構成する用語法の中に含まれていなければなりません。(例えば、モデルの識別子を要求した際には、テキストのインスタンスが返されることを期待するのは良いですが、モデルがテキストクラスであると想定すべきではありません。)

コントローラ

コントローラはユーザとシステムとを紐づけるものです。ユーザに対するインプットは、対応するビューを画面の適切な場所に表示させることによって提供し、ユーザがアウトプットするための手段としては、メニューやその他コマンドやデータを送るための手段を表示させます。コントローラはこうしたユーザからのアウトプットを受け取り、適切なメッセージに変換した上で、1つまたは複数のビューへ引き継ぎます。


コントローラは決してビューを補完すべきではありません。例えばノードのビューの間に矢印をひくことでそれらをつなげるということをしてはならないのです。


逆に、ビューはマウス操作やキーボード操作のようなユーザからの入力について知っているべきではありません。ユーザからの一連の指示を正確に再生するメッセージを送信するようなメソッドは常にコントローラに書くことができなければなりません。

エディタ

コントローラはそのビューすべてと紐づいているため、これらのビューはコントローラの一部と呼べます。ビューによっては特別なコントローラ、すなわちエディタを提供するものもあります。これはユーザがビューに表示された情報を修正できるようにするものです。このようなエディタはコントローラとビューをつなぐルートに接合され、コントローラの延長として機能します。編集のプロセスが完了すれば、エディタはそのルートから取り外され、破棄されます。


追記しておくと、エディタは紐づけられたビューのメタファーを通じてユーザとコミュニケーションします。したがってエディタはビューと密接に関係しているのです。コントローラがエディタを取得する際にはビューに問い合わせを行います。エディタを保持する適切な場所は他にありません。



翻訳者解説

これは1978〜1979年というMVCの黎明期に行われた議論を経て、まさに"Model-View-Controller"という用語が定義された際のドキュメントです。30年前のものということもあって、実装や責務分割という点から見ると現在とは異なっているところもあります。特にエディタについては現在ではビューの延長として考えられており、コントローラは複数のビューの生成、制御とユーザからの入力の処理を受け持つことになっています。Reenskaug氏のサイトより現在のMVCを表した図を引用します。


MVC illustration.


このように多少古くなっている部分もあるのですが、注目すべきは「知識の表象としてのモデル」、「モデルの一部を視覚的に切り取ったものとしてのビュー」、「モデルの用語を使ったユーザとのコミュニケーション」といった、後のドメインモデルへとつながる思想が既に凝縮されている点です。モデルは生まれた瞬間から「モデル」だったということですね。