Aggregates (125ページ) †
要約 †
- [問題についての説明]
- 関連を最小限に抑える設計は、相互関係の爆発を防ぐ
- ほとんどのビジネス領域は、オブジェクト参照で長く深い経路を辿ることになる
- これはソフトウェア設計の問題
- あるオブジェクトを削除するとき、他のオブジェクトも参照しているオブジェクトまで消すわけにはいかない。
- でも残しておくとゴミが出る可能性もある
- GCが解決してくれるかもしれないが、モデルの問題は残る
- 孤立したトランザクションでも、オブジェクトの関係は入りくんでおり明確な境界をひくことができない
- かといって、システム上の全オブジェクトを更新するのは現実的ではない
- 複数のクライアントで同時に同じオブジェクトにアクセスすると厄介
- オブジェクトの変更範囲を間違えると危険
- 問題サマリ
- 複雑な関連を保ちつつ対象となるモデルの変更の一貫性を保つのは難しい
- オブジェクトの不変性を保つ必要があるけれども、用心深いロック機構は複数ユーザの無意味な干渉が起こり、システムが使えなくなる
- [問題の解決方法についての説明]
- DBを持つシステムはデータ更新のトランザクションスコープ、データの一貫性を保つ方法が必要
- 良い解決案を見つけるのはドメインに対する深い理解が必要
- 技術的困難が問題として表沙汰になるが、実は問題はモデルにありバウンダリ(境界)が欠如している。モデルから導いた解決案はモデルや設計を簡単にする。モデルが改訂されるにつれ、実装も変化していく。
- AGGREGATEは、データ更新の目的を単位として構成するオブジェクトの集まり
- AGGREGATEはrootとboundaryを持つ。boundaryはAGGREGATEの中に何があるかを定義する。rootはAGGREGATE内にある一意となるENTITY。
- rootはAGGREGATEにあるオブジェクトの中で唯一外部オブジェクトへの参照を保持できる。root以外のENTITYはローカルIDを持つ。
- 車のモデルを例に説明。車はグローバルID(車両識別番号)を持つENTITY。
- ホイールの位置や走行距離、タイヤの摩耗状況を知りたいとする。タイヤはローカルENTITY(他の車のタイヤのIDは知らない)。タイヤを交換してしまえば、もうそのタイヤについて知る必要はなくなる。エンジンはシリアル番号があって車とは別に知る必要があり、アプリケーションによってはエンジンもAGGREGATEのrootになる。
- 不変条件(Invariants)はAGGREGATEのメンバー間の関係を含む。AGGREGATESにおよぶルールは常に最新になるとは限らない(イベントやバッチなどで解決)。
- AGGREGATEを概念から実装に置き換えるには、すべてのトランザクションに適用されるルールセットが必要
- root ENTITYは不変条件をチェックする役割がある
- rootはDBクエリで直接アクセスでき、他は関連を通して探さなければいけない。
- AGGREGATE内のオブジェクトは他AGGREGATEのrootへの参照を持てる
- 削除処理は一気にAGGREGATEバウンダリ内のすべてを削除しなければならない。(GCがある場合はrootを消すだけでよい)
- 変更は、全てのAGGREGATEの不変条件を満たさなければならない
- 解決方法サマリ
- AGGREGATE内にて、rootが他へのアクセスをコントロールするようにすれば、どんな状態変更でも不変性を保てる
- 結果、実装上の検討事項、サンプル
- 自動ロックなどを行うフレームワークがあると便利だが、ない場合は自己管理能力が必要
Example : Purchase Order Integrity †
- 購入注文システムを例に考えてみる。図は発注書(PO)を簡単に表したもの。品目の合計金額はPOの上限を超えないという不変条件がある。3つの互いに関係しあう問題がある。
- 不変性の実施。新しい品が追加されるとPOは合計をチェックして上限を超えてないかチェックする。これは十分ではない。
- 管理の変化。POが削除 or 保管されたり、時間によって価格が変わったりする。
- DBの共有。複数ユーザは衝突問題を引き起こす
- 複数ユーザが並行してPOを更新し、ちゃんと処理しなければならない。まずは、誰かがある品を更新してる時は誰もその品にアクセスできない(他はOK)、という方法から始めてみる。
- 複数ユーザが同じPOで違った項目を同時に変更する。DBは変更対象以外は無視するので、うまくいってるように見える。ユーザは他のユーザの変更を知らない。結果、ドメインモデルの不変性は崩れる。
- 明らかに単一品目のロックは安全ではない。全てのPOをロックしたら問題は防げた。
- 誰かが処理を完了するまで全てをロックし続けると問題を防げるが、複数人が同時に処理するとなると、このロック機構は厄介。
- パーツをロックしてみる。ジョージがギターとトロンボーンをロック。アマンダはバイオリンをロックして、トロンボーン待ち。サムがトロンボーン待ち。不便極まりない。
- ジョージがバイオリンを追加しようとするとアマンダ待ちに入り、デッドロック。
- 以下の業務知識を取り入れることでモデルを改善できる。
- パーツは多くのPOで(競合しあって)利用される
- パーツの変化はPOより少ない
- パーツの価格変更は既存のPOに必ず影響するとはかぎらない。注文済みのPOに価格変更は影響しない
- 3番目は納品済みの保管されたPOを考慮すると明らかで、現在の価格でなく当時の価格を示すべき。
- このモデルに沿って実装するとPOと品との関連の不変性を保証し、部品の価格が変化してもそれを含んでいる品には直接影響しない。
- AGGREGATEは、商慣習に沿ったPOと品の所有権を課す
***
- AGGREGATESは、不変条件がライフサイクルの各段階で維持すべき範囲をチェックする。FACTORIESやREPOSITORIESなどのパターンはAGGREGATESに影響し、特定のライフサイクルの変わり目に起こる複雑さを隠蔽する
担当者のつぶやき †
みんなの突っ込み †
- p.127 l.1「rootはAGGREGATE内にあるオブジェクトの中で、外部のオブジェクトが参照を保持することを許された唯一のメンバーである。」だと思います。 -- 和智?