エンタープライズギークス (Enterprise Geeks)

企業システムの企画・開発に携わる技術者集団のブログです。開発言語やフレームワークなどアプリケーション開発に関する各種情報を発信しています。ウルシステムズのエンジニア有志が運営しています。

DDD超入門(前編) - Domain-Driven Designの概要

今回から2回に分けて、Domain-Driven Design(ドメイン駆動設計。略してDDD)を紹介する。 DDDとは、Eric Evans氏が2000年代初頭から提唱しているソフトウェア設計手法で、機能中心ではなくドメイン(ビジネス上の関心領域)に設計の重心を置いたオブジェクト指向設計手法の1つである。
前編の今回はまずDDDの概要にふれ、次回は後編としてDDDの適用Stepについて簡単に紹介する。

DDDの前身

DDDは、Martin Fowler氏が以下の書籍『PoEAA(Patterns of Enterprise Application Architecture)』の中で分類している以下の3つのロジックパターンの内「ドメインモデル」の流れをくんでいる。

エンタープライズアプリケーションアーキテクチャパターン

エンタープライズアプリケーションアーキテクチャパターン

トランザクションスクリプト

シンプルな手続き型のパターン。1つのユーザーアクションの中に入力チェック、データのCRUD、計算処理、クライアントへの応答など一連の手続きをまとめて記述する。シンプルで一連の手続きごとに処理が完結するが、一方で機能間でロジックの重複が発生しやすい。

ドメインモデル

1つのユーザーアクションの中にすべてのロジックを持つのではなく、アプリケーションに登場する概念(例えば受注管理であれば、オーダー、顧客、商品、与信ポリシー、在庫、引当順位、倉庫、などの大小様々な概念)をもとにそれぞれオブジェクトとして切り出し、それらにロジックを配置するパターン。切り出したオブジェクト同士が協調して1つのユーザーアクションを担う。

テーブルモジュールモデル

トランザクションスクリプトドメインモデルの中間に位置するパターン。各データベーステーブルを中心にロジックを配置することで、機能間の重複をある程度抑制できて構造としても明快である。ただ、ロジックの配置場所に制約がある分だけドメインモデルほど精度の高いロジック構造は得られない。

DDDとは

上記のPoEAAの「ドメインモデル」の流れをさらに体系立てた設計手法がEric Evans氏のDDDにあたる。 Eric Evans氏は以下の著書の中でドメイン駆動設計について詳しく述べているが、600ページ近くのあるので、ここではエッセンスを絞って紹介する。

エリック・エヴァンスのドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計

まずDDDの根本的な原則について、Eric Evans氏が著書(日本語版)の序文で以下の3つを語っている。 ここでは少し抽象的な紹介となるが、具体例を交えた話は後編で紹介する。

1. コアドメインに集中すること

アプリケーションには、いくつかのドメイン*1が登場する。 大規模なシステムほど数多くのドメインが登場し、そのどれも必要不可欠であるが、その中でも中心的なドメインに対する理解を取り違えて設計すると、いかに技術的に優れたアプリケーションであっても、ユーザーの利用目的を果たさない無用の長物となってしまう。

また 「コアドメインに集中する」ということは、その前提として、サブドメインも含めたドメインの全体像を探求し、その中からコアとなるドメインを発見していくことになる。このドメインの全体像を探求するためのツールが、次項に登場するドメインモデル*2にあたる。

2. ドメインの実践者とソフトウェアの実践者による創造的な共同作業を通じて、モデルを探求すること

DDDの設計スタイルは、ドメインエキスパート*3とソフトウェア開発者が一緒になってドメインモデルを洗練させ、そこで獲得したドメインの知識をソースコードに反映していくスタイルである。

ドメインエキスパートとソフトウェア開発者は完全分業の関係では決してなく、互いに理解の齟齬がないように二人三脚で設計を深めていく関係である。 ドメインエキスパートとソフトウェア開発者が協業してドメインモデルを描くには、当然お互いの専門性を超えて理解し合わなければならず、そこには自ずと共通の言葉が必要となる。 その言葉が、次項のユビキタス言語*4にあたる。

3. 明示的な境界づけられたコンテキストの内部で、ユビキタス言語を語ること

ドメインエキスパートとソフトウェア開発者はユビキタス言語を共通言語としてドメインモデルを深化させていくが、一方で同時にモデルの適用範囲を明確に境界づける必要がある。 DDDはドメイン全部入りの巨大でモノリシックなモデルを標榜するわけではなく、むしろ、コンテキスト*5が異なる領域は分割統治する姿勢である。 あるコンテキスト内で有効なユビキタス言語が他のコンテキストでも同一解釈という保証はなく、逆に混乱をきたしバグの温床となる。 モデルやユビキタス言語の有効範囲を認識して明示的に境界をつけることで、そのコンテキスト内でのモデルの統一性を保つ。

以上が、Eric Evans氏が挙げているDDDの根本的な原則である。

強引だが要約すると、

「DDDは、ドメインモデルを中心にドメインエキスパートとソフトウェア開発者がユビキタス言語を使ってお互いに理解を深めながら、ドメインの知識をプログラムに忠実に反映していく設計の仕方」と言える。

もちろん、この要約だけではDDDの説明として十分ではなくDDDの一部分でしかないが、DDDがドメインを中心とした設計スタイルであることは垣間見える。

では、このDDDがどういった場面で有効かを次節で見ていく。

