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