ドメイン駆動設計(DDD)

集約
集約とは、「必ず守りたい強い整合性を持ったオブジェクトのまとまり」のこと。
ルール1:トランザクションを必ず 1 つにする
必ず集約単位でリポジトリから取得し、集約単位でリポジトリに渡す。
そして、1 トランザクションで集約内のすべてのオブジェクトを更新する。
つまり、集約の中の一部オブジェクトのみの取得/更新は許可しない。
用語1:集約ルート
集約の親となるオブジェクトのこと。1つの集約につき1つ決める。

凝集度と結合度
高凝集・低結合を意識する。
責務とは、「このクラスは何をするクラスか?」という問いに対する答え

ドメイン層
ドメイン知識(ルール・制約)を表現する。
他の層への依存を持たせないようにする。
主なクラス
ドメインオブジェクト
- エンティティ
- 値オブジェクト
- ドメインイベント
上記の利用クラス
- リポジトリ
- ドメインサービス
- ファクトリー
ドメインサービス
「モデルをオブジェクトとして表現すると無理があるもの」
例)ユーザーメールアドレスの重複チェック
一つのユーザーオブジェクト自身ではわかり得ない。
ただし、極力エンティティと値オブジェクトで実装するようにして、どうしても避けら
れない時にのみドメインサービスを使うようにする。
リポジトリ
「集約単位で永続化層へのアクセスを提要するもの」
- インターフェースがドメイン層
- その実装クラスがインフラ層
設計上のポイント:「リポジトリはListのように扱う」
ドメイン知識を持たないようにする。
add, find するなどの使い方となる。「ユーザー登録する」「ユーザーを退会状態にする」というメソッドは持たないはず

ユースケース層
ドメイン層が公開している操作を組み合わせてユースケースを実化nさせる。特定のクライアントには依存しない実装とする。
主なクラス
- ユースケースクラス
- プレゼンテーション層との入出力を定義するクラス
ユースケースからの戻り値クラス:DTO(Data Transfer Object)
DTO のメリット・デメリット
- メリット
- ドメインオブジェクトにプレゼンテーションに関連する処理が混入することを防げる
- ドメイン層の修正の影響をプレゼンテーション層が直接受けなくなる
- デメリット
- ドメインオブジェクトからの整形、詰替えコストが発生する
ユースケースで専用の型定義をしてあげないと、ドメイン層にドメイン知識以外の責務を持ってしまう懸念がある。

プレゼンテーション層
アプリケーション外部との入出力を実現する。
JSONでレスポンスを返したり、HTMLをレンダリングして返す、といった選択はこの層の責務。
主なクラス
コントローラーやアプリケーション外部との入出力を定義するクラス

インフラストラクチャ層(インフラ層)
下位のレイヤー(ユースケース層、ドメイン層)で定義されているインターフェースを実装。アプリケーションを支える技術的な機能を提供する。

メモ
エンティティは不変、値オブジェクトは可変

CQRS(Command Query Responsibility Segregation: コマンドクエリ責務分離)
「参照(取得)に使用するモデルと更新に使用するモデルを分離する」という設計
クエリサービス
ユースケースに特化したクエリを返す

DDDにおけるモデルの概念
- ドメインモデル: ドメインの問題を解決するためのモデル
- データモデル: データの永続化方法を決めるためのモデル
※ 基本的にドメインモデルの文脈で説明する
どの要素を取り込むか、という選択をするプロセスが抽象化であり、その成果物がモデルということになる。
データとして持ちそうなもの
- 名前
- 経歴
- 志望理由
- 顔写真
データとしてもたなそうなもの - 筆跡、筆圧
- 履歴書のメーカー
- 履歴書を書いた時の気持ち
これらを取捨選択する過程が正規化

良いモデルとは?
「良いモデルとは、問題を解決できるモデルである」
つまり、ドメインに詳しくないとどれだけ良いコードで実装ができても解決できないアプリケーションが出来上がってしまう可能性がある。

良いドメインモデル
そのクラスを見るだけで全てのオブジェクト生成、状態遷移パターンがわかるようになっていると良い。
public
なセッターをなくして、クラス外部から想定外の値を設定すことを禁止する。
重要な基本方針
常に正しいインスタンスしか存在させない(ありえない状態のインスタンスを存在させてはいけない)
インスタンス生成時に整合性が保証されている状態で生成されるようにする。
ドメインモデルの知識を対応するオブジェクトに記述する
値を更新する時の条件、ルールを強制する。
public
なセッターをなくして、
「タスクを延期する」関数などを用意してあげてタスク延期のルールを守った状態で関数に処理を書いてあげるようにする。

Application 層 UseCase の作り方
基本的に
- 何をしたいか(What)だけを示すように
- 実装上どのように実現するか(How)は隠蔽する