ドメイン駆動設計(DDD)
何を解決する手法か
ドメイン駆動設計(DDD)は、業務(ドメイン)の言葉と構造を、そのままコードの構造にする設計手法です。
対象は「業務が複雑なソフトウェア」です。技術的に難しいのではなく、業務のルールが多くて絡み合っている種類の複雑さ — 保険の料率計算、在庫の引当、医療の予約制約 — に効きます。
逆に、CRUD が中心で業務ルールが薄いシステムには過剰です。DDDを持ち込むと、単なるデータ入出力に何層もの抽象が乗り、コード量だけが増えます。適用する前に「業務ルールが本当に複雑か」を確かめるのが最初の判断です。
ユビキタス言語
DDDの中心にあるのがユビキタス言語です。業務担当者・設計者・実装者が、同じ言葉を同じ意味で使うことを指します。
| 会話 | コード |
|---|---|
| 「注文を確定する」 | order.confirm() |
| 「引当できない在庫」 | UnallocatableStock |
| 「解約申込と解約成立は別」 | CancellationRequest と Cancellation |
翻訳が挟まると、そこで意味が落ちます。業務担当者が「引当」と呼ぶものを、コードで reserve と assign に分けて書いていたら、その差は誰も説明できません。 [[要件定義]] の段階から言葉を揃えることが、DDDの前提です。
境界づけられたコンテキスト
同じ言葉でも、部門が違えば意味が違うことがあります。
- 営業にとっての「顧客」= 商談の相手。担当者名と接触履歴を持つ
- 経理にとっての「顧客」= 請求先。締日と与信枠を持つ
これを1つの「顧客」クラスにまとめると、どちらの用途でも使いにくい肥大した型ができます。DDDでは意味が通じる範囲を区切り、その中でモデルを閉じます。この区切りが境界づけられたコンテキストです。
境界は [[マイクロサービス]] の分割単位の候補になります。ただし先にサービスを分けてはいけません — 境界の理解が浅いまま分割すると、後から跨る変更が頻発します。まずは同じアプリの中でモジュールとして分け、境界が安定してから物理的な分割を検討します。
戦術的な部品
コンテキストの内側では、次のような部品でモデルを表現します。
- エンティティ — 識別子で同一性が決まるもの(注文、顧客)。属性が変わっても同じもの
- 値オブジェクト — 値そのものが同一性(金額、住所)。不変にして扱う
- 集約 — 一貫性を保つ単位。「注文と注文明細」のように、まとめて更新されるべき塊
- リポジトリ — 集約の永続化の窓口([[リポジトリパターン]])
- ドメインサービス — どのエンティティにも属さない業務ルールの置き場
集約の境界がDDDで最も難しい判断です。 大きくすると同時更新で競合し、小さくすると整合性を自分で保つことになります。
段階的に取り入れる
全部を一度に導入する必要はありません。効き目の順に取り入れられます。
- ユビキタス言語 — 言葉を揃える。コード変更を伴わずに始められて効果が大きい
- 値オブジェクト — 金額や識別子を専用の型にする。[[リファクタリング]] として少しずつ入る
- 境界の切り出し — 意味が違う「顧客」を分ける
- 集約とリポジトリ — 永続化の形を整える
関連技術とのつながり
- [[要件定義]] — 業務の言葉を集める工程。ユビキタス言語はここから始まる
- [[マイクロサービス]] — 境界づけられたコンテキストが分割単位の候補になる
- [[デザインパターン]] — 戦術的な部品の実装で組み合わせる
- [[リファクタリング]] — 既存コードへ段階的に取り入れる手段
- [[リポジトリパターン]] — 集約の永続化を担う窓口
Q: DDDが効きやすいのはどんなシステム?
- [ ] 画面数が多いシステム
- [x] 業務のルールが多く絡み合っているシステム
- [ ] データ量が多いシステム
解説: 技術的な難しさではなく業務の複雑さに効きます。CRUD中心のシステムでは抽象だけが増えて過剰になります。
Q: ユビキタス言語の目的はどれ?
- [x] 業務担当者と実装者が同じ言葉を同じ意味で使い、翻訳による意味の欠落を防ぐ
- [ ] 英語で命名を統一すること
- [ ] 用語集を作って納品すること
解説: 会話とコードで言葉がずれると、その差を誰も説明できなくなります。
Q: 境界づけられたコンテキストを見つけたとき、最初にすべきことはどれ?
- [ ] すぐにマイクロサービスへ分割する
- [x] まず同じアプリ内でモジュールとして分け、境界が安定してから物理分割を検討する
- [ ] 1つのクラスに統合する
解説: 境界の理解が浅いまま分割すると、後からサービスを跨ぐ変更が頻発します。