実装中の問いから引く
DDD実装ガイドライン
Entity、Value Object、Aggregate、Repositoryなど、DDDの実装中に迷いやすい判断を、推奨・判断基準・例外・Good / Bad Exampleで確認できます。
このガイドラインの使い方
上から順に学ぶ章立てではありません。いま迷っている問いを目次から選び、まず「推奨」と「判断基準」を確認してください。例外は、推奨から外れる根拠をチームで説明するときに使います。
Rule 01
Entityはいつ作る?
推奨
属性ではなく同一性で追跡し、時間とともに状態が変わる対象をEntityにする。
なぜ
値が変わっても同じ対象として扱う必要がある場合、識別子とライフサイクルをモデルに明示する必要があります。
判断基準
- 履歴や状態遷移を追う
- 同じ属性でも別物として区別する
- 業務上の識別子が会話に現れる
BAD
表示用の都道府県一覧の各項目に、将来使うかもしれないという理由だけでEntity IDを付ける。
GOOD
注文は配送先が変わっても同じ注文IDの注文として追跡する。
Rule 02
Value Objectにすべき基準は?
推奨
値の組み合わせで意味と等価性が決まり、独立したライフサイクルを持たない概念をValue Objectにする。
なぜ
検証と振る舞いを値の型へ閉じ込めると、不正な値や単位の取り違えを境界で防げます。
判断基準
- 構成する値が同じなら交換可能
- 生成後は不変にできる
- 金額・期間・住所など固有のルールがある
BAD
価格をnumber、通貨をstringとして別々に引き回し、各呼び出し元で検証する。
GOOD
Moneyが金額と通貨を保持し、異なる通貨同士の加算を拒否する。
Rule 03
Aggregate Rootとは何か?
推奨
Aggregateの不変条件を守る唯一の入口となるEntityをAggregate Rootにする。
なぜ
外部からの変更経路を一つに絞ることで、内部の複数オブジェクトにまたがるルールを常に検証できます。
判断基準
- 外部からIDで参照される
- 内部Entityの生成・変更を調整する
- トランザクション整合性の境界になる
BAD
呼び出し側がorder.linesへ直接pushし、検証を迂回できる。
GOOD
Order.addLine()が重複商品や数量上限を検証してOrderLineを追加する。
Rule 04
Aggregateの外から内部Entityを変更していい?
推奨
内部Entityの変更はAggregate Rootが公開する意図のある操作を経由する。
なぜ
内部Entityだけを見て変更すると、Aggregate全体で守るべき不変条件が破られる可能性があります。
判断基準
- setterではなく業務上の操作名を使う
- 変更前にAggregate全体の条件を検証する
- 内部コレクションを可変で公開しない
BAD
order.getLines()[0].quantity = 100 のように内部状態を直接書き換える。
GOOD
order.changeQuantity(lineId, quantity)で対象行と注文上限を同時に検証する。
Rule 05
RepositoryはAggregateごとに作る?
推奨
永続化が必要なAggregate RootごとにRepositoryを用意し、内部Entity用のRepositoryは作らない。
なぜ
取得と保存の単位を整合性境界と揃えると、Aggregateを部分的に更新して不変条件を壊す経路を減らせます。
判断基準
- 保存対象はAggregate Root
- ドメインで必要な取得操作だけを定義する
- テーブル単位のCRUDにしない
BAD
すべてのDBテーブルに同じCRUD Repositoryを機械的に生成する。
GOOD
OrderRepositoryがOrderを取得・保存し、OrderLineRepositoryは作らない。
Rule 06
Repository interfaceはどこに置く?
推奨
Repositoryの抽象は利用側であるドメインまたはアプリケーション側に置き、DB実装をInfrastructure側に置く。
なぜ
ドメインのユースケースがデータベースやORMへ依存せず、必要な取得能力を自分の言葉で定義できます。
判断基準
- メソッド名がドメインの語彙になっている
- ORM型を公開しない
- 実装詳細への依存が内向きに入り込まない
BAD
domainがORMのBaseRepositoryやQueryBuilderを直接importする。
GOOD
applicationのPlaceOrderが要求するOrderRepositoryをdomain側で定義し、SqlOrderRepositoryが実装する。
Rule 07
Domain Serviceはいつ使う?
推奨
重要なドメイン操作が一つのEntityやValue Objectに自然に属さない場合に限って使う。
なぜ
無理に一つのEntityへ置くより意味が明確になりますが、使いすぎるとデータと振る舞いが分離した貧血モデルになります。
判断基準
- 複数のドメインオブジェクトが関与する
- 操作自体がドメインの語彙である
- アプリケーションの手順やI/Oではない
BAD
Orderの全ロジックをOrderServiceへ移し、Orderをgetter/setterだけにする。
GOOD
複数口座間の振替可否を判定するTransferPolicy。
Rule 08
Application Serviceには何を書く?
推奨
ユースケースの進行、入出力、認可、Repository呼び出し、Transaction境界を調整し、業務判断はDomain Modelへ委譲する。
なぜ
アプリケーションの手順とドメインルールを分けると、同じルールを別の入口から安全に再利用できます。
判断基準
- 処理の順序を組み立てる
- 外部I/Oを調整する
- ドメインオブジェクトの操作を呼び出す
BAD
Application Service内のif文だけでキャンセル期限や状態遷移を判定する。
GOOD
注文を取得し、order.cancel(reason)を呼び、保存してイベントを公開する。
Rule 09
Domain ModelとDB Modelは分ける?
推奨
ORM制約がドメイン設計を歪める場合は分ける。単純な領域では同一モデルから始めてもよい。
なぜ
分離には変換コストがある一方、複雑なモデルをテーブル構造や遅延読み込みから守れます。
判断基準
- ORM注釈や継承制約がモデルへ漏れている
- 保存形式とドメインの形が大きく異なる
- DBなしでドメインテストを行いたい
BAD
常に分離するという理由だけで、単純なCRUDにも大量の同形クラスと変換コードを作る。
GOOD
Repository内のMapperがOrderRecordとOrder Aggregateを相互変換する。
Rule 10
IDはDomain側とDB側のどちらで生成する?
推奨
生成直後から識別が必要ならDomain側で生成する。DBの連番は永続化後までID不要な場合に限定する。
なぜ
保存前にIDがあれば、Domain Eventや他オブジェクトの参照をDBへの依存なしで組み立てられます。
判断基準
- 保存前にイベントへIDを含める
- 分散環境で衝突なく生成する
- ID形式自体に業務ルールがある
BAD
仮の0やnullをIDとして持たせ、保存後にDomain Modelを不完全な状態から修復する。
GOOD
FactoryがOrderIdを生成し、完全なOrderをRepositoryへ渡す。
Rule 11
例外クラスはどこに置く?
推奨
破られたルールの所有者と同じ層に置き、技術例外は境界でアプリケーション向けの失敗へ変換する。
なぜ
ドメインの失敗と通信・DBの失敗を区別すると、呼び出し側が意味に応じた処理を選べます。
判断基準
- ドメイン例外は業務語彙で命名する
- ORM例外をUIまで漏らさない
- 予期できる不成立はResult型も検討する
BAD
すべてをBusinessException一種類に包み、原因や回復方法を失う。
GOOD
OrderAlreadyShippedをdomainに置き、DB接続失敗はinfrastructureで変換する。
Rule 12
Transactionはどこで開始する?
推奨
原則としてApplication Serviceの1ユースケースを境界に開始し、1つのAggregateを原子的に更新する。
なぜ
ユースケースの成功・失敗とコミットを揃えつつ、ドメインをDBのTransaction APIから独立させられます。
判断基準
- Application ServiceまたはUnit of Workが制御する
- Domain ModelはTransaction APIを知らない
- 複数Aggregateの長いロックを避ける
BAD
Entityのメソッド内でDB Transactionを開始し、外部API呼び出し中もロックを保持する。
GOOD
PlaceOrderの開始時にTransactionを開き、Order保存とOutbox記録を同時にコミットする。
この内容を書くときに確認した情報
原典、著者による説明、実践者の資料を分けて確認しています。
Eric Evans · original-reference
DDD Reference — Definitions and Pattern Summaries最終確認: 2026-08-08
Martin Fowler · practitioner-article
Domain Driven Design最終確認: 2026-08-08