ドメイン駆動設計メモ
概要
ドメイン
問題解決の対象領域
モデル
問題解決のために物事の特定の側面を抽象化したもの
ドメインモデル
ドメインの問題を解決するためのモデル
データモデル
データの永続化方法を決めるためのモデル
良いモデル
問題を解決できる藻でrう
モデリングの流れ
ユースケース図
誰が何をするのかを明確にする
モデルリングするスコープを決める
ドメインモデル
代表的な属性を書く
ドメイン知識(ルールなど)を吹き出しに書く
箇条書きでOK(別途状態遷移図を作ってもOK)
オブジェクト同士の関連
多重度の定義
集約の範囲の定義
具体例(理解促進)
実装のポイント
ドメインモデルの知識を対応するオブジェクトに書く
ドメイン知識はドメイン層のオブジェクトに移譲する
そのオブジェクトを見ればドメイン知識(ルールなど)がわかる状態
生成条件の強制
コンストラクタかファクトリーメソッドでしかインスタンスを生成できないようにする
ミューテーション条件の強制
各属性のsetterはなくす
ドメイン層のオブジェクトにあるメソッドを利用して更新されるようにする
DDD固有のモデリング
集約
必ず守りたい強い整合性を持ったオブジェクトのまとまり
強い整合性確保が必要なものを1つの集約にする
ドメインモデリングにおいて、すべてのオブジェクトはいずれかの集約に属する
トランザクションを必ず1つにする
1つの集約のオブジェクトの取得・更新はリポジトリにおいて必ず集約単位にする
集約の中の1つのオブジェクトのみの取得・更新は許可しない
集約の境界の基準
整合性を確保する必要性の強さ
トランザクションの範囲の適切さ
大きすぎるとDBに不必要な大きいロックがかかる
境界づけられたコンテキスト
同じユビキタス言語が指すモデルを色々なコンテキストで統一するのは難しい
同じ言葉でもアクター・コンテキストによってイメージするものが異なる
コンテキストごとに境界を引いて、同じ名前のモデルを用いる(字面は同じでも中身は別物)
設計の基本原則
凝集度
1つのモジュール(クラス)における責務・データ・振る舞いの関連の強さ
「このクラスは何をするクラスか?」に対する答えとなるもの
1クラス内の尺度
結合度
複数のクラス同士が依存している度合い
複数クラス間の尺度
ドメイン層の実装
ドメインモデル(= ドメインオブジェクト、「モノ」を表現)
エンティティ
識別子で同値判定する類のもの。その他の属性値は可変
値オブジェクト
属性値で同値判定するもの。不変。
ドメインオブジェクトを使用するもの
ドメインサービス
「モデルをオブジェクトとして表現すると無理があるもの」の表現に使う
集合に対する操作
「メールアドレスが使用されているか?」は1人分のユーザオブジェクトではわからず、他のユーザオブジェクトの値も見る必要がある
できるだけエンティティと値オブジェクトで作り、カバーできない場合はドメインサービスを作る
リポジトリ
集約単位で永続化層へのアクセスを提供する
リポジトリは集約ごとに1つ
リポジトリに渡すものや返ってくるものは集約ルートのエンティティ
リポジトリはListのように扱う
リポジトリ層にドメイン知識を持たせないようにする工夫
ファクトリー
オブジェクトの生成ロジックが複雑な場合や、他の集約を参照する必要がある場合の生成責務をもつオブジェクト
ドメイン知識の表現のためにリポジトリを参照・使用する
ユースケース層の実装
ドメイン層のクラスが公開しているメソッドを組み合わせてユースケースを表現する
ドメインオブジェクトの生成・状態変更
リポジトリを使用した永続化
プレゼンテーション層への戻り値
プレゼンテーション層が扱うのに適した専用のクラスに詰め替えて返す
Data Transfer Object
このクラス内に変換処理を記述する(ドメインオブジェクトにドメイン知識を隠蔽するような感覚)
ユースケースクラスの分割単位
1クラス1パブリックメソッドとなるように分割する
こうすることでクラスの凝集度が高まる
CQRS(Command Query Responsibility Segregation)
複数の集約を含む情報の一覧画面を作る場合などの解決策
参照に使用するモデルと更新に使用するモデルを分ける(参照系のクラスと更新系のクラスを分ける)
部分的な導入でもOK
参照用モデルの型はユースケース層に定義する(ドメイン知識ではないため)