Domain Driven Design Quicklyをさ〜らに要約してみた
はじめに
DDDの要約と基本思想の紹介を、短く素早く読めるかたちで公表されているDomain Driven Design(ドメイン駆動設計) QuicklyがInfoQで無料公開されています。
ただこの資料、量が多く読むのがしんどい為、
今回はこれをさらに要約してみました。
参考元 : Domain Driven Design(ドメイン駆動設計) Quickly 日本語版
ドメイン駆動設計とは何か
ソフトウェアを開発する目的
・ 実世界の作業を自動化するためです。
・ ビジネス上の問題を解決するためです。
ソフトウェアを作るためには
例えば、銀行業務システムを構築するとなった場合、銀行業務について最も大切なことを理解していなければ、銀行業務システムの構築はできません。
つまり、銀行業務のドメインを知る必要があります。
ドメインを知るのは誰?
✖️ ソフトウエアアーキテクト
✖️ ソフトウェアアナリスト
✖️ 開発者
○ 構築するシステムの対象となる業務に精通している人 (上の例なら, 銀行員)
理由 : 銀行業務システムは銀行の中で働く人々や専門家がとてもよく理解しているためです。
ソフトウェアを導入する目的
・ 対象ドメインの業務をより効率的にするためです。
ドメインに適合するソフトウェアを作成するには
・ ドメインの反映としてのソフトウエアを作ることです。
では、どうやって??
それは、モデル化することです。
ドメインモデル
ドメインモデルとは??
・ Eric Evansによると、ドメインモデルは特定の図で表されるものではなく、そのような図が伝えようとする概念です。
・ ドメインモデルはドメインの専門家の頭の中にある単なる知識ではないです。
→ このような知識を取捨選択しながら作成する抽象です。図はモデルを表現して、モデルの意味を伝えることができます。
モデルを相手に伝えるには
1. 図による表現
例 : ダイヤグラム、ユースケース、スケッチ、絵などです。
2. 記述による表現
例 : ドメインについての見通しを文章で記述する方法
3. 独自言語で表現
例 : ユビキタス言語
ドメインの知識を構築する
ドメインの専門家は、ドメインの知識をたくさん持っています。
しかし、モデルを構築するためには、その知識から重要な部分を抜き出して一般化する必要があります。
さて、どうすればいいのか?
ドメインの中の最も重要な概念を明らかにするように努力する
では、これをするためにどうするのか、手順を追って記載します。
1. ドメインの専門家が議論をして、知識を交換します。
まずは、専門家からドメインについてできるだけ多くのことを学ばなければなりません。そのために、簡単な質問を投げかけたり、情報を軽く整理する必要があります。
2. ドメインモデルをスケッチし始めます。
初めは、完璧でも正確でもないスケッチですが、なくてはならないはじめの一歩です。
3. その後、フィードバックを求めます。
これにより、より明瞭に正確にモデルを理解するのを助けてくれます。
ユビキタス言語
開発者とドメインの専門家にある壁
・ 開発者とドメインの専門家の互いが持つ専門の言葉を使い、コミュニケーションを図ろうとするためです。
解決策
ドメインモデルを作成する時は、コミュニケーションのやり方の違いを克服するために、互いの考えを交換する必要があります。
ただ、ドメインモデルについて議論するときは、全員が同じ言語を使わなければなりません。
共通言語の拠り所として、ドメインモデルを使用します。この言語をコミュニケーションや、コードに使うようにする。
→ このような言語を[ユビキタス言語]と呼ぶようです。
ユビキタス言語の表現方法
-
UML
理由 : クラス間の関係を表すのに便利です。 -
図 + 文章 ◎
理由 : モデルを認識合わせする為におすすめの方法は、モデルの部分を表す小さな図を作成することです。
さらに、これらの図に文章を使用すれば、図ができない振る舞いや制約を説明できます。 -
コード
理由 : この方法は、XPプログラミングのコミュニティでも広く支持されています。
しかし、コードを読むことでメソッドが表現する振る舞いを理解できても、そのメソッド名がその振る舞いと同じくらい明瞭に理解できるとは限らないです。つまり、コードによる表現は難しいのです。
モデル駆動設計
モデル駆動設計とは、抽象的な設計の原則を現実のソフトウェアに適用するためのものです。
下記は、モデル駆動設計で使用されるパターンです
レイヤーアーキテクチャ
ドメインモデルに関係のあるコードをひとつのレイヤに集めて、UIレイヤやアプリケーションレイヤ、インフラレイヤのコードと分離していきます。
・メリット
こうするとモデルは、十分な表現力を持ち、ビジネスについての本質的な知識を捉えてるようになります。
エンティティ
ソフトウェアの様々な状態の中で、常に同一であり続けるオブジェクトがあった時、
このオブジェクトが存在し続けることは、重要です。
オブジェクトの存在期間は、システムの寿命に及びます。
このようなオブジェクトをエンティティと呼びます。
人物の概念をプログラムを使い実装する例
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/d2f05398-eb77-49f3-46d6-866f9db2430f.png" width="500px">
したがって、エンティティをソフトウエアに実装するということは、一意性を作成することです。
また、エンティティはドメインモデルに必須のオブジェクトです。
バリューオブジェクト
あるオブジェクトがどんな属性を含むのか知りたい場合、そのオブジェクトは一意性を保証しなくてもいいはずです。
バリューオブジェクトとは、上記のような一意性を保証する必要がないオブジェクトのことです。
サービス
サービスは内部に状態を保持せず、単純に機能だけを提供します。
機能というのは、あるオブジェクトの振る舞いを指します。
また、特定のエンティティやバリューオブジェクトのための機能をまとめます。
モジュール
大規模なアプリケーションの場合、ドメインモデルはどんどん大きくなっていく傾向にあります。
なので、ドメインモデルを複数のモジュールの集まりとして構築する必要があります。
モジュールの注意点
モジュールにはユビキタス言語に含まれる名前を付けるべきだそうです。
モジュールとその名前はドメイン内部に対する洞察を反映していなければなりません。
ドメインオブジェクトのライフサイクルの管理に対処するパターン
・ アグリゲート
アグリゲートは、オブジェクトの所有権と境界を定義するのに使うパターンです。
・ ファクトリ, リポジトリ
ファクトリとリポジトリは、オブジェクトの作成と保管に役立つパターンです。
アグリゲート
オブジェクト同士が複雑に関連しているモデルには、問題点があります。
→ オブジェクトの変更の一貫性を保証するのは難しいことです。
アグリゲートは、関連するオブジェクトの集まりで、データの変更について一括して扱うことができます。
アグリゲートの例
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/63f8dce4-c93f-f291-c91e-56ac0804a819.png" width="500px">
あるアグリゲートを他のアグリゲートから区別するのは、そのアグリゲートに含まれるオブジェクトと含まれないオブジェクトの間にある境界線です。
また、アグリゲートはひとつのルートを持ちます
処理的な流れをまとめていくと、
・ ルートを通すことで、内部のオブジェクトへアクセスするようにします。
・ 外部のオブジェクトには、ルートの参照だけを持たせるようにします。
・ 内部のオブジェクトの参照は、1回の処理で使う場合にのみ、参照として外部のオブジェクトへ渡します。
これにより、どんな変更が加えられても、アグリゲート内のオブジェクトやアグリゲート全体の不変性を維持できます。
ファクトリ
オブジェクトの生成ロジックが複雑な場合、その操作をカプセル化するのに役立つパターンがファクトリです。
ファクトリを実装するためのパターン例
ファクトリメソッド
ファクトリメソッドは、他のオブジェクトを作成するのに必要な知識を保持し隠蔽するメソッドです。
使用例
リポジトリ
リポジトリは、オブジェクトの参照を取得するのに必要なロジックをすべてカプセル化するためのパターンです。
リポジトリの使用例
DDD Quicklyにはリポジトリに対し、以下のような説明があります。
リポジトリパターンを使えば、ドメインオブジェクトは 必要な他のドメインオブジェクトの参照を取得するために、インフラストラクチャを使って直接アクセスする必要はなくなるでしょう
これはつまり、クライアントがリポジトリにオブジェクトを要求した時に、リポジトリがオブジェクトを持っていなかったらデータベース等の永続化ストレージから情報を取得します。
ファクトリとよく混雑するので、分かりやすい図を下記に掲載します。
リファクタリングのためのさらに深い洞察
リファクタリングは、アプリケーションの振る舞いを変えずにコードを改善する作業です。
多くの場合、制御できる小さな範囲で、細心の注意を払ってリファクタリングをするので、振る舞いを変更したりバグを埋め込んだりはしません。
リファクタリングには、2種類あります。
1. コードを対象とするリファクタリング
2. ドメインとそのモデル対するリファクタリング
1については、よく知られており、リファクタリングするパターンは決まっていたりします。
しかし、2についてはどうでしょうか。
2に対する、リファクタリングはそうはいきません。
なぜなら、モデルが複雑で様々な形態をとる為、パターンを作ることができないのです。
ただ、このリファクタリングをおこなうと、ドメインに対して新しい洞察が得られることがあります。
例えば、ドメインの要素が明確になったり、ふたつの要素の間に新しい関係が見つかることもあります。
↓リファクタリングするタイミング
このような改善は、設計段階でリファクタリングを通じておこなわなければなりません。
そして、リファクタリングにはドメインの専門家とドメインを理解しなければならない開発者の密接な関与が必要です。
モデルの完全性を維持する
複数のチームが協力して作業しなければならないような巨大なプロジェクトで使用するモデルは、揺らぎやすくなります。
なぜならば、複数のチームが作業する場合、各チームのコーディングは平行します。この場合、それぞれのチームにはモデルの特定の部分に割り当てられることになります。
それにより、一人の担当しているモジュールの修正が結果的に繋がりのある他のモジュールに影響を与え、ドメインのモデルの変更が生じる可能性があるためです。
では、どうするのか?
それをパターンとしてまとめます。
モデルの完全性を維持するための方法(一例)
コンテキスト境界
コンテキスト境界は、モジュールを包み込む枠組みです。
コンテキストとは、そのモデルに適用される条件のことです。
この条件とは、モデル内で使われる用語が、特定の意味を確実に持つようにするために必要です。
コンテキスト境界を用いる時というのは、モデルを複数に分割するような時です。
なぜ、モデルを分割するのか??
理由は、チーム内の協調性やコミュニケーションは、より柔軟で完全になり、同じモデルに取り組む開発者が楽になる為です。
そして、モデルを分割するときに最も大事なのはモデルの範囲を確定すること、
→ これがコンテキストの境界を描くということです。
たくさんのモデルに分割して扱えば、自身に割り当てられた部分で自由に作業できます。
誰もがモデルの限界も知っていますから、境界内にとどまって作業ができます。
そうすれば他のモデルに影響を与えずに簡単にリファクタリングできます。
継続的な統合
コンテキスト境界を扱うときは継続的な統合が必要です。
付け加えられた新しい要素をモデルの残りの部分と適合させて正確に実装するためです。
コンテキストマップ
コンテキストマップは、**異なるコンテキスト境界と、それらの関係についての概略を示すための文書です。**コンテキストマップで大切なのは、プロジェクトのメンバ全員がこの文書を共有し理解することです。
コンテキストマップの一例を下記に記載します。
共有カーネル
メインモデルのある部分をふたつのチームで共有します。もちろんその部分と一緒に、その部分に含まれるコードやデータベースの設計も共有します。これを共有カーネルと呼びます。
共有カーネルの目的は重複を少なくしながら、ふたつのコンテキストを分離しておくことです。
使用例
継続的な統合の実行を維持する体制ができていないチームや、チームが大きすぎて身動きが取れない場合、コンテキスト境界を定義し、複数のチームを作成し作業を進めるのがいいと思います。このような時に共有カーネルを使用することがおすすめされています。
今日における DDD の諸問題: Eric Evans へのインタビュー
この章は、ものすごく省略していきます。w
Q1 DDDが今までと同様、今日でも重要なのはなぜでしょうか。
A. 複雑に入り組んだドメインを扱うときにはいつでも適応できる原則だからです
Q2 技術プラットフォーム(Java, .NET, Ruby等)は、進化し続けています。ドメイン駆動設計は、これらのプラットフォームにどのように適合するのでしょうか。
A. DDDは特定の技術プラットフォームに依存しません。
Q3 あなたの本が出版されてからDDDのコミュニティでどんなことが起こっていますか。
A. 本に書いたDDDの原則を理解し、それを思いもしなかった方法で利用するようになったこと。
Q4 DDD を学ぼうとしている人になにかアドバイスはありますか。
A. 俺の本を読め。
おわりに
もし本気で理解したいのであれば、Eric Evansの本を読むことを強くお勧めします。
エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)
ちなみに僕も持っています。持っては、いますが。。。
以上です!
ご愛読ありがとうございました。
Discussion