ドメイン駆動設計(DDD)は、ドメインの専門家からのインプットに基づいて、そのドメインに適合するようにソフトウェアをモデリングすることに焦点を当てたソフトウェア設計アプローチです[ 1 ] [ 2 ]。DDDは、単一の統一モデルを持つという考え方とは反対で、代わりに大きなシステムを境界のあるコンテキストに分割し、それぞれが独自のモデルを持ちます[ 3 ] [ 4 ] 。
ドメイン駆動設計では、ソフトウェアコードの構造と言語(クラス名、クラスメソッド、クラス変数)はビジネスドメインに合致している必要があります。例えば、ソフトウェアがローン申請を処理する場合、「ローン申請」、「顧客」といったクラスや、「オファーの承認」、「引き出し」といったメソッドを持つ可能性があります。
ドメイン駆動設計は、以下の目標に基づいています。
ドメイン駆動設計の批判者たちは、開発者はモデルを純粋で有用な構造として維持するために、通常、多くの分離とカプセル化を実装する必要があると主張している。ドメイン駆動設計は保守性などの利点を提供するが、マイクロソフトは、モデルがドメインの共通理解の形成に明確な利点をもたらす複雑なドメインにのみ推奨している。[ 5 ]
この用語は、エリック・エヴァンスが2003年に出版した同名の著書の中で造語したものです。[ 3 ]
Domain-driven design articulates a number of high-level concepts and practices.[3]
Of primary importance is a domain of the software, the subject area to which the user applies a program. Software's developers build a domain model: a system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain.
These aspects of domain-driven design aim to foster a common language shared by domain experts, users, and developers—the ubiquitous language. The ubiquitous language is used in the domain model and for describing system requirements.
Ubiquitous language is one of the pillars of DDD together with strategic design and tactical design.
In domain-driven design, the domain layer is one of the common layers in an object-orientedmultilayered architecture.
Domain-driven design recognizes multiple kinds of models. For example, an entity is an object defined not by its attributes, but its identity. As an example, most airlines assign a unique number to seats on every flight: this is the seat's identity. In contrast, a value object is an immutable object that contains attributes but has no conceptual identity. When people exchange business cards, for instance, they only care about the information on the card (its attributes) rather than trying to distinguish between each unique card.
モデルはイベント(過去に起こったこと)を定義することもできます。ドメインイベントとは、ドメインエキスパートが関心を持つイベントのことです。モデルはルートエンティティによって結合され、集約になります。集約外のオブジェクトはルートへの参照を持つことはできますが、集約内の他のオブジェクトへの参照を持つことはできません。集約ルートは、集約内の変更の一貫性をチェックします。たとえば、ドライバーは車の各車輪を個別に制御する必要はありません。単に車を運転するだけです。この文脈では、車は他のいくつかのオブジェクト(エンジン、ブレーキ、ヘッドライトなど)の集約です。
ドメイン駆動設計では、オブジェクトの作成とオブジェクト自体が分離されることが多い。
例えば、リポジトリとは、データストア(データベースなど)からドメインオブジェクトを取得するためのメソッドを持つオブジェクトです。同様に、ファクトリとは、ドメインオブジェクトを直接作成するためのメソッドを持つオブジェクトです。
プログラムの機能の一部が概念的にどのオブジェクトにも属さない場合、それは通常サービスとして表現されます。
DDDにはさまざまな種類のイベントがあり、その分類に関する意見は異なる場合があります。Yan Cuiによると、イベントには2つの主要なカテゴリがあります。[ 6 ]
ドメインイベントは、特定のビジネスドメイン内で発生する重要な出来事を示します。これらのイベントは境界付けられたコンテキストに限定され、ビジネスロジックを維持するために不可欠です。通常、ドメインイベントはペイロードが軽く、処理に必要な情報のみが含まれています。これは、イベントリスナーが一般的に同じサービス内にあり、その要件がより明確に理解されているためです。[ 6 ]
一方、統合イベントは、異なる境界コンテキスト間で変更を伝達する役割を果たします。これらは、システム全体を通してデータの一貫性を確保するために不可欠です。統合イベントは、潜在的なリスナーのニーズが大きく異なる可能性があるため、追加の属性を持つより複雑なペイロードを持つ傾向があります。これは多くの場合、より徹底したコミュニケーションのアプローチにつながり、すべての関連情報が効果的に共有されるようにするために過剰なコミュニケーションが生じることになります。[ 6 ]
コンテキスト マッピングは、より大きなシステム内の異なるドメインまたはサブドメインの境界を識別して定義します。これにより、これらのコンテキストがどのように相互作用し、互いに関連しているかを視覚化できます。以下は、Eric Evans によるいくつかのパターンです。[ 7 ]
ドメイン駆動設計は本質的にオブジェクト指向アプローチと結びついているわけではありませんが、実際には、オブジェクト指向技術の利点を活用しています。これには、コマンドやメソッド呼び出しの受信側としてのエンティティ/集約ルート、最上位の集約ルート内での状態のカプセル化、そしてより上位のアーキテクチャレベルでの境界付きコンテキストなどが含まれます。
その結果、ドメイン駆動設計は、Javaと.NET Frameworkにそれぞれ固有の技術的な実装の詳細である、プレーンなJavaオブジェクトとプレーンなCLRオブジェクトと関連付けられることがよくあります。これらの用語は、ドメインオブジェクトは、より具体的な技術フレームワークではなく、ドメインのビジネス上の振る舞いによってのみ定義されるべきであるという、ますます広まっている考え方を反映しています。
同様に、ネイキッドオブジェクトパターンでは、ユーザーインターフェースは十分なドメインモデルの単なる反映でよいとされています。ユーザーインターフェースがドメインモデルを直接反映することを要求することで、より優れたドメインモデルの設計が促されます。[ 9 ]
ドメイン駆動設計は、ソフトウェア開発における他のアプローチにも影響を与えている。
例えば、ドメイン固有モデリングは、ドメイン固有言語を用いてドメイン駆動設計を適用したものです。ドメイン駆動設計は必ずしもドメイン固有言語の使用を必要とするわけではありませんが、ドメイン固有言語の定義やドメイン固有のマルチモデリングのサポートに役立てることができます。
一方、アスペクト指向プログラミングを用いることで、ドメインモデルから技術的な懸念事項(セキュリティ、トランザクション管理、ログ記録など)を容易に切り離すことができ、開発者は純粋にビジネスロジックに集中できるようになる。
ドメイン駆動設計はモデル駆動エンジニアリングやモデル駆動アーキテクチャと互換性がありますが、[ 10 ] 2 つの概念の背後にある意図は異なります。モデル駆動アーキテクチャは、より良いドメインモデルを定義することよりも、モデルをさまざまなテクノロジー プラットフォーム用のコードに変換することに重点を置いています。
しかし、モデル駆動型エンジニアリングが提供する技術(ドメインのモデリング、ドメインエキスパートと開発者間のコミュニケーションを容易にするためのドメイン固有言語の作成など)は、実際のドメイン駆動設計を容易にし、実務者がモデルからより多くのものを引き出すのに役立ちます。モデル駆動型エンジニアリングのモデル変換とコード生成技術のおかげで、ドメインモデルを使用して、それを管理する実際のソフトウェアシステムを生成することができます。[ 11 ]
コマンドクエリ責任分離(CQRS)は、データの読み取り(「クエリ」)とデータの書き込み(「コマンド」)を分離するためのアーキテクチャパターンです。CQRSは、ベルトラン・メイヤーによって提唱されたコマンドクエリ分離(CQS)から派生したものです。
コマンドは状態を変更するものであり、集約ルートまたはエンティティに対するメソッド呼び出しとほぼ同等です。クエリは状態を読み取りますが、状態を変更することはありません。
CQRSはドメイン駆動設計を必須とするものではありませんが、集約ルートという概念によってコマンドとクエリの区別を明確にしています。つまり、特定の集約ルートにはコマンドに対応するメソッドがあり、コマンドハンドラはその集約ルート上のメソッドを呼び出すという考え方です。
集約ルートは、操作のロジックを実行し、失敗応答を返すか、データストアに書き込める自身の状態を変更する役割を担います。コマンドハンドラは、集約ルートの状態を保存し、必要なコンテキスト(トランザクションなど)を作成するためのインフラストラクチャ関連の処理を担います。
イベントストーミングは、ドメイン駆動設計 (DDD) のコンテキストでドメインイベントを特定して理解するための前段階として使用できる、ワークショップベースの共同モデリング手法です。このインタラクティブな発見プロセスでは、ステークホルダー、ドメインエキスパート、開発者が協力してドメインイベントの流れ、その原因、および影響を視覚化し、ドメインの共通理解を促進します。この手法では、ドメインイベント、集約、外部システムなどのさまざまな要素を表すために色分けされた付箋を使用することが多く、ドメインの明確で構造化された探索を容易にします。イベントストーミングは、DDD の重要な構成要素であるサブドメイン、境界コンテキスト、および集約境界の発見に役立ちます。ドメインで「何が起こるか」に焦点を当てることで、この手法はビジネスプロセス、依存関係、および相互作用を明らかにするのに役立ち、DDD 原則を実装し、システム設計をビジネス目標に合わせるための基盤を提供します。[ 12 ] [ 13 ]
イベントソーシングとは、エンティティが直接的なシリアル化やオブジェクトリレーショナルマッピングではなく、イベントを読み込んでイベントストアにコミットすることによって内部状態を追跡するアーキテクチャパターンです。
イベントソーシングをCQRSおよびドメイン駆動設計と組み合わせると、集約ルートはコマンドの検証と適用(多くの場合、コマンドハンドラからインスタンスメソッドを呼び出すことによって)を行い、その後イベントを発行する責任を負います。これはまた、集約ルートがメソッド呼び出しを処理するロジックの基盤となります。したがって、入力はコマンドであり、出力は1つまたは複数のイベントです。これらのイベントはイベントストアに保存され、その後、多くの場合、関心のあるユーザー(アプリケーションのビューなど)向けにメッセージブローカーに発行されます。
集約ルートをモデル化してイベントを出力すると、標準的なn層データパッシングアーキテクチャのようにエンティティから読み取りデータを投影する場合よりも、内部状態をさらに分離できます。重要な利点の 1 つは、集約ルートが内部状態を包括的に隠蔽するため、公理的定理証明器 (Microsoft Contracts や CHESS [ 14 ]など) の適用が容易になることです。イベントは集約ルートインスタンスのバージョンに基づいて永続化されることが多く、これにより楽観的並行性によって分散システムで同期するドメインモデルが得られます。
境界コンテキストは、ドメイン駆動設計 (DDD) の基本概念であり、ドメインモデルが一貫性と妥当性を持つ特定の領域を定義し、明確性と関心の分離を保証します。[ 15 ]マイクロサービスアーキテクチャでは、境界コンテキストはマイクロサービスにマッピングされることが多いですが、この関係は設計アプローチによって異なる場合があります。境界コンテキストがそれぞれ単一のマイクロサービスとして実装される 1 対 1 の関係は、明確な境界を維持し、結合度を減らし、独立したデプロイとスケーリングを可能にするため、一般的に理想的です。ただし、他のマッピングも適切な場合があります。境界コンテキストがさまざまなスケーラビリティやその他の運用上のニーズに対応するために複数のマイクロサービスに分割される場合は 1 対 多の関係が発生する可能性があり、複数の境界コンテキストを単一のマイクロサービスに統合してシンプルにしたり、運用上のオーバーヘッドを最小限に抑えたりする場合は多対 1 の関係が発生する可能性があります。関係の選択は、DDD の原則とシステムのビジネス目標、技術的な制約、運用上の要件とのバランスを取る必要があります。[ 16 ]
ドメイン駆動設計は特定のツールやフレームワークに依存しないものの、注目すべき例としては以下のようなものがある。