📐
概念 #DDD #集約 #設計原則 📚 実践ドメイン駆動設計

集約の設計原則(Vernon の4ルール)

「小さく保て」「IDで参照せよ」など、誤った集約設計を防ぐVernon が提唱する4つの実践ルール

背景

集約の概念を理解しても、「何を集約に含めるか」という判断で多くの設計が失敗する。Vernon は IDDD 第10章で4つの経験則を明示した。これは集約の誤った設計パターン(巨大集約)を防ぐための実践ガイド。

ルール1: 真に必要な不変条件だけを集約に含める

集約の境界はビジネスの不変条件(invariant)が要求する範囲によって決まる。「同時に変更されなければならないもの」だけを同じ集約に入れる。

❌ 「関連があるから」同じ集約に入れる
✅ 「同一トランザクションで一貫していなければならない」から同じ集約に入れる

例: OrderCustomer は関連するが、別々に変更されてよい → 別集約。

ルール2: 集約を小さく設計する

大きな集約はロックの競合・パフォーマンス劣化・テストの複雑化を招く。

❌ Forum(大集約)
  ├── Post × 1000
  │    └── Comment × 1000
  └── Moderator × 10

✅ Forum(集約ルート、IDのみ保持)
    Post(別集約、forum_id を持つ)
      Comment(さらに別集約、post_id を持つ)

大抵の場合、集約は2〜5個のオブジェクトで十分。

ルール3: 別の集約を参照するにはIDのみを使う

集約間の参照はオブジェクト参照ではなくIDに限定する。

# ❌
class Order:
    customer: Customer  # 直接参照

# ✅
class Order:
    customer_id: CustomerId  # IDのみ

IDのみの参照により:

  • 集約の境界が明確になる
  • ロード時に不要な集約をメモリに展開しない
  • 集約間の変更が独立する

ルール4: 結果整合性を使って集約の整合性を保つ

「2つの集約を同時に整合させる必要がある」と感じたとき、その多くは結果整合性で解決できる

同期(1トランザクション):  Order.place() が在庫を直接減らす ← ❌
非同期(結果整合性):       Order.place() → OrderPlaced イベント
                          → 在庫コンテキストが非同期で在庫を減らす ← ✅

「即時一貫性が本当に業務要件か」をドメインエキスパートに確認する。大抵は数秒の遅延が許容される。

判断フローチャート

1. これは同じトランザクションで変更しなければならないか?
   YES → 同じ集約に含める
   NO  → 別集約へ(IDで参照、イベントで連携)

2. 集約が巨大になっていないか?
   YES → 不変条件を再確認し、分割できるものを分割

3. 別集約への参照がオブジェクト参照になっていないか?
   YES → IDのみの参照に変更

関連概念

出典: 実践ドメイン駆動設計(Vaughn Vernon)第10章