ObjectSquare [2007 年 10 月号]

[技術講座]


DDD難民に捧げる
Domain-Driven Designのエッセンス
第3回 大規模なプロジェクトへの適用

株式会社オージス総研
アドバンストモデリングソリューション部
佐藤 匡剛

Domain-Driven Design の表紙

Domain-Driven Design
Tackling Complexity in the Heart of Software

Eric Evans 著
Addison-Wesley, 59.99ドル
560ページ
ISBN: 0-321-12521-5

書籍『Domain-Driven Design』を紹介する本連載も、今回で最終回です。前回はDDDの第II部、第III部を紹介し、16のパターンによってドメインモデリングの基本的なアプローチを説明しました。今回は、残る第IV部から22のパターンを紹介します。

単一ドメインを扱ったドメインモデリングのノウハウは、前回までですべて終了です。第IV部「Strategic Design」(戦略的デザイン)が扱うのは、エンタープライズアプリケーション統合(EAI)やSOA、エンタープライズアーキテクチャ(EA)のように、複数ドメインが関与する広大なスコープをもったプロジェクトです。経営戦略的(strategic)なレベルで、いかにしてドメインを中心に据えつつ、企業のコアコンピタンスに貢献できる情報システムを構築するかを説明しています。

「戦略的デザイン」の22パターンは、アプリケーションアーキテクトや統合アーキテクト、さらには企業全体の情報アーキテクチャの決定に責任をもつ人々にも、ぜひとも知ってもらいたいノウハウです。

IV. Strategic Design(戦略的デザイン)

第IV部では、EAIやSOAのようにシステム間の連携を必要としたり、スコープが広大で複数ドメインをまたがったりするようなソフトウェア開発のプロジェクトが対象となります。このような大規模プロジェクトは、企業情報システムの全体構造(EA)に深く関係するため、経営戦略的な視点が求められます。

DDDは、こうした高いレベルにおいても、ドメイン知識を深く反映したシステムこそがビジネスに大きな価値をもたらすという信念を忘れません。ドメインモデル(企業全体のモデル)とそれを実現する個々の実装システム(レガシーシステムやパッケージ製品を含む)とを緊密に対応付け、ビジネス側と技術チームとが互いに理解しあえる共通のユビキタス言語を作り出す、という基本原則をあくまで貫いています。

DDDの「戦略的デザイン」は、以下の3つで構成されています。

コンテキスト ― 他システムとの統合

EAIやSOAのように複数のアプリケーションが連携するようなプロジェクトでは、異なるドメインモデル間の不整合が大きな問題となります。たとえば顧客に対する請求のシステムとビジネスパートナーへの支払いを管理するシステムとでは、同じ「請求」(Charge)という概念でもその意味するところは全く異なります。それを混同してしまうのは、致命的なバグに繋がります。そのため、いかにして各アプリケーションがもつドメインモデルの一貫性を保つかが、最大の課題となります。

DDDでは、ドメインモデルの有効範囲となる「コンテキスト」を考えます。以下に登場する10パターンは、プロジェクトにどんなコンテキストが関与するかを明らかにし、コンテキスト間の関係を整理しつつその境界を維持することによって、ドメインモデルの一貫性を保ちます。

コンテキストの境界を定める

ドメインモデルの一貫性を保つために、コンテキストを維持する基本的な方法を示します。

● Bounded Context(コンテキスト境界)パターン

いくつかのビジネス領域にまたがる大規模な開発プロジェクトでは、それぞれ異なった複数のドメインモデルが並存することになる。本来ドメインモデルが異なるものを無理やり1つのコードベースで表そうとすると、当然無理が生じる。また、チーム内でのコミュニケーションも破綻する。そのため、ドメインモデルの適用可能な範囲(コンテキスト)をはっきり定める必要がある。コンテキストは、チーム編成、アプリケーションのユースケース、コードベースやデータベース(DB)スキーマに沿って、その境界線を引く。コンテキスト境界の中でドメインモデルの一貫性を保ち、境界の外から干渉されないようにする。

