■ 1. 結論
- ドメインサービス内でのリポジトリ実行は避けるべきであるが実害の有無によって判断する
- 実害が無視できない場合は避け そうでない場合は許容する
■ 2. ドメインサービスでリポジトリを実行すべきでない理由
- アプリケーションレイヤとドメインサービスの責務が曖昧になるため
- アプリケーションレイヤの責務:
- 処理の流れを実装する
- ドメインサービスの責務:
- ビジネスルールを実装する
- リポジトリをドメインサービスで実行すると起こる問題:
- 処理の流れとビジネスルールが混在する
- ドメインサービスがファット化する
- トランザクション境界が不明確になる
- アプリケーションレイヤが不自然に薄くなる
■ 3. ドメインサービスの適切な使用条件
- 複数の集約にまたがる操作であること
- その操作にぴったりな名前が付けられること
- 上記条件を満たす実装は少ないためドメインサービスを使う機会は意外と少ない
■ 4. 実害の重要性
- ドメインサービスでリポジトリを実行した場合の実害の程度が判断基準となる
- 実害がなければそのまま維持し 困ったらリファクタリングする
■ 5. 回避策
- パターン1: 妥協してドメインサービスでリポジトリを実行する:
- 実害がない場合に有効(回避策ではなく許容)
- パターン2: 1つの集約にまとめる:
- 集約の境界を見直し 複数の集約を1つに統合する
- 新たな集約の発見や入れ子構造の採用によって解決できる場合がある
- 「xxxされたら」「xxxのあとで」という表現があるケースはドメインイベントの可能性が高くこのパターンに該当しない
- パターン3: ドメインイベントとして扱う:
- 「Taskが作成されたらActivityReportが作成される」のようなケースに適用
- ユースケース内でドメインイベントを発行しイベント受信側が処理を担当する
- イベントソーシングの場合は集約自体がイベントを保持する形になる
- アウトボックスパターン等の実装が必要になる場合があり実装コストが高い
- パターン4: アプリケーションレイヤでリポジトリを実行する:
- ドメインサービスを使わずにアプリケーションレイヤで直接リポジトリを実行する
- トランザクション制御との相性が良く自然に実装できる
- ドメインサービスを乱用するよりこちらを選ぶ方が良い場合がある