DDD 実践メモ
随時追記
DDDのパッケージ構成
以下が参考になる
Repositoryのinterfaceはdomain層とQueryServiceのinterfaceはapplication層に置く。それによりrepository層の直依存を切れる。repository→application/domain層への依存を最小化できる。関心の分離
リポジトリ
- NGパターン
- 1エンティティに対して複数Repository作る -> データ/ロジックの整合性が取れない
- 対策:状態更新に関わる振る舞いはEntityやServiceに実装
- 子テーブルにもRepositoryを作成する -> ビジネス要件のチェックロジックがrepositoryにも持たざるを得なくなったり、チェック処理を迂回して更新ができてしまう
- 対策:集約を使う
- 複雑なクエリをRepositoryで発行する -> メンテナンスしづらい、かつ N+1問題にもつながりかねない
- 対策:CQRS
- 1エンティティに対して複数Repository作る -> データ/ロジックの整合性が取れない
Repository は集約の単位で作成
ref:
集約
- 永続化の単位となるクラス群。境界の定義
- 1トランザクション範囲。(トランザクション整合性)
- 集約の操作は集約ルートを介してのみ可能
- 集約は小さくし、トランザクションの範囲は最小限にする。->トランザクションの衝突が少なく、スケーラビリティ/性能が良く保てる
- 別の集約ルートはIDのみ保持して参照する->値の同時更新が必要ならEntityを持ち、参照のみで済むならID保持(参照するデータが変わるならID変えるだけで済む)
以下に立ち向かう方法が集約:
- サービスクラスに大量の Repository をインジェクションが必要に…
- オブジェクトの一部だけをロードして、子要素が NULL の状態に…
- データアクセスの設定/記述方法により N + 1 問題発生…
例:
orderRepository.save(order); order.orderDetails.forEach(orderDetailRepository::save);
を、1リポジトリで両方の永続化を行うことで以下となり、コードの複数箇所で Order と OrderDetail 保存する場合にも、1Repository の内部実装にて共通化可能
orderRepository.save(order);
ref:
-
CQRS
- 部分的導入が可能
- QuerySerivceの戻り値がユースケースに依存するものなためUseCase層
以下が参考になる
reference indexes
-
- 具体的サンプルがある
indexnext |previous |TERASOLUNA Server Framework for Java (5.x) - ドメイン層の実装
-
- サンプル問題と例有り
実践! Typescript で DDD - マイクロサービス設計のすすめ
- マイクロサービスを考えるなら一読した方が良いかも
-
- ドメインロジック考える時の参考になりそう
最近の海外DDDセミナーを聞いてみたら色々と常識が破壊された
- イベントが設計の基本線となりつつあるらしい… pub/subの設計