● Continuous Integration(継続的な統合)パターン

コンテキスト境界内でも、複数の人間が作業をしていると、次第にドメインモデルは崩れていく。ドメインモデルの一貫性を維持するために、継続的な統合を実践する。つまり、同一コンテキスト内の全コードをマージし、自動テストによりその整合性をチェックする作業を、日々のプロセスとして実行していく。

(「継続的な統合」はエクストリームプログラミング(XP)の実践の1つでもあるが、DDDではコードの統合以上に「概念の統合」に力点が置かれている)

● Context Map(コンテキストマップ)パターン

コンテキスト境界を設定し、その中で一貫したドメインモデルが維持できたら、今度はもっと大きな全体像を把握するために(非OOなレガシーシステムを含む)コンテキスト間の対応関係を明確にする。各コンテキストには、チームのユビキタス言語となるような名前を付ける。それから、あるコンテキストのモデルが別のコンテキストのどのモデルに対応するか、というモデル間の変換マップを考える。システム間連携においては、アプリケーション毎にドメインモデルが全く異なっているのがほとんどなので、コンテキストマップをしっかり作っておくことが重要になる。

コンテキスト間の6つの関係

コンテキストマップに登場するコンテキスト間の関係には、次の6種類があります。

● Shared Kernel(共有カーネル)パターン

互いに関連しあう複数のコンテキストを別々のチームで開発しているときに、わざわざ苦労してモデルの変換層を用意しコンテキストの自立性を保つよりも、モデルの一部を直接共有してしまう方が現実的なこともある。共有される核(カーネル)の部分には、ドメインモデル、ソースコード、DBスキーマなどが含まれる。コンテキスト内ほど頻繁でなくてもいいが、カーネルを共有する複数コンテキストをまとめて、定期的に継続的な統合を実施すること。共有カーネルは特別な部分になるため、他チームへの相談なしに勝手に変更を加えてはならない。

● Customer/Supplier Development Teams(顧客/供給者の開発チーム)パターン

コンテキスト境界の分かれた2システム間の関係が、一方が他方を利用する形になっていることがある。その場合、各チームの役割は必然的に異なったものとなるので、両者の運営を円滑にするために、2チーム間に顧客(使う側)と供給者(使われる側)の関係を導入する。供給チームは顧客チームに対して、実際に交渉や見積もりを行なう。供給チーム側のシステム修正を容易にするため、受け入れテストを供給チーム側の継続的な統合に組み入れる。

● Conformist(順応者)パターン

使われる側のチームが力を持っている場合など、主に政治的な理由で顧客/供給者の関係がうまく構築できないこともある。そのときはコンテキスト境界を固持せずに、あえて使われる側のドメインモデル(ユビキタス言語)に隷属的に従うという選択肢もある。当然、使う側では理想的なドメインモデルを設計できなくなるが、その代償としてアプリケーション統合が劇的に簡単になる。

● Anticorruption Layer(腐敗防止層)パターン

新規に構築するアプリケーションも、たいていはレガシーなど既存の外部システムと連携しなければならない。既存システムが持つドメインモデルは、これから構築しようとする新しいドメインモデルにはそぐわないことが多い。両者のモデルの対応付けが容易でない場合は、新システムと既存システムとの間に隔離層(腐敗防止層)を設けて、そこで両方向に対するモデルの変換を実装して両者のモデルを完全に独立させてしまう。ただし、腐敗防止層の構築には大きなコストがかかるので注意。

● Separate Ways(別々の道)パターン

もし2つのアプリケーションがほとんど機能を共有しておらず、統合することにメリットがないのであれば、無理して統合せずに互いに無関係な別々のコンテキストとして開発していった方がいい。

● Open Host Service(公開ホストサービス)パターン

あるアプリケーションが他の多くのアプリケーションから利用されるような場合は、1つ1つについて変換層を用意するような面倒をせず、プロトコルが公開された共有サービスの形にする。サービスの機能を拡張したいときは、プロトコルを拡張していく。

補足的なパターン

コンテキスト間の関係を構築する際に、次のような補足的なパターンを用いることもできます。

