今日の範囲
- エリック・エヴァンスのドメイン駆動設計
- 5章 ソフトウェアで表現されたモデル
- 関連
- エンティティ(ENTITIES)
- 値オブジェクト(VALUE OBJECTS)
- サービス(SERVICES)
- モジュール(MODULES)
- モデリングパラダイム
今日の概要
- 技術面でも概念面でも高凝集&疎結合がよい
- オブジェクトの関連を設計して無駄をなくす
関連を扱いやすくする3つの方法
- 関連をたどる方向を強制する
- 限定子を付加して多重度を減らす
- 本質的でない関連を除去する
アメリカ大統領の例(1)
アメリカ(の大統領) ->
ワシントン、ジェファーソン、モンロー
ワシントン -> アメリカ(の大統領)
ジェファーソン -> アメリカ(の大統領)
モンロー -> アメリカ(の大統領)
アメリカ大統領の例(2)
- 関連をたどる方向を強制する
アメリカ(の大統領) -> ワシントン、ジェファーソン、モンロー
- 限定子を付加して多重度を減らす
1790年のアメリカ(の大統領) -> ワシントン
エンティティ(ENTITIES)
- 同一性identityで定義されるオブジェクト
- 属性によって定義されるのではない
- 属性は変化する
- 同じ属性を持つケースも
(例:同姓同名)
- 要はアプリのユーザが気にするかどうか
オブジェクト指向言語における同一性
- 同一性の演算:Javaの==演算子など
- メモリ上の位置の比較など
- ドメインではほぼ無意味
- 別の一意の識別子が必要
- 同じモノでもモデル上の表現が変わる
エンティティをモデル化する
-
同一性の定義:ドメイン理解が必要
- パターン1:オブジェクトの属性
- パターン2:属性でキーが決まらない
- UUIDなど自動生成
- ID表示すべきか問題(ドメイン次第)
- パターン3:システム境界を越える同一性
-
同一性の最終判断はユーザが行う
値オブジェクト(VALUE OBJECTS)
- ドメインにおける記述的な側面を表現する
- 概念的な同一性を持たない
- 複雑な値オブジェクト
- 値オブジェクトから構成される
- エンティティを参照する
住所:エンティティか値オブジェクトか?
- 通販ドメインの顧客の住所:値オブジェクト
- 郵便ドメインの住所:エンティティ
- 電気会社のドメイン
- サービス提供先:エンティティ
- 住居の一属性:値オブジェクト
値オブジェクトの凝集度
// NG
顧客: { 名前, 都道府県, 市区町村, 番地 }
// OK
顧客 { 名前,
住所 { 都道府県, 市区町村, 番地 }
}
値オブジェクトの設計
- 同一性がない=どのインスタンスでも良い
- 設計が自由、性能最適化が可能
- 別のエンティティにコピーできる
- 別のエンティティと共有できる
- 性能のため1インスタンスを共有
| |
| public static Long valueOf(long l) { |
| final int offset = 128; |
| if (l >= -128 && l <= 127) { |
| return LongCache.cache[(int)l + offset]; |
| } |
| return new Long(l); |
| } |
値オブジェクトに可変性を認めるべきか?
- パフォーマンスを考慮して許可するケースも
- 値が頻繁に変化する
- オブジェクト生成・削除が高コスト
- クラスタリングが妨げられる場合
値オブジェクトを含む関連を設計する
- モデル中の関連は数が少なく単純である方が良い
- 双方向の関連
- エンティティの場合、保守が困難に
- 値オブジェクトの場合、役に立たない(同一性がないので)
サービス(SERVICES)
- どのオブジェクトにも属さない操作の集合
- 手続き型プログラミングはNG
- エンティティ/値オブジェクトから
全ふるまいを奪うのもNG
優れたサービスの3つの特徴
- 操作がドメインの概念に関係している
- ドメインモデルに基づくインターフェース定義
- 操作に状態がない(副作用はあってもよい)
サービスと隔離されたドメイン層
- サービスの3つのレイヤ
- インフラ層の技術的サービス
- アプリケーションサービス
- ドメインサービス
- インフラ層の技術的サービス
- 例)メール通知サービス
- ビジネスに関する意味が一切ないはず
- アプリケーションサービス
- ドメイン/技術的サービスを呼び出す
- 入力を変換する
- ドメインサービス
粒度
- アプリケーションサービス:ドメインオブジェクトのふるまいが組み合わさる場所
- ドメインサービスの粒度が細かいと、
ドメイン知識がここに流出する
- 中くらいの粒度のサービスが吉
モジュール(MODULES)
-
パッケージ(PACKAGES)ともいう
-
認知負荷を下げるためにモジュール化
- モジュールの内部詳細に専念(高凝集)
- モジュール間の関係性に着目(疎結合)
-
ドメイン層のモジュール
- 意味のあるモデルの一部
- コードだけでなく概念も分割
アジャイルモジュール
- 初期の誤ったモジュールが利用されがち
- オブジェクトの結合度が高い
- リファクタリングが困難
- ドメイン理解の深化に合わせ
モジュールも変化すべき
- 広範囲のコード変更、混乱を生む可能性
- 歯を食いしばってリファクタリング(モジュール再構成)すべき
Javaのパッケージ利用例
import my.package.*
- モジュールの依存関係を伝える
- リファクタリングが楽
フレームワーク駆動パッケージングの代償
- 例:J2EEの分割規約
- オブジェクトが散らばってしまう
- 複雑なフレームワークの理解で疲弊
- ドメインコードとそれ以外を分離するために
パッケージを利用せよ
モデリングパラダイム
- モデル駆動設計=オブジェクト指向設計だけ、ではない
- オブジェクト指向設計はシンプルだがドメイン知識を伝える力がある
- ルールエンジンやワークフローなどのパラダイムもある
- 斬新なパラダイムはそれを使える開発者やツールが少ない問題
パラダイムの混在
- 基本的にパラダイムを混在させないよう
努力すべき
- どの実装でも使える
単一のモデルを見つけよう
- 複数のパラダイムをまとめる効果的なツール
=ユビキタス言語
まとめ
- ドメインオブジェクト:エンティティ、
関連、値オブジェクト、サービス、モジュール
- ドメインオブジェクトが実現するモデルと
関係ないものを追加してはいけない
DDD輪読会 II-5 2022/05/26 @kdnakt
{"metaMigratedAt":"2023-06-17T01:17:16.896Z","metaMigratedFrom":"YAML","title":"DDD輪読会 II-5","breaks":false,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"df36d0f0-b67e-41ac-96b3-f3988326d230\",\"add\":5344,\"del\":1006}]"}