# DDD輪読会 II-6
2022/06/09 [@kdnakt](https://twitter.com/kdnakt)
---
### 今日の範囲
- エリック・エヴァンスのドメイン駆動設計
- 6章 ドメインオブジェクトのライフサイクル
- 集約(AGGREGATES)
- ファクトリ(FACTORIES)
- リポジトリ(REPOSITORIES)
- RDBに合わせたオブジェクト設計
---
### オブジェクトのライフサイクル
```mermaid
flowchart LR
誕生 -->|生成|アクティブ
アクティブ-->|修正|アクティブ
アクティブ-->|格納|DB
DB-->|再構成|アクティブ
アクティブ-->|アーカイブ|ファイルetc
アクティブ-->|削除|死
ファイルetc-->|削除|死
```
----
#### オブジェクト管理の課題
1. ライフサイクルを通じて
整合性を維持できるか
2. 複雑なライフサイクルで
モデルが侵食されないか
----
#### 課題を解決する3つのパターン
- 集約:
境界を定義し、整合性を保つ
- ファクトリ:
複雑なオブジェクトの生成、再構成
- リポジトリ:
永続層へのアクセスをカプセル化
----
#### ファクトリとリポジトリ
- それ自体はドメインに由来しない
- モデルオブジェクトを操作可能に
- モデル駆動設計を完成させる
---
### 集約(AGGREGATES)
- 不変条件を維持する必要性
- =TXのスコープとデータの一貫性を維持する
- 🙅♂️技術的な問題
- 🙆♀️モデル、ドメイン理解の問題
- 境界が未定義
----
#### 購入注文の整合性
- シンプルなモデル
- 不変条件:注文品目総額 <= 限度額
```mermaid
classDiagram
class 購入注文
購入注文 : +int 限度額
class 購入注文品目
購入注文品目 : +int 数量
購入注文品目 "*" <|-- "1" 購入注文
class 商品
商品 : +int 価格
購入注文品目 -- 商品
```
----
##### 相互に関連した3つの問題
1. 不変条件の強制が不十分
- ロックの範囲はどこか?
2. 変更管理がモデル化されていない
- 商品価格の変更などどこまで関係を辿るべきか?
3. データベースの共有
- 別のトランザクションにおける同時編集
----
##### ビジネス知識でモデルを改良する
- 商品:共有、変更頻度低
- 商品価格変更:必ずしも購入注文に反映不要
```mermaid
classDiagram
class 購入注文
購入注文 : +int 限度額
class 購入注文品目
購入注文品目 : +int 数量
購入注文品目 : +int 価格
購入注文品目 "*" <|--o "1" 購入注文
class 商品
商品 : +int 価格
購入注文品目 --|> 商品
```
※◇-->:集約を表す記号
---
### ファクトリ(FACTORIES)
:::warning
- オブジェクトや集約の生成が複雑
- オブジェクトの内部構造が剥き出し
:::
- :no_good: 複雑なオブジェクトがそれ自体を生成
- :no_good: クライアントがオブジェクトを生成
- :ok_woman: ファクトリによるカプセル化
----
#### ファクトリの責務
- 複雑なオブジェクトや集約を生成/再構成する
- オブジェクトの具象クラスをクライアントから隠す
- ひとまとまりの集約を生成し不変条件を強制する
----
#### 集約の拡張をカプセル化するファクトリ
- 既存の集約に要素を追加するケース
- 集約内部実装をクライアントから隠蔽
- ファクトリが集約の整合性を保証
- 集約をリファクタリングするケース
- 取引注文->売り注文/買い注文
----
#### コンストラクタが適切なケース
- 構築が複雑でない
- インターフェースのない型である
- クライアントが実装を知る必要がある
- 例)ストラテジーパターン
- 例)Javaのコレクション
----
#### ファクトリのメソッドシグネチャ設計
- 各操作をアトミックに
- 1回で全ての引数を渡す
- 生成失敗時のコーディング標準
- NULL?例外?
- 引数と結合する
- 引数は具象クラスでなく抽象型を
----
#### 再構成のためのファクトリ
- DB:オブジェクトをシリアライズして保存
- メソッドの情報などは失われる
- 利用時に組み立てが必要
- 例)ORM, XMLパーサ
- 生成時のファクトリとの違い
- 新しい識別子を割り当てない
- 不変条件の取り扱い
---
### リポジトリ(REPOSITORIES)
- オブジェクトを利用するには参照が必要
- どうやって参照を手に入れる?
1. オブジェクトを生成する
2. 別オブジェクトから関連を辿る
- 最初のオブジェクトはどこから手に入れる?
----
#### RDBから再構成する
- クエリによりオブジェクトを再構成
- 全てのオブジェクトの関連は不要
- 検索で直接到達できる
- 「検索vs関連」のトレードオフ
----
#### モデルが無視される危険性
- クライアント開発者:ドメイン層縮小しがち
- SQLクエリを構築
- 関連を追加
- 集約ルート以外から内部オブジェクトにアクセス
- モデル駆動設計が不明瞭になる
----
#### DBアクセスに起因する課題への対処
- リポジトリパターン
- クエリオブジェクト
- メタデータマッピング層
- ファクトリによる再構成
- DB技術をカプセル化しモデルに焦点を戻す
- クライアントはモデルの言葉でアクセス
- モックによりテストも容易
- 開発者が実装を無視するのはNG
- 例)集計に全データをロードしOOM
----
#### リポジトリのインターフェース設計
1. 特定のパラメータを受け取る
- クエリはハードコード
- 例)getOrderById
1. 仕様パターン
- クライアントが仕様を記述(詳細は9章
----
##### 仕様パターンの例
- JPAのCriteria API

----
#### リポジトリを実装する
- 型を抽象化する
- :no_good: 具象クラスごとにリポジトリ
- クライアントから切り離す
- 性能の最適化
- テスト時のインメモリモック
- トランザクションはクライアントが制御
- リポジトリをシンプルに保つ
- フレームワークの範囲内で
- ドメイン駆動設計と混ぜすぎない
----
#### ファクトリ
- リポジトリ:データからオブジェクトを作る
- ある意味ではファクトリ
- モデル的にはファクトリではない
- 生成と再構成は別
- オブジェクトのライフサイクル
- 初期:ファクトリが生成
- 中期以降:リポジトリが再構成
- ファクトリに処理を委譲
- リポジトリの責務を明確化
---
### RDBに合わせたオブジェクト設計
- DBはオブジェクトでないシステム構成要素
- それぞれが歩み寄る必要性
- モデルの豊かさを犠牲に
- 選択的な非正規化も必要
- オブジェクトシステム外からDBにアクセスしないこと
- 不変条件への違反
- オブジェクトのリファクタリング困難
----
#### ユビキタス言語による結びつき
- オブジェクトモデルと関係モデルは別物
- ユビキタス言語で単一のモデルができる
- オブジェクトの要素の名前や関連に注意
- マッピングツールによっては微妙に異なる関係を生む
{"metaMigratedAt":"2023-06-17T02:14:27.409Z","metaMigratedFrom":"YAML","title":"DDD輪読会 II-6","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"df36d0f0-b67e-41ac-96b3-f3988326d230\",\"add\":4072,\"del\":237}]"}