● Published Language(公表された言語)パターン

コンテキスト間連携の通信媒体として、共通の情報モデルを定めたいことがある。しかし、既存の自家製ドメインモデルでは不適切なことが多い。モデルが未成熟だったり、無駄に複雑だったり、あるいは文書化されていなかったりするためだ。そのようなときは、きちんと文書化されていて広く周知された共有言語を採用するのがよい。

蒸留 ― 抽象化の方法

コンテキストによって一貫性あるドメインモデルを維持できたとしても、複数ドメインが関与する複雑なプロジェクトからビジネスに重要な本質部分を見抜くことは容易ではありません。競争力の源泉となるようなエンタープライズシステムを構築するには、ドメインに適切な抽象度を与えて、ビジネスにとって本当に重要な部分にフォーカスして資源を投入していかなければなりません。

DDDでは7つのパターンによって、広大なシステムから本質部分を「蒸留」(distill)するノウハウを示します。*1「蒸留」パターンは、開発上の優先度を示すとともに、アウトソースやオフショア開発、パッケージ製品の導入などの戦略上の決定をする際の指針にもなるものです。

*1 蒸留とはもともと化学用語で、複数の物質が混じり合った混合物を蒸発させることによって、特定の化学成分だけを濃縮する操作のことです。ちなみに、Eric Evansは化学工学の修士号をもっているそうです。

ドメインの優先順位付け

エンタープライズシステムの本質部分を見つけるには、ドメインを「中核ドメイン」と「汎用サブドメイン」の2つに分類し、優先順位を明確にします。

● Core Domain(中核ドメイン)パターン

巨大なシステムでは、複数の異なるドメインモデルが並存する。すべてのドメインで完璧なモデルを構築することは不可能なので、優先順位を付けて、ビジネスにとって最も影響力のある重要なドメイン(中核ドメイン)にフォーカスする。中核ドメインに最も優秀な人材を投入し、経営資源を注ぎ込む。中核ドメインの資産価値を最大化しつつ、他の周辺ドメインは中核ドメインへの貢献度によりその投資対効果(ROI)を評価していく。*2

*2 他のパターンの多くが複数形「〜s」で名付けられているのに対し、中核ドメインパターンが単数形なのは、おそらく中核は本来システム中に1つしかないものだからでしょう。

● Generic Subdomains(汎用サブドメイン)パターン

ドメインの中には、ビジネス上の差別化要因とならない汎用的な機能を提供するだけのものがある。そうしたドメインはサブドメインとして中核ドメインからは区別し、開発上の優先度を低く設定する。汎用サブドメインから深いドメイン知識が得られることは稀なので、優秀な人材をそこに投入してはならない。汎用サブドメインの構築には、以下の4つの選択肢がある。

  1. パッケージ製品を導入する
  2. 公表されたモデル(アナリシスパターンなど)を流用する
  3. 開発をアウトソースする
  4. 自社で開発する

中核ドメインの文書化

中核を見出したら、今度はそれを見失わないようにドキュメント化します。

● Domain Vision Statement(ドメインビジョン声明文)パターン

中核ドメインでは、プロジェクト開始時に1ページほどの「ドメインビジョン声明文」を用意する。声明文とは、ドメインの説明と、ドメインがビジネスにもたらす価値(バリュー・プロポジション)とを簡潔に書いたもの。記述はなるべく簡潔に努め、新たな知見を得るたびにきちんと改訂していく。声明文を用意することの意義は、プロジェクトのことを詳しく知らなくても、誰もが一目でそのドメインの価値を理解できるようにすることにある。

● Highlighted Core(中核のハイライト)パターン

ドメインビジョン声明文中核ドメインの価値をすぐさま理解するのに重要だが、ドメインをもう少し詳しく理解したいときには別のドキュメントが必要になる。「中核のハイライト」は中核ドメインの構成要素が何であるかを示し、人によって中核ドメインの理解がブレないようにするためのドキュメントである。中核ハイライトの書き方には、次の2つのアプローチがある。

  1. 中核ドメイン(構成要素とその相互関係)を簡潔に記述した、3〜7ページの軽いドキュメントを用意する
  2. プロジェクトのモデル全体を記述した正式な設計ドキュメント上で、中核ドメインの構成要素となるモデルに単に印を付けていく

