副作用はドメインイベントで表現する
ルール
ある集約の操作が別の集約や外部システムに影響を与えるとき、直接呼び出してはならない。代わりにドメインイベントを発行し、購読者(イベントハンドラー)が副作用を実行する。
❌ 直接呼び出し
order.confirm() {
inventory.reduce(this.items) // 別の集約を直接操作
mailer.sendConfirmation(this) // 外部サービスを直接呼び出し
}
✅ イベント経由
order.confirm() {
this.record(new OrderConfirmed(this.id, this.items))
}
// InventoryService が OrderConfirmed を受け取り在庫を減らす
// NotificationService が OrderConfirmed を受け取りメールを送る
理由
集約が別の集約を直接呼び出すと:
- トランザクション境界が崩れる(1トランザクションで複数の集約を変更することになる)
- 結合度が高まり、副作用の追加・変更時に集約本体を修正しなければならなくなる
- 「この操作の副作用は何か?」がコードを読まないとわからなくなる
ドメインイベントを使うと、副作用が追加されても集約本体を変更しなくてよい。
例外
- 同一集約内の内部状態変化(エンティティ間)は直接操作してよい
- パフォーマンス上の理由で同期的な整合性が必須の場合(ただし集約設計を見直す余地も検討する)
関連概念
- → ドメインイベント
- → 集約
- → 集約をトランザクション境界とする
出典
実践ドメイン駆動設計(Vaughn Vernon)第8章