ドメイン駆動設計(エヴァンス本)の要点
ドメイン駆動設計の要点
第1章 知識をかみ砕く
用語の説明
- モデル … 知識の表現手法
- ドメインモデル … 知識を抽象化した「考え方」
3行まとめ
- ドメインエキスパート(業務の専門家)との会話を通してドメインを理解する
- 抽象化・モデル化を経て、何度も会話を重ねてドメインのコア部分を理解する
- 繰り返し行い、不要な情報を削除し、モデルを洗練させる(蒸留する)
第2章 コミュニケーションと言語の使い方
用語の説明
- ユビキタス言語 … 業務とソフトウェアを紐付けるためにチーム全体で利用する共通言語
- ドキュメント … モデルの概念を説明、またはコードを補足するための資料、最新状態を保つこと
3行まとめ
- チーム全体で利用する用語集(ユビキタス言語)を作成する
- ドキュメントはユビキタス言語を使って、まず自然言語で書き、その上でシンプルな図(UMLやフロー図など)で補足する
- モデルはドメインの教材、設計の補足、コンテキストの説明などに用いることができるが、目的別に作成してはならない(Singleton)
第3章 モデルと実装を結びつける
用語
- モデル駆動設計 … モデルとコードを緊密に結びつけることでコードに意味を与える設計手法(DDDの本質)
- 分析モデル … ドメインの分析のためだけに作られるモデルのこと、アンチパターン
3行まとめ
- モデルはドメインの分析 → モデリング → 設計の土台 → コードへのアプローチとすべての工程において役にたつ
- 責任を過剰に分離すると情報が劣化し、せっかくつくったモデルが陳腐化する(とくにモデリングとプログラミングは切り離さない)
- ユビキタス言語がモデルと実装を結びつける土台となる
第4章 ドメインを隔離する
用語
- レイヤードアーキテクチャ … Presentation/ Application / Domain / Infrastructure と責務ごとにレイヤーを分ける
- プレゼンテーション層(UI) … 情報の表示、入力の解釈
- アプリケーション層 … 他レイヤーと相互作用するもので薄く保つ
- ドメイン層 … モデルが表現されるレイヤー(ビジネスルールを表現する)
- インフラストラクチャ層 … データの永続化、メッセージの送信など
- 利口なUI(Smart UI) … Presentation層 にビジネスロジックを実装してしまうアンチパターン(現在の cloud-cpanel)
3行まとめ
- ドメイン駆動設計の肝は「ドメイン層」を隔離すること。隔離されていれば他はどんなレイヤーでも問題ない
- レイヤードアーキテクチャを採用する際、各レイヤーは凝集度を高め、下位レイヤーにだけ依存する(Clean Architecture を参照)
- DDDが最も効果を発揮するのは大規模プロジェクトで、熟練の開発者がいるとき(DDDの習熟には時間がかかるため)
第5章 ソフトウェアで表現されたモデル
用語
- エンティティ(Entities) … 別名:参照オブジェクト、詳細は3行まとめ参照
- 値オブジェクト(Value Objects) … 詳細は3行まとめ参照
- サービス(Services) … 詳細は3行まとめ参照
- モジュール(Modules) … 別名: パッケージ、詳細は3行まとめ参照
- 関連 … オブジェクト同士の関係を表現したもの、一対* にすることで設計が用意になる
- モデリングパラダイム … モデルを表現するためのパラダイム、オブジェクト指向が主流
エンティティ 3行まとめ
- システム内で連続性、一貫性を持ったユニークなモデル
- 同一性を表す何か、ふるまい、そのふるまいが必要とする属性を持つ
- コア部分を別エンティティに切り出せないか考え、ときには値オブジェクトになる可能性もある
値オブジェクト 3行まとめ
- 何らかの状態を表現する不変な属性、またはその属性を表現させる機能(可変にする場合はいろんな条件がある)
- 同一性は与えず、エンティティを維持するための複雑な設計は避ける
- 値オブジェクト同士の双方向の関連を完全に取り除き、シンプルな形を保つ
サービス 3行まとめ
- 概念的にどのオブジェクト(エンティティ、値オブジェクト)にも属さない操作をまとめたオブジェクト
- ユビキタス言語を用い、動詞で命名される
- シンプルなインターフェースだけを提供する
モジュール 3行まとめ
- 高凝集・低結合でコードだけでなく概念でまとめたもの(別名: パッケージ)
- モジュール名にはユビキタス言語の一部をつけ、import文に意味をもたせる
- クラスに比べ、リファクタリングが難しく影響範囲が広くなるが、歯を食いしばってモデルと一緒に進化させる
第6章 ドメインオブジェクトのライフサイクル
用語
- ライフサイクル … オブジェクトの生成から保存、削除までの一連の流れ
- 集約(Aggregates) … 3行まとめ参照
- ルートエンティティ … システム全体で同一性を持ち、不変条件の責任を持つオブジェクト
- 境界 … 集約内部に何があるか定義するもの
- 不変条件 … 集約のデータが変更されるときに守る一貫性のルール
- ファクトリ(Factories) … 3行まとめ参照
- リポジトリ(Repositories) … 3行まとめ参照
- ドメインモデル貧血症 … https://bliki-ja.github.io/AnemicDomainModel/
集約 3行まとめ
- 複数の関連するオブジェクトをひとまとめにしてライフサイクルを通じて整合性を維持するために使われるもの
- 境界内ではエンティティ(ルートではない)、値オブジェクトを持つことができる
- 集約を削除するときはルートエンティティだけでなく、境界内部のものすべてをまとめて削除する
ファクトリ 3行まとめ
- 複雑化したオブジェクトや集約の生成処理を隠蔽し、単純なインターフェースだけを提供するもの
- 生成メソッドはアトミックで、かつ集約の不変条件を強制する
- 生成が複雑でない(他のクラスのコンストラクタを呼び出さない、パラメータが少ない)場合はコンストラクタで代用可能
リポジトリ 3行まとめ
- オブジェクトの取得、追加、変更、削除のメソッドを提供し、実際の永続化処理などは隠蔽するもの
- ただし、トランザクション制御(コミットタイミングなど)はクライアントに委ねる
- オブジェクトのコレクションがメモリ上にあると錯覚させるための仕組み(Fluxアーキテクチャの Store層 に近い)
第7章 言語を使用する:応用編
ある仕様に対してモデリングを行っていく章なので、特にまとめなし
第8章 ブレイクスルー
用語
- 深いモデル … ドメインの表層的な部分から掘り下げた結果得られるモデル
- ブレイクスルー … 小さな改良を続けた結果に起きるシステム全体に好影響を及ぼすほどの気付き
- (DDDにおける)リファクタリング … ドメインエキスパートとともに学び、ドメインの新たな洞察や動機をモデルに組み込むこと
- しなやかな設計 … 第10章参照
3行まとめ
- 地道な作業(知識を噛み砕く、ユビキタス言語を育てる、ドメインの概念を探求する、しなやかな設計に改良する、モデルを蒸留する)をした先にブレイクスルーが訪れる
- リファクタリングはドメインエキスパートとともに学ぶイテレーティブなプロセス
- 身動きがとれなくなる前に改良を行う
第9章 暗黙的な概念を明示的にする
用語
- 暗黙的な概念 … モデルに表現されていない概念
- 制約 … なんらかの処理に対する条件、またはその条件に名前をつけたもの
- 仕様 … 制約を抽出し、明示的に値オブジェクトとして表現するパターン(ドメイン層に置く)
3行まとめ
- 設計やドメインエキスパートの発言の違和感やぎこちなさを精査し、暗黙的な概念を見つけ出しモデル化する
- 条件(if文の中身など)や手続き型の処理に名前をつけ、明示的に値オブジェクトとして表現することで議論しやすくなる
- 新しいオブジェクトや集合が仕様を満たすように作成したいなら、仕様の代わりにジェネレータを使うとより柔軟に設計できる(かもよ)
第10章 しなやかな設計
用語
- しなやかな設計 … 暗黙的な概念を掘り出し、簡潔かつ明確にとらえモデルを育てること
- 意図の明白なインターフェース(Intention-Revealing Interfaces)… ユビキタス言語を用い、効果と目的がわかるインターフェースをつくること
- 副作用のない関数(Side-Effect-Free Functions)
- 副作用 … システムの状態に対して与えられるあらゆる影響のこと
- コマンド … 何らかの変更を与える操作
- クエリ … 情報取得など変更を与えない操作
- コマンドクエリ責務分離 (CQRSパターン) … コマンドとクエリは明確に分けること
- 表明(Assertions)
- 契約による設計(Design by Contract) … 事前条件、不変条件、事後条件を明示する設計手法
- Assertion が使えないプログラミング言語ではユニットテストでカバーする
- 契約による設計(Design by Contract) … 事前条件、不変条件、事後条件を明示する設計手法
- 概念の輪郭(Conceptual Contours) … 設計要素を凝集した単位に分割することで見えてくるモノ(高凝集)
- 独立したクラス(Standalone Classes) … 依存関係をできる限り排除し、自己完結型にしたクラスのこと(低結合)
- 閉じた操作(Closure of Operations) … 引数と戻り値をできる限り同じ型にすること
- 宣言的な設計(Declarative Design) … DSLなどを使い、モデルの特徴を宣言することで動作するプログラムを作ろうとすること
3行まとめ
- ソフトウェア設計がダメダメだと、処理結果を予測できない、整理できない、バグが発生する、開発者の負担が大きくなる
- 意図の明白なインターフェース、副作用のない関数、表明などを用いることで設計にしなやかさを持たせる
- 英文を書いてるかのようにプログラムを書く(宣言的スタイル)
第11章 アナリシスパターンを適用する
用語
- アナリシスパターン … マーチン・ファウラーの著書、またはモデリングをする際のヒントとなる概念
3行まとめ
- モデリングを支援する考え方
- すでに実用化された(業界で使われている)パターンがあるなら、それをモデリングのヒントにする
- 業界に定着したユビキタス言語があるなら独自にカスタマイズしない
第12章 デザインパターンをモデルに関係づける
用語
- ストラテジーパターン(Strategy、別名:ポリシー) … ルールとルールのふるまいを切り離し、置き換え可能にするパターン
- ※GoF と DDD の文脈において若干の違いがある
- コンポジット(Composite) … 再帰的なデータ構造(木構造)を表現するパターン
- フライウェイトパターン(Flyweight) … すでに生成されているインスタンスを使い回すパターン
- cf. シングルトン(Singleton) … 唯一無二のインスタンスを生成するためのパターン(Flyweightとはアプローチの仕方が異なる)
- ※詳細は GoF のデザインパターン参照
3行まとめ
- 具体的な実装方法やパターンの適用方法は GoF のデザインパターンを参照したほうがわかりやすい
- DDDにおけるストラテジーパターンは、プロセスの中にあるポリシーやルールなどの概念を明示的に表現することにフォーカスしている
- フライウェイトはドメインモデルにおいて一致するものがないデザインパターンで、無理やり適用させることもできるけどコンポジットのほうが扱いやすい
第13章 より深い洞察へ向かうリファクタリング
用語
- (特になし)
3行まとめ
- 物事を多角的に見る、ドメインエキスパートとの対話を継続することでより深くドメインを知ることができる
- 少人数の機動的なチームで、課題を小さく抜き出し、柔軟に議論を重ねる
- 先延ばしにすると変更が難しくなるので、最新のドメインとの乖離や埋もれた概念を見つけたときがリファクタリングをするタイミング
第14章 モデルの整合性を維持する
DDD本の中で一番ページ数を割いている章、一言でいうと「大規模プロジェクトを推進するための戦略・戦術指南」な章
用語
- 境界づけられたコンテキスト(Bounded Context) … チーム編成、物理などによってモデルの概念やルール、ユビキタス言語が異なる場合に境界線を引くことでできた独立したコンテキストのこと
- 重複した概念 … 同じ概念を表現しているモデルが2つ以上あること → 統合対象
- 偽同族語 … 同じ用語、用途だけど異なる概念 → 分離しておく(DRY原則注意)
- 継続的な統合(Continuous Integration) … 多チーム・人数で開発するときにモデル概念や実装をマージすること(本書では一般的なCI/CDの文脈より大きな範囲を扱っている気がする)
- エクストリームプログラミング … 同名の書籍で語られている開発プロセス
- コンテキストマップ … 境界づけられたコンテキストにユビキタス言語から名前をつけ作成した相関図
- モデルコンテキスト戦略
- 共有カーネル(Shared Kernel) … チーム間の合意の上でドメインモデル(コードやDB設計も含む)を共有する
- 顧客/供給者の開発チーム(Customer/Supplier Development Team) … 上流システム(供給者)と下流システム(顧客、ユーザーの代表)として関係を確立し、開発を行う
- 順応者(Conformist) … 顧客/供給者の協力関係がうまく行かないときに、下流が上流にあわせて(順応して)開発を行う
- 腐敗防止層(Anti-Corruption Layer) … ファサード・アダプターパターンや変換サービスを用いシステム間でセマンティクスを変換を責務とするレイヤー
- 別々の道(Separate Ways) … 統合のコスパが悪いときに境界づけられたコンテキストを独立させて小さいスコープ内だけで開発を行う
- 公開ホストサービス(Open Host Service) … 腐敗防止層だけでは難しいときにどのサービスからでも使えるサービスの集合として定義する
- 公表された言語(Published Language) … 明確にドキュメント化された共通言語(XMLやJSONなど)を用いデータ交換用として使う言語
境界づけられたコンテキスト 3行まとめ
- エンタープライズシステムは影響範囲が大きく、チーム間調整で鈍化し、モデルが複雑化して扱いづらくなる
- チーム編成や物理的な制約、特定モデルで解決できる範囲ごとにコンテキストを分割し、その間に境界線を引く
- 境界内では一貫したモデル・ユビキタス言語を扱う
継続的な統合 3行まとめ
- 同一コンテキスト内の話
- モデルを改善していく過程で同じ概念が見つかったら統合し、ユビキタス言語を更新する
- 再生可能なマージ・ビルドテクニック、自動化されたテストスイートを用いる(よくあるCIテクニック)
コンテキストマップ 3行まとめ
- 境界づけられたコンテキストにユビキタス言語から名前をつけ相関図を作成する
- コンテキスト間のコードの再利用は危険なため、適切なインターフェースを設計しやりとりを行う
- コンテキスト間のやりとりの戦略を決める
第15章 蒸留
用語
- 蒸留 … 複雑で混ざりあったコンポーネントを分離するプロセス
- コアドメイン … モデルと設計における最も重要なポイント
- 蒸留テクニック
- 汎用サブドメイン … コアではないがシステムに欠かせないドメイン、ドメイン用のライブラリ
- ドメインビジョン声明文(Domain Vision Statement) … アプリケーションがもたらす具体的な価値を示すためのもの(具体的な話ではなく、ドメインモデルがどのように動き、価値を生み出すかを表現した抽象的なもの)
- 強調されたコア(Highlighted Core)
- 蒸留ドキュメント … コアドメインとコアを構成する主要な相互作用を記述したもの ≠ 設計ドキュメント
- コアにフラグを立てる … 膨大な資料の中からコアドメインになりそうな部分にアタリを付けること
- 凝集されたメカニズム(Cohesive Mechanisms) … ライブラリやパッケージのようなもので、ドメインは表現しない
- 隔離されたコア(Segregated Core) … コアとそれ以外を分離し、コアを高凝集・疎結合にする
- 抽象化されたコア(Abstract Core) … モデルの根本的な概念を別クラスや抽象クラス、インターフェースとしてくくりだすこと
3行まとめ
- アプリケーションに最も重要なコアドメインを見つける
- コアドメインは複雑になりやすく、また情報量が多く理解もしづらいため、蒸留をして不要な部分を削ぎ落とす
- リファクタリングを継続し、コアドメインを隔離する
第16章 大規模な構造
用語
- 進化する秩序(Evolving Order) … 制約(アーキテクチャ)と開発のバランスをとり、もとの制約に固執しすぎないで進化させること
- システムのメタファ(System Metaphor) … わかりづらいシステムをメタファによって説明すること(例: ネットワーク脅威保護 → 防火壁 → ファイアウォール)
- 責務のレイヤー(Responsibility Layers) … 責務ごとにレイヤーを分ける(成功している例: レイヤードアーキテクチャ)
- 知識レベル(Knowledge Level) … 要件に対し、設定可能なふるまいで対応する
- POSA の リフレクションパターン(Pattern-Oriented Software Architecture) … システムの構造とふるまいを動的に変更するメカニズム
- 着脱可能コンポーネントのフレームワーク(Pluggable Component Framework) … 抽象化されたコアのインターフェースを使って、多様な実装に置換できるようにすること
3行まとめ
- 大規模なシステムは理解しづらいので、ルールや役割、関係性をパターン化し、システム全体に適用する
- パターンを利用することで詳細をしらなくても全体像を理解できる
- 制約(ルール、役割、パターンなど)は大規模システム開発に必須だが、開発を妨げないように進化を続けなければならない
第17章 戦略をまとめ上げる
3行まとめ
- 大規模システムを開発するにあたり、戦略的設計の基本原則(コンテキスト、蒸留、大規模な構造)を適用する
- アーキテクチャよりもコアドメインが重要なため、優秀なエンジニアはドメインに集中してもらう(アーキテクトチームで無駄遣いしてはならない)
- 戦略的設計はミニマリズムと謙虚さが必要なので、すべてを適用せず必要なものだけ順次利用する