中核を磨き上げる

優先順位付けにより抽出された中核も、そのままでは本質と関係のない不純物が混ざっていたり、まだドメインが複雑すぎることがあります。ドメインリファクタリングによって、中核をさらに中核的なものへと磨き上げていく必要があります。

● Cohesive Mechanisms(凝集されたメカニズム)パターン

中核ドメイン汎用サブドメインはドメインモデルの中で注目すべきものとそうでないものとを分けるためのパターンだが、ドメインモデル(What)と実現のためのメカニズム(How)とを分離することも必要になる。概念的にまとまりのあるメカニズムを、軽量なフレームワークの形にしてドメインから分離する。フレームワークのインタフェースには意図の明白なインタフェースパターンを採用し、ビジネス上の問題とテクニカルな解決法とを明確に切り分ける。こうすることで、ドメインはより宣言的(declarative)なスタイルになっていく。汎用サブドメインはドメイン上の汎用部分を抽出するパターンなのに対し、凝集されたメカニズムはソリューションの汎用部分を抽出するパターンと言える。

● Segregated Core(中核の隔離)パターン

中核ドメインの中から、さらに本質と関係のない付随的な部分を汎用サブドメインの方へ移していく。ドメインリファクタリングを施し、本質的な概念だけからなる純粋なモデルになるよう中核を隔離していく。分割によって中核を磨き上げる方法。

● Abstract Core(中核の抽象化)パターン

中核ドメインが複数のモジュールで構成され、モジュール間に複雑な相互作用があるような場合、各モジュール内のキープレイヤーを(抽象クラス/インタフェースによって)抽象化したモデルを作り、それを新しい1つのモジュールにまとめる。このモジュール内のモデルは、複数モジュール間の相互作用を抽象化して全体像をまとめたものになる。そして、これが新しい中核のモデルとなる。抽象化によって中核を磨き上げる方法。

大規模な構造 ― 「大きな絵」の共有

コンテキスト蒸留により、統合システム間の関係を把握し、システムの本質部分にフォーカスすることが可能となりますが、それだけでは大規模なシステムが全体としてどんなストーリーをもっているかを理解することはできません。大規模システムの構築を成功させるには、チーム内のメンバやチーム間でアーキテクチャレベルの「大きな絵」を共有し、同じ目標意識をもって協調していくことが肝心です。

DDDは最後に、概念レベルの大規模な構造を扱うための5つのパターンを示します。ただし、著者自身も認めているように、「大規模な構造」をパターンにまとめる試みはまだ始まったばかりであり、DDDが現時点で提供できるノウハウも部分的なものに過ぎません。「大規模な構造」のパターンは、今後さらなる成熟が求められる分野でもあります。

大規模な構造を扱う際の基本思想

大規模な構造を設計する場合には、経験則から、まず始めに受け入れなければならない基本的な考え方があります。

● Evolving Order(進化する秩序)パターン

すべての要件を満足する大規模な概念構造を、一度に設計することは不可能だ。アプリケーションを作りながら、少しずつ構造を進化させていくのがよい。進化の過程で、以前とまったく異なる構造に変化していくことも稀ではない。大規模な構造はコンテキストマップと違い必須のものではないため、誤った構造を作り込んでしまう位なら何も構造を定めない方がよい。したがって、常に必要最小限のシンプルな構造を探し求めること。

大規模な構造の3例

DDDが現時点で提供できる大規模な構造のパターンには、以下の3つがあります。

● System Metaphor(システムのメタファ)パターン

比喩(メタファ)を使うことが、システムアーキテクチャの理解に有効なことがある。その場合は、チームにメタファを浸透させ、ユビキタス言語に取り込む。しかしメタファとは本来大雑把で不正確なものなので、不適切なメタファを使うとチームを誤った方向に導いてしまう。メタファを使う場合は、それが本当に適切かどうかを継続的に検証しつづけなければならない。システムの開発が進むにつれてメタファが適切でなくなってきたら、メタファを捨て去る勇気を持たなければならない。

