Help us understand the problem. What is going on with this article?

DDD本6章を読んでこのように理解しました

はじめに

エリック・エヴァンスのドメイン駆動設計(2004)の第6章 「ドメインオブジェクトのライフサイクル」を読んで自分的に理解したことを書き出す
結構自分の考えと混じってしまってるので、ここに書いてあることイコール本の内容ではないです

自分の理解の足りないところやおかしいところはバシバシ突っ込んでもらいたいです:bow:

他のまとめ

対象者

  • 古いシステムからリプレイスする人
  • リリース優先で作った際のリスクを見ておきたい人
  • 設計をしていなくて雰囲気で物を作っている人
  • エリック・エヴァンスの本を読むと抗えない眠気に襲われる人

ざっくりどんな話?

すべてのドメインオブジェクトにはライフサイクルがあります
生成、状態変遷、最終的にアーカイブまたは削除のようなライフサイクルが一般的でしょう

オブジェクトのライフサイクルがメモリ上で完結していると問題はないのですが、RDBにデータを格納したり、キャッシュしたりする場合オブジェクトの扱いが複雑になり、こうしたオブジェクトを管理するにあたって2つ課題がでてきます

  1. ライフサイクルを通じて整合性を維持する
  2. ライフサイクルを管理するのが複雑でも、モデルが侵食されないようにすること

この2つの課題に対応するためにAggregates、Factories、Repositoriesの3つのパターンを使用し対応していきます

Aggregatesパターンによってライフサイクルのすべてのフェーズにおいて整合性を担保させる

Factoriesパターンによって内部構造をカプセル化させる

Repositoriesパターンによって永続化されたオブジェクトにアクセスする手段を提供することとインフラストラクチャをカプセル化させる

この章ではドメインオブジェクトのライフサイクルを簡潔に保つ3パターンを共有していました

以降では大事だと思ったAggregates、Factories、Repositoriesを深掘りしていきます

3つのパターン

Aggregates(集約)

Aggregatesとは関連するオブジェクトの集まりであり、データを変更するための単位として扱われる

各AggregatesにはAggregate Root(ルート)とAggregate Boundaries(境界)がある

Aggregate Root(ルート)

  • 集約に含まれている特定の1つのエンティティ
  • 不変条件をチェックする責務を負う
    • 集約境界の内部に存在するオブジェクトに対する変更がコミットされるときには、集約全体の不変条件が全て満たされていなければいけない
  • 境界内部に存在するオブジェクトへの操作の責務を負う
    • ルートエンティティは集約内部のエンティティへの参照を他のオブジェクトに渡せるが、受け取ったオブジェクトは参照を一時的に使用することができるだけで、その参照は保持してはならない
    • データベースに問い合わせて直接取得できるのはルートのみ、それ以外のオブジェクトは関連をたどることで取得する必要がある
  • 外部オブジェクトが参照を保持できるのはルートのみ
  • 境界内のオブジェクトは互いに参照を保持し合っても良い
  • ルート以外のエンティティは局所的な同一性を持っているが、その同一性は集約内部でのみ識別できれば良い
  • 値オブジェクトのコピーを別のオブジェクトに渡せるがその場合は、そのコピーは集約との関連がないためどうなっても良い

Aggregate Boundaries(境界)

  • エンティティと値オブジェクトを集約の中にまとめ、各集約の周囲に境界を定義すること
  • これがトランザクションの単位となる
  • 各集約に対してルートとなるエンティティは1つ
  • 集約内部のオブジェクトは他の集約ルートへの参照を保持できる
  • 削除の操作は、集約境界内部に存在するあらゆるものを一度に削除しなければならない

ddd-p126.png
(Eric Evans, 2004)

集約について考慮する際にはトランザクションやデッドロックなどを考慮し境界を定めていく、その過程でドメインモデルの更新もありえる

上記を行うことでドメインモデルに対してmoduleによって境界をあたえることができ、そのmodule内でオブジェクトの依存を集約しているものがルートにあたる

Factories(ファクトリ)

インスタンス生成のためのアクセスポイントを提供する必要があり、そのスコープは明示的に定義する必要がある

アクセスポイントはコンストラクタの場合もあるがより複雑な生成工程が必要な場合はファクトリを導入するとよい

ファクトリは生成と再構成というライフサイクルの変遷をカプセル化する

導入

