Practical DDD #2: 責務のレイヤーとPolicy-Control-Operation
2014年4月6日に大阪で開催された第4回ドメイン駆動設計読書会@大阪に参加しました。読書会の内容のまとめなどはWikiの方をご参照ください。今回は第1章の知識のかみ砕き、深いモデルと第2章ユビキタス言語の前半を読み、ディスカッションしました。ディスカッションで得られた気付きとこれまでに私が考えていたこと、ドメイン駆動設計の後半に出てくる「責務のレイヤー」などとのつながりについて、考察してみます。
モデルの「深さ」とは何か
モデルに対して深いのか浅いのかについて、ドメイン駆動設計で何か客観的な指標が示されているわけではありません。あくまでエヴァンス氏の主観でしかないと言えますし、開発者が取り組んでいるドメインやコンテキストに依存するものでもあります。ドメイン駆動設計においては、モデルの深さを探求していくことが大きな目標の1つとされており、「深いモデル」という言葉が開発者同士の共通語になってはいます。しかし、もう少しブレの無い言葉で表現しておいた方が良いように思います。ここで、ソフトウェア工学で使われてきた「凝集度」という言葉を使えば、「概念群の凝集度」という視点で置き換えられるのではないかと私は考えます。この捉え方はすでに増田亨さんのブログでも触れられています。ドメイン駆動設計の後半では、蒸留カテゴリの中に凝集は繰り返し現れます。
ユビキタス言語で凝集度を判定する
内容の順序と前後しますが、ユビキタス言語の章では2つのシナリオが例示さています。分かりやすい箇所を抜粋します。
シナリオ 1:開発者:わかりました。該当する貨物IDを持ったすべての行を輸送テーブルから削除してから、荷受け地と荷出し地、新しい通関地点を経路選択サービスに渡せば、テーブルにデータが再登録されます。貨物にブール値を持たせて、貨物テーブルにデータがあることがわかるようにしましょう。
シナリオ 2:
開発者:わかりました。経路仕様にある属性をどれか1つでも変更したら、古い輸送日程を削除した上で、経路選択サービスに対して、新しい経路仕様に基づいた新しい輸送日程を生成するよう依頼します。
シナリオ 1 では、ユビキタス言語由来の単語は2つですが、シナリオ 2 では3つになっています(この箇所では貨物は出てこなくなっています)。そして、伝えたい意図を表現するための語彙のセットに変化しています。シナリオ 1 では、概念凝集度の低いモデルの表象としてのユビキタス言語をベースに開発者が意図を話そうとしているわけですが、この発言をしながら開発者自身「語彙が足りない」ことに気づくのではないでしょうか。言うならば、初めての海外旅行先で英語を話そうとしても、言いたいことが言えないという感覚と同じです。みなさんもモデリングセッションの中で少なからず体験されていることと思います。
ユビキタス言語が凝集されていない状態:
凝集度の高いユビキタス言語:
ところで、次に出てくる疑問は、どのようにしてユビキタス言語を構成しうる知識をかき集め、ドメインモデルを成長させていくのか、という点でしょう。これをエヴァンスは「知識のかみ砕き」や「蒸留」、「隠された概念を引き出す」のように表現しています。
オーバーブッキングポリシー
「隠された概念を引き出す」例として、オーバーブッキングポリシーの話が示されています。貨物輸送ドメインにおいては「オーバーブッキングの仕方」は重要な概念なので、概念として明示的にドメインモデルに登場させます。それと同時に実装コード側も、メソッド本体の if 文に埋もれた状態から1つの独立したクラスに切り出されています。
この例では、業務知識からの要請によってオーバーブッキングポリシーという概念を得ています。この程度のものであれば、業務知識がなかったとしても、コードのリファクタリングから発見できた可能性もあるでしょう。ドメイン駆動設計では実装からのフィードバックも重視されており、実装とコードのリファクタリングから何か得られるかもしれない、という心構えは常に必要です。
一方で、あらゆる対象ドメインをゼロから実直にモデリングして実装し、リファクタリングを繰り返さなければ深いモデルにたどりつけないのかという疑問が出てきます。手早く確実に「オーバーブッキングポリシー」という概念を得る方法はないのでしょうか。業務知識を豊富に持っていれば、もちろん役立つでしょう。しかし、あらゆるドメインの個別知識を持つことなどできません。ある程度汎用性のある知識、つまり知識の体系、それも一段階抽象度の高いメタレベルの知識体系が、このような問題解決に役立ちます。このようなメタレベルの知識体系としてドメイン駆動設計で取り上げられているものの1つが、第16章「大規模な構造」の中の「責務のレイヤー」です。
責務のレイヤー
責務のレイヤーがどのようなものなのかの説明は書籍を読んでいただくとして、オーバーブッキングポリシーの例を責務のレイヤーに割り当ててみると、私の理解では次のようになります(例では航海が積載量を保持していますが、能力レイヤーに該当する要素としてうっすらと船・顧客の存在を示してみました。こちらに積載量を持たせてみています)。
ただし、この責務のレイヤーというのは文字通り「責務」のレイヤーであり、下から上方向への依存がないような知識の体系ではありますが、それでもドメインのある1つの側面を取り出してレイヤー構造に表したにすぎません。実際に貨物の運送予約という業務のユースケースを想定した場合、意思決定支援/ポリシーレイヤーにある知識が当然業務で使われなければなりませんから、この段階(コンテキスト)ではレイヤーが異なるという意識は不要になります。
ここで示したように、責務のレイヤーという知識体系によって、オーバーブッキングポリシーがどのような種類の情報なのかが明確になりました。とても自然に、それぞれの情報が各レイヤーに当てはまっているように見えます。逆に、責務のレイヤー(能力/業務/意思決定支援・ポリシー)という情報の分類を開発者が最初から知っていれば、オーバーブッキングポリシーという概念に相当早くたどり着けるように思われます。
「それなら、なぜドメイン駆動設計の最初に、責務のレイヤーを説明しないんだ!」という声が聞こえてきます。私もそう思いました。
責務のレイヤーとドメイン駆動設計の関係
責務のレイヤーを最初から知っていれば、深いモデルに早くたどり着ける。これはつまり、責務のレイヤーという概念は、ドメインの知識体系そのものの一部分であるということです。エヴァンスが「ドメイン駆動設計」として本にまとめて伝えようとしているエッセンスは、ドメインの知識体系にどうアプローチしていくのかということです。ですから 、責務のレイヤーはより早く深いモデルに到達するための既存知識体系の1つ、として紹介されているだけなんでしょうね。同じように、アナリシスパターンなどが知識体系のショートカットとして紹介されています。このようなメタレベルの知識体系で役立つものは他にいくつもあります。
ところでこの責務のレイヤーという知識体系について、元をたどるとPolicy-Control-Operationという体系があることを、2月の関西IT勉強宴会に登壇された中西先生から教わりました。
Policy-Control-Operation
経営、管理、業務という3つのタイプで、これは企業や何らかの組織がある目的を持って活動する時、つまり経営活動が行なわれる時に、さまざまなレベルで表れる構造です。
この構造のうち、特に情報の種類について言及されている例が、Milt Bryce and Tim Bryce著「IRMー情報資源管理のエンジニアリング」第2章(p. 37)の表「情報が果たす役割」として挙げられています。
ドメイン駆動設計読書会の最初の回でも紹介されていたTM(T字形ER手法)の佐藤氏のページでも、事業過程・管理過程・組織過程という業務の階層の考え方が解説されており、モデリングの際の視点の決め方として重要とされています(これは遡ると20世紀初頭の管理原則の父アンリ・ファヨールの管理過程論などからの系譜です)。
長くなりましたので、続きの「船荷証券」の話は、また次回 (Practical DDD #3: モデルの深さ)。