(XPの実践の1つである「システムのメタファ」と同じものである)

● Responsibility Layers(責務の階層)パターン

オブジェクト指向設計では、各オブジェクトを責務の割り当てに基づいて設計する責務駆動設計(Responsibility Driven Design, RDD) が基本だが、RDDは大規模な構造に対しても適用可能だ。大規模な構造においては、アーキテクチャパターンのLayersパターンを責務の構造にも適用し、システム全体にまたがった「責務の階層構造」を考える。階層構造では、上位層は下位層に依存するが、下位層は上位層からは独立している。責務の階層は、システムの高次元の目的や設計を物語り、ドメインモデル設計のガイドラインとなる。責務の階層の一例を示すと、以下のようなものになる。

  • 意思決定(decision)層 … どんな戦略やポリシーを実行すべきかを決定する層
  • ポリシー(policy)層 … 戦略上のゴールや業務ルールを実際に適用する層
  • 運用(operation)層 … 日常行なわれている業務を表す層
  • 業務基盤(capability)層 … どんなリソースがあり、業務上なにが可能なのかを表す層

● Knowledge Level(知識レベル)パターン

アナリシスパターンには、オブジェクトを「運用レベル」(operational level)*3と「知識レベル」(knowledge level)に分けるパターンがある。この考え方は、大規模な構造を設計する場合にも適用できる。知識レベルのモデルは、運用レベルのドメインモデルについてのルールや知識を規定する。知識レベルは一見「責務の階層」の一例のようにも思えるが、知識レベルと運用レベルの間には双方向の依存関係が許容される点が異なる(責務の階層では下位層は上位層からは独立している)。

(知識レベルとは「モデルについてのモデル」のことなので、アーキテクチャパターンのReflectionパターンをドメインモデルに適用したケースと捉えることもできる)

*3 「操作レベル」という訳の方が有名ですが、知識(knowledge)との対比で "operation" を使うときは、法体系や業務ルール、経営上の意思決定に対して、それを実際に適用し実施するという意味合いが強いと思い、あえて「運用レベル」という訳語を充てました。ビジネスの世界でよく使われる operation という言葉には、たとえば運用部門(operational department)や、企業の最高意思決定者であるCEOとの対比で最高業務責任者(Chief Operating Officer、COO)などがあります。「知識」との対比が分かりにくい「操作」よりも、概念上の決まりごと(知識)を実行に移すという意味で「運用」と訳した方が、2つのレベルの違いがイメージし易いのではないかと私は考えています。

DDDの最終形態

ドメインモデル開発の成功を繰り返し経験した幸運なプロジェクトが、稀に到達することのできるDDDの桃源郷があります。

● Pluggable Component Framework(着脱可能コンポーネントのフレームワーク)パターン

あるドメインで何度かDDDを成功させ、ドメインへの深い理解へと到達していくと、そのドメインに特化したドメインフレームワークを設計できることがある。ドメインフレームワークとは、中核の抽象化により抽出されたドメインの中心的なインタフェースと相互作用から構成される中央ハブのようなもので、そこにドメインの可変部分をコンポーネントとして着脱できる。ただし、ドメインフレームワークには、(1) 実現が非常に難しい、(2) フレームワークが提供する中核ドメインにアプリケーションが縛られる、などの欠点もある。

(半導体製造ドメインで「着脱可能コンポーネントのフレームワーク」の構築を試みた例に、Mohamed FayadとRalph JohnsonのSEMATECH CIMフレームワークがある)

[コラム] 戦略的DDDをエンタープライズアーキテクチャに適用した事例

DDDの「戦略的デザイン」パターンは企業の経営戦略レベルに適用できるとは言っても、具体例がないとなかなかイメージしにくいと思います。DDDの公式サイトにて、エンタープライズアーキテクチャ(EA)の改善に「戦略的デザイン」パターンを適用した、ノルウェーの大手石油/ガス会社StatOil社の事例が紹介されています。*4