そもそもどういったときにファクトリを導入するのかについて何個かパターンを出して、妥当なのかどうかを見てみる

  • オブジェクト自体にオブジェクトの生成を任せる
    • モデルによってはあり、ただし複雑な組み立て操作は生成されるオブジェクトの責務としてはおかしい
    • 複雑なオブジェクトの生成はファクトリを用意する
  • オブジェクトの生成をクライアントに任せる
    • 組み立てられるオブジェクトと集約のカプセル化に違反
    • クライアントと密結合になる

まとめるとオブジェクトの生成はドメイン層の責務であり、単純な生成はコンストラクタを利用すればいいが複雑なオブジェクトの生成の場合はそのオブジェクトの責務を逸脱するのでファクトリを用意する

配置

ファクトリを生成するのは、詳細を隠蔽したいと思うものを構築するためであり、ファクトリを配置するのは制御を行わせたい場所である
このような決定は集約を中心として行われる

集約の観点で着目して、ファクトリ実装について見てみると2つのパターンがでてくる

  • 独立したファクトリ
    • オブジェクトがファクトリメソッドをもつのが責務としておかしい場合に選ぶパターン
    • 通常は集約全体を生成してルートへの参照を渡し、生成された集約への不変条件が必ず強制されることを保証する
    • 集約内部のオブジェクトがファクトリを必要とし、ルートがそのファクトリの置き場として正しくない場合はその集約用のファクトリを用意する
  • ファクトリメソッド
    • オブジェクトにファクトリメソッドをもたせる
    • ファクトリメソッドを持つオブジェクト以外のオブジェクトの生成を行う場合もありうる

コンストラクタ

コンストラクタは単純である必要があるため、コンストラクタ内で他のクラスのコンストラクタを呼び出してはいけない

Repositories(リポジトリ)

オブジェクトは生成された後に、RDBなどに一度格納されまたそのオブジェクトに対して操作やそのオブジェクトを利用する場合にRDBから取得されオブジェクトとして再構成される

オブジェクトの生成、再構成に関しては前述したファクトリパターンが利用されるがその間の永続化の部分にはリポジトリパターンを利用できる

ちなみに今回はRDBを例として出したが、永続化=RDBではなくキャッシュやキューイング、外部API呼び出しもここに含まれる

リポジトリとは

クライアントが必要とするのは、すでに存在するドメインオブジェクトへの参照を手にいれる手段である

リポジトリではデータベース接続やクエリ等の永続化技術の部分をカプセル化することである

実装

  • ドメインオブジェクトを引数、返り値として利用する
  • クライアントから切り離す利点を活かすこと
    • 永続化の戦略をいつで気切り替えられるようにすること
    • 本番はRDBを使うがテスト時はインメモリに切り替えられるなど
  • トランザクション定義をクライアントに委ねる
    • コンテキストによってトランザクションの範囲は変わるためリポジトリに持たせるのはおかしい
  • ファクトリを導入する場合はリポジトリの生成処理を委譲する形になる
    • ファクトリはオブジェクトを一から生成するもの、リポジトリは左記を含みつつ、古いオブジェクトを再構成する機能なども持つのでファクトリを導入する場合はリポジトリの生成処理を移譲するのがよい

注意点

  • ドメインモデルの分析モデルとデータベース設計の設計モデルの分離を避ける場合は、データベース設計のほうで選択的な非正規化などを選ぶ必要がある
  • クライアントとリポジトリは密に結合していないので例えば別々の人で開発を行うことができるかもしれない、その場合は性能面で気をつける必要がある

最後に

ドメインオブジェクトのライフサイクルに関するパターンを紹介した章でした
特にリポジトリの部分は性能面を気をつけつつも設計はきれいにしたいという部分が難しそうですね

7章は4~6章で学んだパターンをつかってドメインモデルをブラッシュアップしていく過程を紹介している章なのでまとめは行わない予定ですので是非1読してみてください

第2部はこれで終了です。ありがとうございました

mfykmn
AWS、Terraform、Kubernetes、Docker、CircleCI、etc... ここらへんをよく触ります DevOpsを整える仕事が最近多く、これからSRE的な部分を学習していきます〜
http://mafuyuk.com/
bell-face
BtoBセールスに特化したインサイドセールスシステム、ベルフェイスを開発・運営しています
https://bell-face.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away