DDDの戦術モデリング
去年の夏前くらいにDDDまわりの勉強していた。でこのメモを書いていたので少し直して晒してみる。 前回の続編。
他のメモではアーキテクチャやフレームワークとの関わりの中でDDDの戦略的なモデリングについて言及している。
ここではDDDでの設計アプローチを簡単に説明してから、戦術的なモデリングで紹介されているパターンや用語について整理する。
設計方針
ドメイン駆動設計(DDD)では、対象ドメインに最も詳しい人(ドメインエキスパート)と協力体制を組み、ドメインをうまく表現する言語(ユビキタス言語)を作り上げる。
そして、アプリケーションの設計はこのユビキタス言語と対応させると考える。 ユビキタス言語と対応をとるがプログラミング言語にユビキタス言語が合わせることはしない。 もちろんユビキタス言語も技術的な背景を受けて調整はされるものの実装を真に受けるわけではない。
例えば、あるコンセプトをプログラミング言語がサポートしておらずフレームワークやデザインパターンを利用することにしても、ユビキタス言語を実装レベルの表現に分解したりはしない。
DDD本では具体例としてJavaを使っている。そして設計はJavaに影響を受けている。 また FDM本 では基本的にイミュータブルに実装するために Model,Service,Interpreter を基本にアプリケーションを設計する。永続化などは全て Interpreter が担当する。その場合でもユビキタス言語は大きく影響されない。
モデルの構成要素
ユビキタス言語に登場する構成要素(オブジェクト)は色々あるが、とりあえず大きく4つのグループに分類してみた。
ものを指すオブジェクト, オブジェクトのライフサイクルに関わるオブジェクト, オブジェクトの利用に関わるオブジェクト, オブジェクトを集めたオブジェクト。
ものを指すオブジェクト
これは具体的でも抽象的でもものを指すオブジェクトのグループ。 例えば、ユーザーやルールなどを表す。
これらのオブジェクトは互いに関連を持ち参照し合う。 特に重要なのは集約で一貫性を保つ境界になることが期待される。
要素 | 特徴 |
---|---|
エンティティ | ライフサイクルがあり属性と独立した同一性があるもの |
値 | 同一性が属性から導けるもの |
集約 | 一貫性を保つ境界を為し内部にエンティティ,値を保持する |
ライフサイクルに関わるオブジェクト
エンティティ,集約にはライフサイクルが存在する。これらの生成,永続化に関わるオブジェクト群がある。
要素 | 特徴 |
---|---|
ファクトリ | 生成を担当する |
リポジトリ | 永続化,検索などを担当する |
利用に関わるオブジェクト
単一のエンティティ,集約に属すと捉えにくい機能や計算などを表現するための要素がいくつかある。
要素 | 特徴 |
---|---|
サービス | 複数の値やエンティティを受け取り計算や変更を行う |
ドメインイベント | 何かの操作や変更を表現する |
ドメインイベントパブリッシャー | ドメインイベントの発行者 |
ドメインイベントサブスクライバー | ドメインイベントの購読者 |
イベントストア | ドメインイベントを格納するキュー |
イベントストアはドメインの内部/外部へのトピックとして機能する。 ドメイン内部をリアクティブに実装したりシステム外のPub/Subにメッセージを発行して他のコンテキストと連携したりさせるのに用いる。
集めたオブジェクト
同じコンテキストの中でもより関連の強いもの弱いものが出てくる。 それらを整理するために用いられる。
要素 | 特徴 |
---|---|
モジュール | 関連の強いオブジェクト群を集めた単位 |
ものを指すオブジェクトに現れるパターン
DDD本ではいくつか典型的なパターンを紹介していた。 オブジェクト指向でのデザインパターンを参考に持ってきているが技術的な工夫のパターンではなく概念の関係として使える ということが重要と書かれてた。
紹介されていたのはストラテジ,コンポジットの2つ。デザインパターンの同名のものと同じでクラスの関係ではなく概念の関係だよって強調されているだけ。
パターン名 | 概要 |
---|---|
ストラテジ | オブジェクトが別のオブジェクトの振る舞いを表現している |
コンポジット | オブジェクトが同種のオブジェクトで再帰的に構成されている |
深い洞察をもつ設計へのアプローチ
DDD本の3部では、わかりやすく汎用的なユビキタス言語と伴うプログラミングのコンポーネントの設計をどのように育てるかについて割いていた。
ここでは方針やテクニックだけ列挙する。
- 意図の明白なインタフェース
- 副作用のない関数
- 表明
- 概念の輪郭
- 独立したクラス
- 閉じた操作
自分用に言い換えてみる。
高凝集,疎結合を目指しましょう。 インタフェースは約束を明記するべきで実装は書かないようにしましょう。 関数が引数の要素の一部を書き換えるのはやめましょう。 集約の操作にはアサーションを入れて規約を厳格化しましょう。 操作や関数の返り値が引数と同じ方になるように演算体系を作りましょう。 そうやってDSLを作っていきましょう。
感想
基本的な問いは下の3つ。
- チームで共通のイメージを持てるか?
- それを促す言葉を作れているか?
- その言葉は使い勝手がよく適切な表現力を伴っているか?
互いに理解ができる言語体系がなければ実装は更に曖昧なものになる。そして実装から明らかにされたことをその体系に反映しないとならない。
そうだねって感じ。
でも実装の際には別の面からの難所が生まれるよなぁと思った。 そのあたりは別の機会で書こうと思う。