なぜDDDか?

DDDの目的は大きく分けて2つの側面を持っている。 1つは前節のDDDの原則でふれたような「コミュニケーションとしてのDDD」で、もう1つは冒頭のPoEAAでふれたような「デザインパターンとしてのDDD」である。

そして、どちらにも共通しているモチベーションがEric Evans氏の著書の副題にある「ソフトウェアの複雑さに立ち向かう」ことである。

コミュニケーションとしてのDDD

前節で紹介したように、DDDはその名の通りドメインにこだわっている。 その理由は、ソフトウェアの複雑性は本質的にドメインの複雑性に起因しているからである。 ソフトウェアを制するには、ドメインを制する必要がある。

複雑なドメインをソフトウェアとして確実に表現するには、ソフトウェア開発者だけでは不可能で、必ずドメインエキスパートの力が必要となる。 そして、そのドメインエキスパートと協業としていくためにはユビキタス言語やドメインモデルといった、お互いの理解を確認し合えるコミュニケーションツールが必要となる。

ドメインエキスパートの価値ある知識を引き出し、それをソフトウェアの表現へとつなぐ懸け橋しとしてDDDの設計スタイルは有効な手段となりえる。

ただ残念ながら、ドメインエキスパートと開発者が物理的または組織的に離れた場所に居て、コミュニケーションや会話を直接取りづらいプロジェクト環境の場合は、実践が難しいだろう。

デザインパターンとしてのDDD

クラス構成について正直に言えば、DDDを採用せずとも機能一覧またはユースケース一覧をもとにコントローラー(Controller)を洗い出して、それらに対してCRUDの実装を割り当てればアプリケーションとしては立派に成立する。もちろん、これをちゃんと実現するだけでも相当に大変な仕事である。

これは、冒頭のPoEAAで言うところの「トランザクションスクリプト」に該当するわけだが、ロジックを各コントローラー(または、コントローラーに従属するクラス)に収める「個別完結型」のシンプルなスタイルである。一方で機能や複雑度が増すにつれて各コントローラーごとに似たようなロジックが重複しやすい。 新しく機能を追加するするたびに似たようなロジックを再度組んだり、ロジック変更が入ると各コントローラーを横断的に改修をしないといけない。 複雑度があがるにつれてロジックが散在しやすく、デメリットが顕著になる。

それに対してDDDでは、ドメインそのものが持つ大小様々な概念とロジックをそのままオブジェクトとして切り出し、切り出したドメインのオブジェクトを調整する薄いコントローラー(DDDではアプリケーションサービスと呼ぶ)を配置することで、アプリケーションを成立させようとする。 コントローラーは、ドメインのオブジェクトを必要に応じて組み合わせながら機能を実現する「組み合わせ型」のスタイルである。 この設計の場合、各ドメインのロジックを再利用しやすく、DRY*6の原則にも従いやすい。 加えてドメインエキスパートの知識像を保ったままソフトウェアとして組み立てることができる。仮にドメインエキスパートの知識像が複雑なものであっても、それに追随した近しい表現で組み立てることができる。 一方で、オブジェクト同士の適切な配置や相互作用を見極めるのが難しく軌道に乗るまで時間がかかる。

DDDのトレードオフ

DDD採用の是非は、ここまで見てきたDDDのメリット・デメリットを踏まえた上で判断すべきである。

利用期間が決まっている短命のシステムの場合は、シンプルにトランザクションスクリプトで作ってしまった方が立ち上がりも早い。 逆に基幹システムのように寿命が長く、複雑度が本質的に高いシステムの場合は、稼動後の長い運用過程においても、機能追加は何度も発生して複雑度が増し、ビジネス変化によりロジック変更も度々行われる。このような場合は、DDDで構築して将来発生する機能追加、ビジネス変化、複雑性の増加に備えておく方がよい。

参考までに、以下にPoEAAに記載されている各パターン別の複雑度と労力のグラフを紹介しておく。 トランザクションスクリプトでは、複雑さが増すにつれて労力が指数的に増している一方で、 ドメインモデルの方は、複雑さと拮抗するかのように労力が線形増加を保っている。

f:id:rxyt:20160412202103p:plain

Martin Fowler著: Patterns of Enterprise Application Architecture より引用

以上ここまでの流れを整理すると、 ドメインエキスパートの知識を引き出すための「コミュニケーションとしてのDDD」と、引き出した知識の意味を失うことなくソフトウェアとして組み立てる「デザインパターンとしてのDDD」を武器にソフトウェアの複雑さに立ち向かっていくことが、DDDの言わんとするところと考える。

後編ではDDDの適用Stepについて見ていく。

[田上 悠樹]

*1:ビジネス上の関心領域

*2:ドメインに登場する概念と概念同士の関係性を図示したドメインの知識像。後編に具体例を紹介する。

*3:そのドメインに対して深い知識・造詣を有している人物を言う。 ドメインエキスパートは必ずしもソフトウェアの設計や開発に精通している人物ではなく、むしろ非エンジニアであることが多い。

*4:ドメインエキスパートとソフトウェア開発者が互いに意思疎通するために使う共通言語。 この言語はドメインモデルに基づき、チームで行う作業のいたるところ(チームの会話、設計、モデリング、実装)で利用する。

*5:単一のモデルやユビキタス言語圏が適用できる範囲

*6:Don't Repeat Yourself、重複の排除