目次
DDDは難しい
WebでMVCとか学ぶと嫌でもドメイン駆動設計(DDD)という単語を目にします。
私自身DDDするものだという認識でMVCを学んでしまったため、ドツボにハマりました。 ドメインモデル貧血症...、外形化する各レイヤー...、そんな苦しみの中、とある方からオススメの本を教えてもらいました。
ひとまず、これから読むと入りやすいかも? https://t.co/aNSxotObqN
— Atsushi Nakamura (@nuits_jp) January 7, 2019
なので読んで学んだことをまとめたいと思います。
そもそもドメイン駆動設計とは?
一言で言うと『業務知識を適切な形にモデリングしたドメインモデルを中心とする設計手法』です。
ドメイン駆動設計によく出てくるドメインモデルは業務知識をモデリングしたものだったんですね。
これを知るとデータを格納するプロパティしかないクラスがドメインモデルではないことが分かります。 (一番初めは私もそう勘違いしていました)
ドメイン駆動設計を導入すると大きく以下のメリットが得られます。
- 業務側の視点も踏まえた設計が可能
- 属人化の防止や知識継承の容易化
- ドメインエキスパートとエンジニアのコミュニケーションの円滑化
ここで、本書(わかる!ドメry)では業務知識に精通した人のことをドメインエキスパートと呼んでいます。 ドメインエキスパートのドメインは以下のような意味を持っています。
- システムを使用するユーザの活動や関心に関係する領域
- 組織がおこなう事業やそれを取り巻く世界
- 組織がおこなう事業のノウハウの領域や進め方の方法
ドメイン駆動設計の一番の目的は「ドメインを可能な限りコードへ反映させること」にあります。
ドメインがコードに適切に反映されているということはそれだけ業務側の視点が反映されているということになります。
また、コードからドメインが読み取れるのであれば、担当者が闇落ちしてしまってもコードを読んで引き継ぐことが可能です。
さらに、コードからドメインが読み取れるほど反映されていれば、機能追加・改修の対象コードや処理内容の意図について、 実装者ではなくドメインエキスパートが答えることも出来るようになります。
実装者本人やエンジニア職でなくても実装を理解出来るというのは非常に大きいメリットと言えます。
ドメインモデルってどうやって定義するの?
ドメインモデルを定義するに当たって、ドメイン駆動設計には戦略的設計と戦術的設計の2つのアプローチがあります。
- 戦略的設計
- ユビキタス言語
- 境界づけられたコンテキスト
- コンテキストマップ
- 戦術的設計
- エンティティ
- 値オブジェクト
- サービス
- レイヤー化オブジェクト
- etc...
戦略的設計は考え方や概念によるアプローチ、戦略的設計は技術的なアプローチになります。 これらは片方だけすれば良いものではなく、両方うまく組み合わせることでドメイン駆動設計の効果を最大限に発揮します。
「わかる!ドメイン駆動設計」では主に戦略的設計について記述されていました。 (おそらく戦術的設計については次巻が出ると思います)
戦略的設計は以下の流れで行い、概念部分の定義を行います。
ユビキタス言語
ユビキタス言語とはチームで共有すべき共通言語の事を指します。
ユビキタス言語が定まっていない場合、同じ概念を指している単語が複数出来てしまい、これにより機能の重複が起こる可能性があります。
ユビキタス言語は名詞とは限りません。動詞や形容詞の可能性もあります。
ユビキタス言語は以下の手順で見つけます。
- ドキュメントから調べる
- 同じものを表す用語が複数ある
- 概念はあるのに名前はない
- ビジュアルはあるのに名前はない
- ドメインエキスパートの発言から調べる
- 「〜することを想定している」
- 「〜したいですね」
- ピックアップした単語を議論して確立させる
- 業務に必要な名詞の列挙
- 名詞に紐付く動詞、形容詞の列挙
- 名前がなかったり曖昧な概念に名前をつけて確立させる
- 5W1Hをはっきりさせる(誰が、何と同じか、何を持つか)
ドメインモデル
ドメインモデルとはドメインを適切に反映した、コードに落とし込む前の概念的なモデルの事を指します。
ドメインモデルはユビキタス言語から構成されます。そのため、ドメインモデルには名前(名詞)とその関係性、振る舞いが含まれています。
また、ドメインモデルはドキュメントによって体系化すべきではありません。最終的なドメインモデルはコードに息づくものなので、リファクタリングによって日々洗練されていきます。そのためドキュメントでの管理は難しいわけです。
リファクタリングによって洗練させる例として本書では以下のようなコード例がありました。
// 1: よくない例 var food = new Food(); food.Name = name; food.LimitDate = limitDate; food.CreatedAt = DateTime.Now; foodManager.registerFood(food);
上記のコードは「食品」ドメインの「アプリに食品を登録する」という振る舞いを表すコード例です。
上記では...
- 呼ぶ側が登録日時を指定しないといけない
- Foodに識別子がない
- 「登録のための入れ物としてのFood」と「登録された食品としてのFood」という別の概念を同じオブジェクトモデルで扱おうとしている
...と言った問題があります。
// 2: 正しい例
var food = foodManager.RegisterBy(name, limitDate);
1のコードをリファクタリングした結果が2になります。
リファクタリングの結果、「食品」ドメインの振る舞いが「アプリに食品を登録する」から「食品名と賞味期限から食品を登録する」に変わります。
このようにしてドメインモデルを洗練させて行きます。
また、ドメインモデルを定義するにあたって気をつけなければならない状態がドメインモデル貧血症という状態です。
ドメインモデル貧血症とはドメインモデルを反映させたクラスに振る舞いとなるメソッドがなく、プロパティやgetter、setterしかない状態を指します。
ドメインモデル貧血症になったクラスはドメインモデルを反映しているとは言えません。ユビキタス言語を意識してクラスを再設計する必要があります。
境界づけられたコンテキスト
境界づけられたコンテキストとはドメインモデルに対してユビキタス言語が適応出来る範囲の事を指します。 ユビキタス言語はチームごとに定義されるため、チームが変われば境界づけられたコンテキストも変わります。
例えば、一言にアカウントというドメインを定義してもコンテキストによって意味が変わります。
- 銀行取引コンテキスト → 銀行口座
- 文学コンテキスト → 報告書
そもそも、ドメインモデルの対象となるドメインは様々なサブドメインによって構成されます。
サブドメインの種類は以下の通りになります。
- コアドメイン
- 事業成功の為に不可欠なサブドメイン
- 会計業務であれば簿記を付ける機能
- 支援サブドメイン
- 汎用サブドメイン
- 業務に必ずしも不可欠とはならないサブドメイン
- 会計業務であれば帳票を印刷する機能
支援サブドメインはシステムによってはコアドメインになり得ます。 例えば上記の場合、対象システムが経営支援の場合、財形情報をグラフ化する機能はコアドメインと言えます。
汎用サブドメインはサードパーティ製ソフトウェアやライブラリに置き換えることができます。 また、納期とのトレードオフにされる対象になりやすいです。
ここで境界づけられたコンテキストには以下の特徴があります。
例えば、とあるドメインがサバクラ実装になってサーバサイドとクライアントサイドでチームが分かれた場合、境界づけられたコンテキストはここで分かれます。逆に同じユビキタス言語を使い、ドメインモデルを論理的に統一した状態を保てるのであれば分ける必要はありません。
また、境界づけられたコンテキストのサイズは「対応するサブドメインのユビキタス言語全体を捉えられる程度」のサイズになります。 ユビキタス言語は「チームが共有すべき共通言語」なので境界づけられたコンテキストのサイズは1チームが行える作業サイズとも言えます。
なので、サイズがアーキテクチャやフレームワークのような技術的要因や、 開発要員へのタスクの割り当てやすさのようなPM的要因に引きずられてはいけません。
コンテキストマップ
コンテキストマップとは、境界づけられたコンテキスト間の関係性・状態を表すものです。 コンテキストマップを用いることで組織・政治的な要因やチームの熟練度・PJへの取り組み姿勢を読み取ることが出来ます。
本書ではコンテキストマップとして8つのパターンが示されています。 これらのパターンはチームの現状を分析・理解することに役立ちます。
名前 | 説明 |
---|---|
共有カーネル | ドメインモデルの一部を共有する |
顧客/供給者の開発チーム | 2つのチームに顧客と供給者の関係が確立する |
順応者 | 相手のコンテキストに従う |
腐敗防止層 | 隔離するためのレイヤを作成する |
別々の道 | 2つのコンテキストのつながりを持たない |
公開ホストサービス | 共有プロトコルを公開する |
公表された言語 | 標準化されたプロトコルを利用する |
巨大な泥団子 | ドメインモデリングを諦め、隔離する |
共有カーネル → 顧客/供給者の開発チーム → 順応者 → 腐敗防止層 → 別々の道 の順にドメインの共通部分が減って行きます。
また、公開ホストサービスは1対多の際の関係性になり、それを補完する関係性として公表された言語があるイメージです。
公表された言語は要はJSONとかXMLのような誰でも知ってるデータ表現を使いますってことです。
現状を理解する上でコンテキストマップを記述する特定の方法はありません。 コンテキストマップの目的は境界づけられたコンテキスト間の関係性をチーム全体が理解することにあるので、 UMLを使おうが汚い適当な図を書こうが何でもよいです。優先すべきはチームでの共有と理解です。
読んだ感想
私の場合、色々なサイトから独学で理解しようとしていたため、何が正しいのかわからず情報の海に溺れかけていました。ですが、今回本書を読むことによってかなり情報の矯正・整理が出来たと思います。
ページ数は総数51ページとそれほど多くはありませんが、内容が濃いため理解するのに何度も読み返しました。
本書はドメイン駆動設計の一部しか説明されていませんが、それでもドメイン駆動設計が何かはわかるようになりました。私には効率的で良い本だったと思います。
具体的な技術の部分が次巻も出ていなさそう(2019/02/20確認時)なので、気が向いた時に本書の原典であるエリック・エヴァンスのドメイン駆動設計も読んでみたいと思います。
最後に上記のまとめに間違い不備があればどんどんマサカリ投げてください。全力で受け止めに行きます。