Domain Modeling Made Functional / 関数型ドメインモデリング ドメイン駆動設計と F#でソフトウェアの複雑さに立ち向かおう
1. Introducing Domain-Driven Design
DDD の最終ゴールは、全ての関係者が同一のメンタルモデルを使って話をすること。 これにより、早く価値を届け、高い価値を生み、無駄をなくし、保守と拡張を容易にすることができる。
やるべきことは 4 つ。
- ビジネスイベントとワークフローに着目する。データ構造ではなく。
- ドメインをサブドメインに分割する
- サブドメインのなかでモデルをつくる
- 共通言語を作って使う
ビジネスイベントを通じてドメインを理解する
ビジネスは、ある一時点のデータだけでは表現できないし価値も持たない。
ビジネスは、データを別のデータに変換していく 一連のワークフローにより表現され、そこにこそ値があるといえる。
この変換を引き起こすきっかけをドメインイベントと呼ぶ。 ドメインイベントは常に「〜が起こった」のような過去形で表現される。
例:
- イベント: 「顧客が注文ボタンを押した」
- ワークフロー:
- 注文内容の検証
- 在庫の確認と引き当て
- 決済処理
- 出荷指示の作成
- データ変換:
- 注文状態: 「カート」→「確定済み」
- 在庫数: 減少
- 顧客情報: 購入履歴に追加
ドメインイベントの発見にはイベントストーミングという手法が有効である。 イベントストーミングは以下を目的とする。
- 関係者全員で共有できるモデルを作る
- 関係者全員に当事者意識を持たせる
- 仕様の齟齬を見つける
- 部署間の接続がどうなっているか見つけ出す
- 帳票の必要性を明らかにする (=> 過去の出来事を知る必要性)
イベントを洗い出すときには、少ない範囲で満足せず、 可能な限り端まで拡張して見つけ出すことを心がける。
イベントを引き起こす要因をコマンドと呼ぶ。 コマンドは常に命令形で表現される。 コマンドはワークフローを通じて別のイベントを引き起こす。
- Command: "Place an order" -> Place Order というワークフロー -> Event: "order placed"
- Command: "Send shipment" -> Send Shipment というワークフロー -> Event: "shipment sent"
全てのイベントがコマンドから発生するわけではなく、 スケジュールされたイベントや外部システムからの通知によるものもある。
ドメインをサブドメインに分割する
ドメインとは「密接に関連する知識の範囲」である。
もっとざっくりいうと、ドメインとは専門家が存在する分野のこと。 その専門家が実際に行っている仕事の範囲がドメインである。
例えば「請求」というドメインについて考えるなら、請求部門の人たちがやっている仕事の範囲がドメインである。
現実世界のドメインは、互いにほんの少しだけ重複するベン図として表現できる。
Bounded Contexts を使ってソリューションを作る
現実世界のドメインをソリューションの世界に持ち込むとき、 ドメインはBounded Contextsとして扱う。
なぜコンテキストかというと、コンテキストから切り離された情報は混乱を招いたり役に立たなかったりするからである。
なぜ境界を作るかというと、相互依存を排して保守性を高めるためである。
現実世界とソリューションの世界のドメインは必ず 1 対 1 で結びつくわけではない。 1 対多になることもあれば、多対 1 になることもある。
Bounded Contextを正しく作るのは科学ではなくアートの世界だが、いくつかの基準はある。
- ドメインエキスパートに聞く
- 既存のチームや部署の構成を参考にする (参考にするだけ)
- 境界をはっきりさせ、適切なサイズにする
- コンテキスト単位でチームが自律できるようにする
- ワークフローがコンテキストをまたがないようにする