IDDD本読書メモ 12章リポジトリ①

腹筋しろよ

同僚氏がやっているIDDD本もくもく読書会#16でまとめたメモ。 内容の正否は検証してません。

メモ #

  • 集約とリポジトリが1対1で対応

  • インスタンスへの変更は永続化

  • リポジトリから削除したらインスタンスの取得は負荷

Evansより

  • 各型のオブジェクトで構成されるコレクションが、メモリ上にあると錯覚させることができるようにすること
  • オブジェクトの追加・削除を行うメソッドを提供すること
  • 属性値が条件に一致するような、完全にインスタンス化されたオブジェクトを提供すること
  • 集約にたいしてのみリポジトリを提供すること

複数の集約型がオブジェクトの階層を共有している場合、単一のリポジトリを共有している。

12.1コレクション指向のリポジトリ #

特徴

  • 古典的アプローチ(DDDのパターンとして示されていたアイデア)
  • コレクションを真似たもの、標準的なインタフェースをすべてシミュレート

集約

  • 一意な識別子を持つ
  • ルートエンティティに識別子が関連づけられている

重要なこと

  • リポジトリが真似るべきコレクション(HashSet)について理解しておくこと
  • 同じオブジェクトを複数追加できるようにしていはいけない
  • 永続化メカニズムは、クライアント向けの公開インタフェースには一切現れない
  • HashSetの特徴を兼ね備えた永続データストアを作ること

変更履歴を追跡する仕組み

  • 暗黙のコピーオンリード最終的にオブジェクト同士を比較して変更を確認する
  • 暗黙のコピーオンライト変更時に該当の場所へマークを付けていく

暗黙コピーはメモリ面でも速度面でも大きなオーバーヘッドになる

  • 明示的なコピービフォーライト
    • 「明示的な」とは、クライアントからユニットオブワークに対して変更をするつもりであるということを伝えなければならない

コレクション指向設計 #

コレクションを真似たインタフェースを定義する

  • インタフェースの定義は格納する集約型と同じモジュールに配置する
  • 実装クラスの置き場所は別のパッケージ
  • 戻り値はvoidとするほうが適切(トランザクションのコミット状況の影響を受けるかもしれないから)
  • addAllI()やremoveAll()は提供してもしなくても良い(コレクション内で順次やっても同じだから)

削除が好まれないケース

  • 法的関連で削除するのが好ましくない
  • 法的関連で削除ができない
  • 対応方法
    • 「無効」「使用不能」などのマークをつける
    • コードレビューでオブジェクトの削除を防ぎ、クライアントからの削除も行われないよう注意深くしらべる
    • 削除操作を出来ないようにするほうが楽

実装

  • 集約やリポジトリのモジュール直下のモジュールを使う
  • コラボレーションコンテキストでチームが選んだのはすべての実装クラスをインフラストラクチャへ置く方法
    • 依存関係逆転の原則論理的に他のすべてのレイヤの上位に位置し、下位のドメインレイヤへの単方向の参照を持つ
      • add, addAllにてSaveOrUpdateを使っておけば重複は発生しないしない
        • 同じもので、何度も更新してもこれらのメソッドは更新は何も行わないオブジェクトの状態を変更してあ、更新を暗黙のうちに追跡しているから
      • 例外はそのまま流さない。わかりやすいExceptionへWrapするか、ドメイン特化した例外を宣言して投げる
      • remove, removeAll
        • 1対1のマッピングを使った集約の削除
          • 関連するオブジェクトに変更を連鎖できない
          • 関連の両側にあるオブジェクトを明示的に削除しなければいけない。
          • ライフラサイクルを利用する手もあるが
            • 集約が永続管理するやり方は納得できない
            • 永続化はリポジトリにまかせておきたい
            • DDDのエキスパートは集約に永続化を管理させる手法は使わないモノ