小さなオブジェクトで ドメインモデルを組み立てる
Qcon Tokyo 2013
2013年4月23日
有限会社 システム設計 増田
ドメイン駆動設計 実践ガイド
Domain-Driven Design (DDD)
ドメイン駆動設計
コンセプト編 1. 業務アプリケーション 2. 開発の難しさ 3. ドメイン駆動設計のアプローチ
業務アプリケーション • データの種類と量
• ユーザの役割と権限
• 履歴データ:記録、参照、照合、…
• 通知・連絡・報告とルーティング
• 予定(未来)の管理
• 状態遷移
• 状態+権限に依存した制約ルール
• 人間の判断待ち
…
開発の難しさ • 複雑さ
– 権限、状態、区分、… 組み合わせ – 例外規定、救済ルール
• あいまいさ – ビジネス=人と人との相互作用 – 決め事・調整ごとの積み重ね – 暗黙の前提
• 不確実性 – ビジネス環境の変化 – 事業の変化 – 人の異動、組織の変更
• 複雑さに立ち向かう
• あいまいさに光をあてる
• 不確実性を受け入れる
ドメイン駆動設計
アプローチ • 「概念モデル」をそのまま実装
• ドメイン層の独立
• モデルの継続的な改良
概念モデルをそのまま実装 • 名前
– パッケージ名、クラス名、メソッド名、…
– 業務用語に合わせる (粒度、関連性)
• 業務の構造に合わせる – 業務手順
– サービスポリシー、キャンセルポリシー、…
– 会計ルール、管理会計、評価基準、…
• 現実主義 – 実装の都合・制約からのフィードバック
– 設計判断
ドメイン層の独立 • 関心事の分離
– 業務の関心事と実装の関心事
– UI、データベース、通信
• 依存関係の逆転 – 他の層がドメイン層に依存
• DIP : Dependency Inversion Principle
– 例:永続化(データベースアクセス) • ドメイン層でインタフェース宣言:業務のやりたいこと
• データアクセス層で実装:実装技術依存コード
ドメイン層の継続的改良 • モデルの深化
– ドメインの理解度の深まりを継続的に実装に反映
– 機能追加やバグ修正が、ひとつのチャンス
• モデルの変化
– ビジネスモデルの変化を反映し続ける
• コミットログ(変更理由)は業務の言葉で
– 不要・無効になった概念・ルールを丁寧に除去
実践編 4. アプリケーション・アーキテクチャ 5. ドメイン層の設計パターン 6. リッチなドメインモデル 設計スタイル
お断り:Java/Spring フレームワークでの実践例です。
アプリケーション アーキテクチャ
構築モデル
アプリケーションサーバー
アプリケーション フレームワーク
アプリケーション ロジック
アプリケーションコンテナ ディスパッチャ イベントリスナー
Web MVC バリデーション O-Rマッピング テンプレートエンジン
独自に開発
再利用
再利用
@Autowired
ドメインモデル
イベント駆動の実行モデル
ブラウザ, Web API
HTTP リクエスト
メール
受信メール自動処理
非同期 メッセージ
サービス間連携
アプリケーションサーバー Tomcat
メッセージング Active MQ
サービスコンテナ Mule ESB
メールサーバーJames
Mailet コンテナ
Servlet コンテナ
サービス
業務イベント
ユースケースの実装
業務知識 ビジネスルール
マクロな業務手順 (トランザクションスクリプト)
問題領域の オブジェクトモデル
サービス起動トリガー
リッチな ドメインモデル
シンプルな ドメインモデル
ドメイン層の2つの
実装スタイル
手続き型 記述
オブジェクト モデル
リッチな トランザクション
スクリプト
シンプルな トランザクション
スクリプト
大きい(たくさんのインスタンス変数) データの入れ物(getter/setter) テーブルと対応 小さい(1つ2つのインスタンス変数)
データ+ロジック テーブルのカラム
設計パターン リッチなドメインモデル
日付
期間
予定日
有効期限
場所
地域
商品種類
形状
単価
数量
税率 型式
翌月 拠点
キャンペーン
Event (出来事)
シンプルなトランザクションスクリプト
Reference (参照/追跡)
Repository (記録)
Transfer (通知)
Policy (判断) (制約)
部門
役割
担当者
ファンダメンタルなオブジェクト
端数
超重要
ここが 育つほど 楽になる
ユースケースの実装
基本 オブジェクト
ドメイン層の基本オブジェクト
Event (出来事)
Service (業務機能)
Reference (参照/追跡)
Repository (記録)
Transfer (通知)
Policy (判断/制約)
トランザクションスクリプト ファサード(実際の仕事はドメインオブジェクトに任せる)
問題領域の出来事を表すオブジェクト イベント種別、いつ/だれが/何を
記録と参照の業務ニーズの表現 インタフェース宣言(実装は、データソース層で)
通知の業務ニーズの表現 インタフェース宣言(実装は、データソース層で)
関心事の「識別」(参照番号、管理番号、追跡番号、…) 関連オブジェクトの集約ルート(値オブジェクトの集約)
ルールの集約 (プライシング、キャンセル、オーバーブッキング、…)
ファンダメンタルなオブジェクト リッチなドメインモデルの構築基盤
日付
期間
予定日
有効期限
場所
地域
商品種類
形状
単価
数量
税率 型式
翌月 拠点
キャンペーン
部門
役割
担当者
• 業務モデルを表現する基本語彙集 • ビジネスルールの基本ロジック 日付計算、形式チェック、区分の列挙、… • プログラミング言語のプリミティブな型のラッパー
端数
役に立つ ドメインオブジェクト
良い名前
小さく
ばらばらに
良い名前の見つけ方
正しく使う(言葉を使って相手の反応をみる)
言葉を組み合わせてみて反応をみる
似た言葉を使い分けて反応をみる
名前の宝庫(初日に見つける) ・その分野のガイドブック ・類似サービスのヘルプ画面 ・類似パッケージソフトのカタログ (英語版ならクラス名の宝庫)
頻度、重要度、関心度、…
語彙を増やす 読む/調べる 聴く/尋ねる
小さく作る クラス 50行以内 メソッド 3行以内 パッケージ 10ファイル以内
これを超えたら、 分割を考える習慣をつける。
3行メソッド
register( order ) { verify( order ); record( order ); notifyTo(shippingSection); }
こういうのが良い感じ
小さく作る狙い
作りやすい わかりやすい 使いやすい 捨てやすい
業務の言葉をオブジェクトで
プログラミング言語の基本データ型 (Date,String, BigDecimal, Long, …)
をラップした 業務の基本用語ごとのオブジェクトに、
その用語に関するデータとロジックをまとめる。
日付 (時分秒を持たない) 時分(秒を持たない) 翌営業日, 休前日 月末,月初, 四半期, 半期, 年度 期間 有効期限 予定日 期限切れ一週間前のアラート 前日のリマインダ …
金額 単価 数量,数量単位,換算 消費税,税率,端数処理 合計,小計,総合計 数量割引 キャンペーン価格 季節料金 キャンセルポリシー …
管理番号,登録番号 取引先コード 取引区分 契約番号 商品番号 型式コード 製造番号 シリアルナンバー …
用語の粒度=オブジェクトの粒度
委譲メソッド 面倒でも隣人とだけ話す × person.contactInfo().phones().mobile() ◎ person.primaryContact()
ばらばらにする習慣
実装継承 控え目に。もっと控えめに。
パッケージ階層 フラットに。もっとフラットに。
• 構造を安易にコードに埋め込まない。 • 初期の構造はまちがっていることが多い。 • 構造の変更を簡単にする準備をしておく。
構造の変更に備える
ビジネスロジックの カプセル化
• if 文/switch 文を使わない
• for 文を閉じ込める/使わない
if 文 / switch 文を使わない
• 列挙型(enum)
–区分、種別、カテゴリー、エリア、… – EventType, StateType, Category, …
– タイプごとの振る舞いを if 文なしに記述
• Strategy/State パターン • たとえば、「未記入」や「不明」の表現→ MissingObject パターン
• Map, Set
…
for文を閉じ込める/書かない • ファーストクラスコレクション
– コレクション変数は単独でラッピング
• List<Order> orders ; → class Orders
– for 文を使ったロジックの集約と整理
• コレクション操作の副作用の撲滅
• for 文を書かない – コレクション API の活用
– Comparable/Comparator の実装
– equals()/hashCode() のオーバーライド
ドメインオブジェクトの
組み立て方 • サービスクラスを起点に
– サービスクラスはマクロな業務手順(数行)を記述 – 判断・分岐・導出は、ドメインオブジェクトに委譲
• フレームワーク(Inversion of Control) – 組み込み済の制御構造
• Web MVC、 バインド&バリデーション • O-R マッピング、 O-X マッピング • 例外ハンドラー
– @Autowired • パターンマッチング、命名規約、アノテーションで自動で組み
立ててくれる。
参考情報 7. 設計と実装のスキルアップ 8. ドメインモデルの開発スタイル 9. 問題領域の把握手法 10. 開発プロセス
設計と実装のスキルアップ
エクササイズ 9つのルール 小さく作る
・メソッドの構成 ・オブジェクト間の特性移動 ・データの再編成 ・条件記述の単純化 ・メソッド呼び出しの単純化
実装の原則
ドメインの理解 言葉の力 モデル駆動
設計のスタイル
For Thoughtful Developer Leading Designer
オブジェクト指向
基礎訓練
・クラス ・振る舞いとメソッド ・状態とコレクション
設計の改善
責任割当の原則 GRASP
責任駆動設計 役割ステレオタイプ
契約による設計
リファクタリング
モデリング プログラミング
イテレーティブで発見的な活動
ドメインモデルの開発
三位一体
リレーションシップ駆動 要件定義(RDRA)
・コンテキストモデル ・業務フローモデル ・イベント/状態モデル
ICONIX
・ドメインオブジェクトの発見 ・ドメインモデルの育て方 ・ロバストネス分析
ビジネスルールの発見と定義
業務フロー図から ドメインモデルから イベント/状態モデルから
問題領域を把握する
初期のラフモデルを 2時間以内で描く
モデル間を関連づけ 整合性と網羅性を確保
ユースケースと 実装のギャップを埋める
それぞれのモデルから ビジネスルールを抽出する ヒントとテクニック
ドメイン駆動の開発プロセス
業務フロー
モデルの改良
要約、骨格
画面・帳表 ユースケース
属性の追加 モデルの洗練
イベント 状態遷移
データモデル
初期の ラフモデル
コンテキスト図
手がかかり
初日からドメインモデルの設計と実装
ロバストネス分析
必要ならシーケンス図
操作追加
Java ソース
基盤クラス追加
DDL/SQLソース
問題領域の把握
構造化用語集
Domain-Driven Design (DDD)
ドメイン駆動設計
まとめ
アプローチ • 「概念モデル」をそのまま実装
• ドメイン層の独立
• ドメインモデルの継続的な改良
役に立つ ドメインオブジェクト
良い名前
小さく
ばらばらに
Recommended