DDD輪読会 II-5

2022/05/26 @kdnakt


今日の範囲

  • エリック・エヴァンスのドメイン駆動設計
    • 5章 ソフトウェアで表現されたモデル
      • 関連
      • エンティティ(ENTITIES)
      • 値オブジェクト(VALUE OBJECTS)
      • サービス(SERVICES)
      • モジュール(MODULES)
      • モデリングパラダイム

今日の概要

  • 技術面でも概念面でも高凝集&疎結合がよい
  • オブジェクトの関連を設計して無駄をなくす

関連(Associations)

  • 現実の多対多、双方向の関連
    • 実装と保守が複雑

関連を扱いやすくする3つの方法
  1. 関連をたどる方向を強制する
  2. 限定子を付加して多重度を減らす
  3. 本質的でない関連を除去する

相互依存関係を減らしシンプルな設計に


アメリカ大統領の例(1)

  • 国と大統領:双方向の関係性
アメリカ(の大統領) ->
    ワシントン、ジェファーソン、モンロー

ワシントン -> アメリカ(の大統領)
ジェファーソン -> アメリカ(の大統領)
モンロー -> アメリカ(の大統領)

アメリカ大統領の例(2)

  1. 関連をたどる方向を強制する
アメリカ(の大統領) -> ワシントン、ジェファーソン、モンロー
  1. 限定子を付加して多重度を減らす
1790年のアメリカ(の大統領) -> ワシントン

エンティティ(ENTITIES)

  • 同一性identityで定義されるオブジェクト
    • 属性によって定義されるのではない
    • 属性は変化する
    • 同じ属性を持つケースも (例:同姓同名)
    • 要はアプリのユーザが気にするかどうか

オブジェクト指向言語における同一性
  • 同一性の演算:Javaの==演算子など
    • メモリ上の位置の比較など
    • ドメインではほぼ無意味
      • 例)同日同口座同額の預入
    • 別の一意の識別子が必要
  • 同じモノでもモデル上の表現が変わる
    • 例)座席予約:自由席と指定席

エンティティをモデル化する
  • 同一性の定義:ドメイン理解が必要

    • パターン1:オブジェクトの属性
      • 例)新聞:名前、都市、発行日
    • パターン2:属性でキーが決まらない
      • UUIDなど自動生成
      • ID表示すべきか問題(ドメイン次第)
    • パターン3:システム境界を越える同一性
      • マイナンバー、社会保障番号etc
  • 同一性の最終判断はユーザが行う


値オブジェクト(VALUE OBJECTS)

  • ドメインにおける記述的な側面を表現する
  • 概念的な同一性を持たない
  • 複雑な値オブジェクト
    • 値オブジェクトから構成される
    • エンティティを参照する

住所:エンティティか値オブジェクトか?
  • 通販ドメインの顧客の住所:値オブジェクト
  • 郵便ドメインの住所:エンティティ
  • 電気会社のドメイン
    • サービス提供先:エンティティ
    • 住居の一属性:値オブジェクト

値オブジェクトの凝集度
  • 概念的にまとまりとして表現すべき
// NG
顧客: { 名前, 都道府県, 市区町村, 番地 }

// OK
顧客 { 名前,
    住所 { 都道府県, 市区町村, 番地 }
}

値オブジェクトの設計
  • 同一性がない=どのインスタンスでも良い
    • 設計が自由、性能最適化が可能
    • 別のエンティティにコピーできる
    • 別のエンティティと共有できる
      • ゆえに不変であるべし
    • 性能のため1インスタンスを共有
// JavaのLong.javaの例 public static Long valueOf(long l) { final int offset = 128; if (l >= -128 && l <= 127) { // will cache return LongCache.cache[(int)l + offset]; } return new Long(l); }

値オブジェクトに可変性を認めるべきか?
  • パフォーマンスを考慮して許可するケースも
    • 値が頻繁に変化する
    • オブジェクト生成・削除が高コスト
    • クラスタリングが妨げられる場合

クラスタリングのくだりよく分からなかった🙇‍♂️


値オブジェクトを含む関連を設計する
  • モデル中の関連は数が少なく単純である方が良い
  • 双方向の関連
    • エンティティの場合、保守が困難に
    • 値オブジェクトの場合、役に立たない(同一性がないので)

サービス(SERVICES)

  • どのオブジェクトにも属さない操作の集合
    • 手続き型プログラミングはNG
    • エンティティ/値オブジェクトから 全ふるまいを奪うのもNG

優れたサービスの3つの特徴
  • 操作がドメインの概念に関係している
  • ドメインモデルに基づくインターフェース定義
  • 操作に状態がない(副作用はあってもよい)

サービスと隔離されたドメイン層
  • サービスの3つのレイヤ
    • インフラ層の技術的サービス
    • アプリケーションサービス
    • ドメインサービス
  • インフラ層の技術的サービス
    • 例)メール通知サービス
    • ビジネスに関する意味が一切ないはず
  • アプリケーションサービス
    • ドメイン/技術的サービスを呼び出す
    • 入力を変換する
  • ドメインサービス
    • 例)銀行業ドメインの資金振替サービス

粒度
  • アプリケーションサービス:ドメインオブジェクトのふるまいが組み合わさる場所
    • ドメインサービスの粒度が細かいと、 ドメイン知識がここに流出する
    • 中くらいの粒度のサービスが吉

中くらいってなんやねん! (現時点では説明なし)


モジュール(MODULES)

  • パッケージ(PACKAGES)ともいう

  • 認知負荷を下げるためにモジュール化

    • モジュールの内部詳細に専念(高凝集)
    • モジュール間の関係性に着目(疎結合)
  • ドメイン層のモジュール

    • 意味のあるモデルの一部
    • コードだけでなく概念も分割

アジャイルモジュール
  • 初期の誤ったモジュールが利用されがち
    • オブジェクトの結合度が高い
    • リファクタリングが困難
  • ドメイン理解の深化に合わせ モジュールも変化すべき
    • 広範囲のコード変更、混乱を生む可能性
    • 歯を食いしばってリファクタリング(モジュール再構成)すべき

Javaのパッケージ利用例
  • import my.package.*
    • モジュールの依存関係を伝える
    • リファクタリングが楽

あまり推奨されない (参考:フューチャー株式会社の規約


フレームワーク駆動パッケージングの代償
  • 例:J2EEの分割規約
    • オブジェクトが散らばってしまう
    • 複雑なフレームワークの理解で疲弊
  • ドメインコードとそれ以外を分離するために パッケージを利用せよ
    • 参考:第4部 戦略的設計

モデリングパラダイム

  • モデル駆動設計=オブジェクト指向設計だけ、ではない
  • オブジェクト指向設計はシンプルだがドメイン知識を伝える力がある
    • 高度に数学的なドメインなどは不適
  • ルールエンジンやワークフローなどのパラダイムもある
    • 斬新なパラダイムはそれを使える開発者やツールが少ない問題

パラダイムの混在
  • 基本的にパラダイムを混在させないよう 努力すべき
  • どの実装でも使える 単一のモデルを見つけよう
  • 複数のパラダイムをまとめる効果的なツール =ユビキタス言語

まとめ

  • ドメインオブジェクト:エンティティ、 関連、値オブジェクト、サービス、モジュール
    • 実装とモデルが直接一致する場所
  • ドメインオブジェクトが実現するモデルと 関係ないものを追加してはいけない
    • 技術的なオブジェクトについては第6章
Select a repo