StatOil社では、原油・精油・液化天然ガス(LNG)を扱うサプライチェーンのビジネスプロセスにEAを適用して、IT投資への戦略を練っています。この事例では、EAの論理的なアーキテクチャと、それを実現する物理的なソフトウェアアーキテクチャとのギャップを埋めるのにDDDを適用しました。事例には、「(資源の)供給業務」「請求業務」「取引業務」「通信ゲートウェイ」「輸送と配給」「フロント画面」「フォルダ」「文書ストレージ」の8つのコンテキストが登場します。この大規模なエンタープライズシステムに対して、戦略的デザインの3要素「コンテキスト」「蒸留」「大規模な構造」を適用し、評価しています。

「コンテキスト」の適用では、上記の8コンテキストからコンテキストマップを作成し、コンテキスト間の関係を顧客/供給者共有カーネル公開ホストサービス腐敗防止層の4パターンに分類して整理します。「蒸留」の適用では、各コンテキストを中核ドメイン汎用サブドメインに分類し、開発上の優先順位を定めます。「大規模な構造」の適用では、責務の階層を導入してコンテキストを階層毎に分け、各コンテキストの担当者が担うべき役割を明確化します。

適用結果は、以下のようにまとめられています。

コンテキスト
コンテキストマップおよびマッピングの過程で得られた知見が、EAの中で新規プロジェクトのスコープを決定するのに大いに役立った。また、既存のソフトウェアアーキテクチャの改善にも貢献した。
蒸留
中核ドメインの特定が、開発資源を分配する指針の決定や、開発中のソフトウェアがどんな目的をもっているかを開発者自身が理解するのに役立つと思われた。しかし、そのためにはどのドメインが最も重要かについて、ビジネス側の合意を得なければいけない。これは困難で、ビジネス側にも熟練を要求する作業だった。
大規模な構造
責務の階層の適用が、当事者間のコミュニケーションの促進に役立つと思われた。しかしそのためには、責務の階層が定める責任範囲へのコミットを、ビジネス側から得なければならないというハードルがあった。

このレポートの結論は、コンテキストマップはすぐにでもEAの改善に役立つが、蒸留および責務の階層については、有望な考え方ながらもビジネス側の努力も必要となるため手軽には導入できなかった、とのことでした。

なお今回は紹介しませんが、同じくStatOil社の事例として、ERPなどの商用パッケージ製品の評価に「戦略的デザイン」パターンを適用した事例も紹介されています。こちらの事例では、コンテキストマップと責務の階層の組み合わせが、パッケージ製品の評価に不可欠な暗黙知の顕在化に役立ったと報告されています。

*4 この事例紹介は、2006年のOOPSLA(Object-Oriented Programming, Systems, Languages, and Applications、世界最大のオブジェクト指向国際会議)に論文として発表されたものです。なお、スカンジナビア地方(ノルウェー、スウェーデン、デンマーク)は特にオブジェクト指向が盛んらしく、Eric Evansが主催するDomain Language社の顧客にはこの地方の企業が多いそうです。

おわりに

以上で、DDDの全41パターンを紹介することができました。あの分厚いDDDの書籍が全体としてどんなことを伝えようとしていたのか、その全体観が読者の皆さんに理解していただけたなら、本連載の目的は達成です。

この紹介記事は、あくまでDDDの書籍から細部を省略して、全体像を概観したに過ぎません。小さな記事では紹介しきれなかった優れた思想やノウハウ、著者の実経験に基づいたリアルなプロジェクトの具体例が、書籍では豊かに盛り込まれています。本記事をきっかけに、今度はぜひ書籍にもチャレンジしてみてください。

そして、ぜひDDDを実践していきましょう。

top ページのトップへ戻る

記事の内容を5点満点で評価してください。
1点 2点 3点 4点 5点
記事に関するコメントがあれば併せてご記入ください。

© 2007 OGIS-RI Co., Ltd.
Prev Index
Prev. Index