ドメイン駆動設計(DDD)で設計をしていると、次のような疑問に必ずぶつかります。

  • このエンティティは同じ集約に入れるべきか?
  • それとも別の集約として切り離すべきか?

集約の境界は、DDDにおいて非常に重要な設計判断です。 この記事では、実務でよく使われる判断基準を整理します。


1. 不変条件を同時に守る必要があるか(最重要)

最も重要な基準は 不変条件(Invariant) です。

「このルールは常に同時に成立している必要があるか?」

  • YESなら 同じ集約
  • NOなら 別集約

注文と注文明細

Order
 └ OrderItem

不変条件

  • 注文の合計金額 = 各注文金額の合計
  • 注文明細の数量 ≥ 1

数量が変われば、注文全体の合計金額は変わります。 つまり、これらは 常に同時に成立している必要があります。 そのため OrderOrderItem同じ集約になります。


別集約になる例

Order
Inventory (在庫)

ルール

注文が確定したら在庫を減らす

この処理は

  1. 注文確定
  2. 在庫更新

の2つの処理に分かれます。

これらは 同時トランザクションでなくても問題ないため

Order集約
Inventory集約

と分けます。


2. ライフサイクルが一緒か

次に考えるのは ライフサイクルです。

「一緒に生まれて一緒に消えるか?」

  • YES → 同じ集約
  • NO → 別集約

Order
 └ OrderItem

OrderItem

  • Order が作られるときに作られる
  • Order が削除されるときに削除される

つまり 独立した存在ではないため、同じ集約に含まれます。


別集約の例

User
Order

Order

  • User が削除されても履歴として残る

このように ライフサイクルが独立しているため、別集約になります。


3. 集約は他の集約をIDで参照する

DDDでは次のルールがよく使われます。

集約は他の集約をIDで参照する

OK

Order
 └ userId

NG

Order
 └ Userオブジェクト

集約間はオブジェクト参照ではなく ID 参照にします。 これは「IDで参照できるなら別集約」という意味ではなく、 「別集約である場合は ID で参照する」というルールです。

このルールを守ることで、集約間の結合度を下げることができます。

具体例は別の記事 (DDDで「集約はIDで参照する」とはどういう意味か) を参照してください。


4. 同時に更新されるか

もう一つの判断基準は 更新タイミングです。

「この2つはいつも一緒に更新されるか?」

  • YES → 同じ集約の可能性
  • NO → 別集約

Order
Payment

多くのシステムでは

  • 注文作成
  • 決済

は別タイミングで行われます。

そのため

Order集約
Payment集約

のように分けることが多いです。


5. 集約は小さく保つ

DDDではよく次の原則が言われます。

集約は小さく保つ

巨大な集約を作ると

  • トランザクションが重くなる
  • ロック競合が増える
  • スケールしにくくなる

といった問題が起きます。

そのため、迷った場合は 小さく分ける方向で設計することが多いです。


まとめ

集約を設計する際は、次の質問を自分に投げかけると整理しやすくなります。

  1. この不変条件は同時に守る必要があるか?
  2. 一緒に生まれて一緒に消えるか?
  3. 片方だけ更新されるケースはあるか?
  4. トランザクションを分けても問題ないか?

特に重要なのは次の考え方です。

「どの不変条件をトランザクションで守るか」

これが、そのまま 集約の境界になります。

集約設計はDDDの中でも難しい部分ですが、この視点を持つと設計の判断がしやすくなります。