読者です 読者をやめる 読者になる 読者になる

実践ドメイン駆動設計 6.5〜6.7メモ

実践ドメイン駆動設計 (Object Oriented Selection)

実践ドメイン駆動設計 (Object Oriented Selection)

実践ドメイン駆動設計

実践ドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

6.5 実装

  • BusinessPriorityのサンプルは値が持つ全ての特徴を示すだけでなく、ストラテジとして使う方法も示している
  • 例ではSerializeableインタフェースを実装
    • リモートシステムとやりとりするときにや永続化にも役立つはず
  • BusinessPriorityにはratingsの値のプロパティを持たせる
    • BusinessPriorityRatings型
    • 特定とのプロダクトバックログアイテムを実装することによる、事業価値と出費のトレードオフ
    • BusinessPriorityRatingsを使ってBusinessPriorityにbenefit, cost, penalty, riskのレートを渡す
  • 値オブジェクトに2つのコンストラクタ
    • 必要なパラメータをすべて受け取る => 筆者は自己委譲をつかう
    • コピーコンストラクタ
      • シャローコピーをする
      • ディープコピーでもいいが、複雑になるし不変な値を扱うのであればシャローコピーでよい
      • ユニットテストで重要
    • ストラテジといってるのは値オブジェクトのメソッド
    • 副作用のない関数の命名規則
      • getValuePercentageよりvaluePercentageがいい
        • JavaBeansの仕様はダメダメという筆者の意見

6.6 値オブジェクトの永続化

  • 方法はいろいろある
  • 値単体のインスタンスを永続化するのは関心がないので、集約の状態も含めて永続化する方法に注目
  • これ以降は親のエンティティが、永続化させる値のインスタンスへの参照を全て保持していることを前提
  • ORMによる永続化
    • すべての属性をカラムにマッピングすると複雑になる
    • NoSQLが人気だけど、ここではORMベースの永続化を取り上げる
  • ドメインモデリング対データモデリングがはじまる……

データモデルが漏れることに寄る影響を排除する

  • 値オブジェクトをデータストアに永続化する場合、殆どの場合非正規化状態で保存
    • 通常はこれでいい(モデルとデータが一致しているということ?)
  • 値オブジェクトを永続化ストアにエンティティとして格納しなければいけない場合
    • 値オブジェクトのインスタンスのコレクションをORMで扱う場合など
      • 1対多のような状態?
    • データモデルとドメインモデルのインピーダンスミスマッチ => ドメインモデルの視点が大事
      • ドメインにおけるモノか、測定値などのモノの性質についての説明か
      • データモデリングして、ドメインの要素を表したときに、まとめた値の特徴をすべて満たしているか
      • エンティティを使う理由が、データモデルがドメインオブジェクトをエンティティとして扱うことを求めているからか?
      • エンティティを使う理由が、一意な識別子を必要かつオブジェクトの状態を追跡する必要があるか
      • 「性質についての説明、イエス、イエス、ノー」だと値オブジェクト
  • データモデルでドメインモデルを曲げてはいけない
    • インデックスの都合や主キーなど

ORMでの単一の値オブジェクトの扱い

  • 単一の値オブジェクトを非正規化して、親のエンティティの行に組み込むのが基本
    • シリアライズしたオブジェクトが分かるようにカラムの命名規則を標準化する
    • 例:BusinessPriority.ratings.benefit => business_priority_ratings_benefit
    • この場合だと特に問題はなさそうにみえる

ORMでの、複数の値をシリアライズした単一カラムの扱い

  • ListやSetで保持している値オブジェクトをシリアライズして、一つのカラムに持たせる
  • カラムのサイズや問い合わせの条件の考慮が必要
    • 問い合わせはできないよねこれ
    • Hibernateだとカスタムユーザー型が必須

SQLアンチパターン

SQLアンチパターン

ORMでの、複数の値をデータベースのエンティティに格納する場合の扱い

  • データモデルのエンティティとして値型を扱う
    • 1対多の関係
  • ドメインモデルとしてはエンティティではない、あくまで実装の都合
    • データモデルからはエンティティとして扱うが、ドメインモデルでは違う
  • 代理キーを隠蔽 => レイヤースーパータイプ
    • IdentifiedDomainObject
      • 代理主キーを提供
      • クライアントからは見えなくする
    • IdentifiedValueObject
      • 値オブジェクト特化
      • 単なるマーカー => ソースコードにドキュメントの意味をもたせられる
    • やっぱり型が必要にみえる……Scalaがいいのかやっぱり

ORMでの、複数の値をテーブルの結合に格納する場合の扱い

  • Hibernateには、コレクションを連結テーブルに格納する機能がある
    • 値型そのものにはデータモデルのエンティティの特性を持たせる必要がない
    • コレクション専用のテーブルに永続化
    • 親エンティティの識別子を外部キーとして定義
    • この方法なら代理識別子は不要
  • Hibernateの<composite-element>タグ
  • 弱点
    • 代理キーが不要でも結合は必要
    • 値がnullになってはいけない
      • Setの場合を例に、削除できない場合が存在する
    • マッピング対象の値型の中に、コレクションが含めることができない
  • 筆者は制約がありすぎると判断

ORMでの、enumをステートオブジェクトとして利用する場合の扱い

6.7 まとめ

  • まとめなのでとばし

この辺りになると、Javaでの実装話が多くなってくるがこれを各プラットフォームでどう実現するか、などを考えると訓練になるかな。コレクションまわりの扱い方はORMにエンティティとして持たせるのが一番現実的だなぁという感覚。あとはドメインモデル中心に考えるとやっぱり非正規化して永続化するのがいいのかしらね。リポジトリの章でそのへんの話でてくるかな。