ドメイン駆動開発(Domain-Driven Design、DDD)は、複雑なソフトウェアシステムの設計と開発のためのアプローチです。このアプローチは、ビジネスドメイン(業務領域)に焦点を当て、ソフトウェアの構造とロジックをビジネスの概念と一致させることを目指します。DDDは2003年にEric Evansによって提唱され、彼の著書「Domain-Driven Design: Tackling Complexity in the Heart of Software」で詳細に説明されています。
ユビキタス言語は、開発者とドメインエキスパート(業務専門家)の間で共有される共通言語です。この言語はプロジェクト内のすべてのコミュニケーション、コード、ドキュメントで一貫して使用され、技術チームとビジネスチームの間の理解のギャップを埋めるのに役立ちます。
大規模なシステムでは、異なる部分で同じ用語が異なる意味を持つことがあります。境界づけられたコンテキストは、特定のモデルが適用される明確な境界を定義し、各コンテキスト内でモデルの整合性を保ちます。
エンティティは、一意の識別子を持ち、ライフサイクルを通じて同一性が維持されるオブジェクトです。例えば、顧客や注文などがエンティティになります。
値オブジェクトは、属性によってのみ定義され、同一性を持たないオブジェクトです。例えば、住所や金額などが値オブジェクトになります。値オブジェクトは不変(イミュータブル)であるべきです。
集約は、一緒に扱われるエンティティと値オブジェクトのクラスターで、一貫性の境界を形成します。各集約には集約ルート(Aggregate Root)があり、外部からのアクセスはこのルートを通じてのみ行われます。
ドメインサービスは、特定のエンティティや値オブジェクトに自然に属さない操作を実装します。例えば、複数の集約にまたがる操作や、複雑なビジネスルールの適用などがドメインサービスになります。
リポジトリは、集約のインスタンスの永続化と取得を担当します。これにより、ドメインモデルはデータアクセスの詳細から分離されます。
ファクトリは、複雑なオブジェクトや集約の生成を担当します。これにより、オブジェクトの生成ロジックがドメインモデルから分離されます。
戦略的設計は、大規模なシステム全体の構造に関するものです。主な概念には以下が含まれます:
戦術的設計は、特定のコンテキスト内でのモデルの実装に関するものです。主な概念には以下が含まれます:
DDDは通常、以下のような層に分かれたアーキテクチャで実装されます:
ヘキサゴナルアーキテクチャは、ドメインロジックを外部の懸念事項から分離するための代替アプローチです。これにより、ドメインモデルは外部システムやフレームワークに依存せず、テストが容易になります。
CQRSは、データの更新(コマンド)と読み取り(クエリ)の責任を分離するパターンです。これにより、複雑なドメインモデルを使用してコマンドを処理し、最適化された読み取りモデルを使用してクエリを処理することができます。
イベントソーシングは、システムの状態の変更をイベントとして保存するアプローチです。これにより、システムの完全な監査証跡が提供され、状態を任意の時点に再構築することができます。
DDDは以下のような状況で特に有効です:
一方、以下のような状況ではDDDの適用が過剰になる可能性があります:
オンラインショッピングシステムでDDDを適用する場合、以下のような境界づけられたコンテキストが考えられます:
注文コンテキスト内では、以下のようなドメインモデルが考えられます:
DDDの境界づけられたコンテキストの概念は、マイクロサービスアーキテクチャと自然に適合します。各境界づけられたコンテキストは、独自のドメインモデルを持つ独立したマイクロサービスとして実装できます。これにより、サービス間の結合度を低く保ちながら、各サービス内での高い凝集度を実現できます。
ドメイン駆動開発(DDD)は、複雑なビジネスドメインを持つソフトウェアシステムの設計と開発のための強力なアプローチです。DDDは、ビジネスドメインに焦点を当て、ソフトウェアの構造とロジックをビジネスの概念と一致させることで、より効果的で保守性の高いシステムを構築することを目指します。
DDDの核心は、ユビキタス言語、境界づけられたコンテキスト、エンティティ、値オブジェクト、集約などの概念にあります。これらの概念を適切に適用することで、複雑なドメインを理解しやすく、実装しやすい形で表現することができます。
DDDは学習曲線が急で、すべてのプロジェクトに適しているわけではありませんが、複雑なビジネスロジックを持つ長期的なプロジェクトでは、その投資に見合う価値があります。特に、マイクロサービスアーキテクチャを採用する場合、DDDの原則は適切なサービス境界を定義するのに役立ちます。