Software Design2月号で特集されていたドメイン駆動設計入門を読んだ時のメモです。
きっかけ
直近のタスクで作ったコードの設計がなんとなくいまいちで、どうすればもっとよくできていたのか悩んでいました。 また少し読んでいたGoの本で出てきたAPIのリポジトリ構成の設計思想がクリーンアーキテクチャやDDDがベースになっているもので、この辺り理解を深めたいなと思っていました。 そんな折にたまたま雑誌を見つけたので買って読んでみた次第です。
ざっくりとした感想
ちゃんと学びたいのであれば本当は原点の本にあたるべきなのですが、分厚く内容も古いため、雑誌の方が効率よく概要を把握できたような気がします。 特に本では説明されていない、クリーンアーキテクチャのような他の設計との関係性など、実用的な追記されているのが良いところでした。
前半1~3章(概要・ドメインモデルの作り方・分散アーキテクチャの設計パターン)まではよかったのですが、4章(開発事例)に関しては説明が腑に落ちなかったり、事例に結果が伴っていなかったりと物足りなさは感じました。 とはいえ前半3章だけでも十分に読む価値はありました。
思想みたいなものは大分把握できたと思うのですが、実業務にうまいこと導入するところに関してはまだイメージが湧かないので、もう少しいろんな他社事例を見てみれたらと思います。
余談ですが、分散アーキテクチャの章で紹介されていた書籍「ソフトウェアアーキテクチャ ノードパーツ」読みたい。
内容
主に復習&自分が思い出す用。第4章は割愛し、第5章(用語まとめ)は織り交ぜて要所要所に混ぜ込んだ。
第1章. ドメイン駆動設計とは
根本の考え方について説明されている章。原点本の内容ベースだが、それにアプリケーション開発・オブジェクト指向・アジャイル開発と絡めた説明を筆者が追記している。
- 前提としている考え方
- 事業の存続と発展
- それには、成長と変化するソフトウェアが必要になる
- それを実現するためには、複雑な業務ロジックに焦点を当てる必要がある
- そのためにドメインモデルを使う
- ドメイン
- なんらかのルールに基づいて管理されている範囲
- ソフトウェアが対象とする領域
- ドメイン駆動設計は、ソフトウェアV字モデルの最上位と最深部を強く関連づけることを目標とし、事業活動が発展し、変化を繰り返しながら存続していくことに貢献することを目指している
- ドメインモデル
- 事業の要点を抜き出してわかりやすくしたもの
- 活用方法として以下がある
- 業務知識の理解を深める
- 用語がバラバラになる問題に対し、同じ言葉で開発できるようにする
知識豊富な設計
- 重要な業務ルールを見極め、関係性を整理するためにドメインモデルを作っていくこと
深いモデル
- 見落としに気付けたり、暗黙的な枠組みを明示的に表現できるようになったドメインモデル
- これら二つは目指す方向性の認識合わせに必要
- モデルと実装を結びつけるためのパターン
- 3層構造
- ポート&アダプター
- クリーンアーキテクチャ
- 3は完成コストが高く、それを簡略化したものが1や2という見方もある。上記3つの基本原則は同じ
- 分離方法
- 業務ロジックとそれ以外のクラスを分離する
- 業務ロジックを表現するクラスだけを、ドメインモデルに置く
- 必要であれば両方を合成するクラスを作る(これはドメインモデルの外に置く)
- これらが混在することはよくあるので、都度リファクタリングをしていく
第2章. ドメインモデルを理解しよう
ドメイン駆動設計の中心となるドメインクラス設計のやり方について、原点本にも出てくる貨物運搬の予約フローを例にモデルに落とし込むやり方が解説されている。
- 業務ロジックを記述する方法3つ
- トランザクションスクリプト
- 入出力手順中心
- ▲同じ計算が異なるトランザクションスクリプトに点在。関連する業務ルールが点在しがちになる。複雑なルールの記載は難しい
- ドメインモデル
- 業務ロジックとデータ参照を分ける
- このデータ参照部分をアプリケーションクラス・ユースケースクラスと言ったりする
- テーブルモジュール
- CRUDの中に必要に応じて業務ロジックを埋め込む
- ▲複数のテーブルをまたぐロジックは埋め込めない
- トランザクションスクリプト
- 事業活動のモデルを作る観点として、以下3つがある
- 観点
- プロセス
- フロー図やumlのアクティビティ図に起こす
- この図ではルールの存在を明示できない
- データ
- よくあるのは、イベントとリソースに分けてモデリングするやり方
- ルール
- 業務ルールを表現する概念をクラスで表現しながら、業務ルールに基づく計算判断のロジックの置き場所としてメソッドを作る
- プロセス
- 観点
- モデル設計の構成要素
- エンティティ
- 個別に認識できる実態。管理番号を持つ何か。クラスの有力候補
- 業務ルールを見つける方法として、エンティティを「イベント」「短命なリソース」「長命なリソース」に分けるやり方がある
- イベントには2種類のルールが関連する
- イベント発生に関するルール(許可・禁止)
- 行動ルール(記録・通知など)
- イベントには2種類のルールが関連する
- 値オブジェクト
- 業務ルールに基づく計算判断に使う属性を発勁んし、クラスとして表現するパターン
- 値オブジェクトに注目することで、値を使う業務ルールが見つかる
- コレクションオブジェクト
- 配列・集合・写像などインスタンス変数としてもち、それを使う操作ロジックを同じクラスに集める
- 区分オブジェクト
- 場合分けを整理するのに使う。Enumで表現されるような
- モジュール
- エンティティやオブジェクトなど、数あるクラスをわかりやすく整理するパターン。パッケージや名前空間となる
- エンティティ
第3章. 分散アーキテクチャとドメイン駆動設計
分散アーキテクチャとドメイン駆動設計がどう絡むかを、原点本ベースにした内容が紹介されている。
- 単一モデル
- 従来のソフトウェア設計では、事業活動全体をこれで考えていた。しかしそれによって全体の構造が固定され、柔軟性や発展性が失われていった
- 分散モデル
- 自立して活動する複数の構成要素が動的につながって、ネットワークを構成している
- ドメイン駆動設計が提供する分散アーキテクチャのモデルには、以下の3パターンがある
- 境界づけられたコンテキスト
- 1つのドメインが対象とする範囲を限定するアプローチ
- これによって、業務の目的や関心事が異なる領域を切り分ける。ユビキタス言語の適用範囲になる
- コンテキスト(文脈):言葉の意味は文章の前後によって決まる。ドメインモデルを作るときは言葉の意味が同じになる範囲を切り分ける、が発想元
- 必ずしも分散アーキテクチャの範囲となるわけではない
- コンテキストマップ
- 1の中だけで意味を持つ複数のドメインモデルをどう繋げるかを検討するパターン
- コアドメイン
- 2が増えた時に、複雑な全体の中で中核になる要素に焦点を合わせ、全体に秩序を生み出す
- 境界づけられたコンテキスト
- マイクロサービス化する際に考えなければいけないこと
- サービス間の繋ぎ方
- 通信はDBに比べて遅く不安定なので、検知やリトライの仕組みが必要になる
- データの共有
- 同じデータを参照する仕組みのやり方色々
- 必要な情報を都度問い合わせる
- 共有のためのサービスを作る
- 情報を複製(キャッシュ)する
- 同じデータを参照する仕組みのやり方色々
- サービス間の繋ぎ方
- コンテキストマップを複雑にする要因はチーム間の関係性
- 関係性のパターン
- 対等
- パートナーシップ
- 共有カーネル
- 偏りがある
- 顧客と供給者
- 順応者
- 腐敗防止層
- 公開ホストサービス
- 断絶した関係
- 対等
- サービス間調整のやり方
- API仕様の公開
- テスト仕様の公開
- 仕様を一種の契約と見做して、双方が満たすことに責任を持つ
- テスト環境の提供
- 提供側の負担は大きいが、問題の早期発見につながる
- 関係性のパターン
- コアドメインに集中する
- 事業領域の全体にドメイン駆動設計のやり方を適用するのは、現実的ではないので、集中すべきところを絞る
- 集中すべきところ
- 業務プロセスやルールが複雑な箇所
- 独自性のある箇所
- コアドメイン以外の対処法
- 既製品を使う。契約管理など
- イージーオーダー
- フルオーダー
進化する秩序
- コンテキストやつなぎ方は日々進化していくため、秩序を整えていく必要がある
責務のレイヤー
- 上記を実現する手段の一つ。1つのドメインの中でパッケージの役割を分類し、パッケージ間の依存関係を整理する
- ドメインモデルを中核としたアプリケーションを動かすパターン
- ユースケース(アプリケーション)
- アプリケーションが必要とする計算判断を「集約」が提供するが、それを使って計算判断を実行する役割のクラス
- ファクトリー
- 複雑な集約を生成する役割のクラス
- リポジトリ
- ユースケースが記録や参照に使う役割のクラス
- ユースケース(アプリケーション)