Traffine I/O

日本語

2022-11-15

ドメイン駆動設計(DDD)

ドメイン駆動設計(DDD)とは

ドメイン駆動設計(DDD)は、堅牢で保守性が高く、適応性のあるソフトウェアソリューションを構築するために、システムのコアドメインを理解することを優先するソフトウェア開発方法論です。DDDの中心には、ドメインエキスパートとソフトウェア開発者の協力があり、その結果として作成されたソフトウェアは、対象とする問題空間に密接にモデル化されます。

DDDの利点

ソフトウェア開発にDDDを使用することには、以下のようないくつかの利点があります。

  • ビジネスニーズに合わせたソフトウェアの整合性
    DDDは、ソフトウェアモデルが基礎となるドメインを正確に表現することを保証し、開発者がビジネス要件に直接対応するソフトウェアを作成できるようにします。

  • 保守性と適応性の向上
    DDDは、関心の分離を促進し、ドメインが進化するにつれてソフトウェアを変更、拡張、またはリファクタリングすることを容易にします。

  • 協力を促進
    DDDは、コミュニケーションと共通言語を重視することで、ドメインエキスパートと開発者の協力を促進し、より情報の豊富なソフトウェア設計決定を導きます。

DDDでの一般的な用語

DDDには、以下のような一般的な用語があります。

ユビキタス言語

ドメインエキスパートとソフトウェア開発者が効果的にコミュニケーションし、協力するために使用する共通言語。ユビキタス言語は、全てのステークホルダーがドメイン、その概念、およびそのルールについて共通の理解を持っていることを保証します。

ドメインモデル

ドメインモデルはドメインのコアコンセプト、ビジネスルール、および関係性を表すモデルです。ドメインモデルは、ソフトウェアシステムの基礎として機能し、その設計と実装に影響を与えます。

バウンデッドコンテキスト

バウンデッドコンテキストは自己完結型のドメインの領域であり、独自のモデル、言語、ルールを持つ領域です。バウンデッドコンテキストは、ドメインロジックをカプセル化し、他のコンテキストへの依存関係を最小限に抑え、システムを保守可能かつスケーラブルにします。

コンテキストマッピング

コンテキストマッピングはバウンデッドコンテキスト間の関係を特定して文書化するプロセスです。コンテキストマッピングは、システムの異なる部分がどのように相互作用し、協力するかを理解するために開発者が役立ちます。

DDDの基本要素

DDDでは、高レベルのコンセプトを定義し、相互に組み合わせてドメインモデルを作成および修正することができます。

DDD terms
EP32: REST vs. GraphQL

エンティティ

エンティティはドメイン内で一意の識別子とライフサイクルを持つオブジェクトです。エンティティは、しばしばドメインのコアコンセプトを表し、可変状態で特徴づけられます。エンティティは、属性が他と同じであっても識別子によって区別されます。

値オブジェクト

値オブジェクトはドメインの側面を表すが、独自の識別子を持たない不変オブジェクトです。エンティティの特性や属性を説明するためによく使用されます。値オブジェクトは、そのプロパティによって定義され、プロパティが同じ場合、2つの値オブジェクトは等価とみなされます。

アグリゲート

単一のユニットとなる、関連するエンティティと値オブジェクトのグループで、1つのエンティティがアグリゲートルートとして機能します。アグリゲートルートは、ビジネスルールを強制し、アグリゲート全体の整合性を確保する責任があります。アグリゲートは、特定のドメインコンテキスト内で不変性を強制し、整合性を維持するのに役立ちます。

リポジトリ

リポジトリは多くの場合、基礎となる永続化メカニズムを抽象化することにより、アグリゲートやエンティティのコレクションへのアクセスを提供する責任があるコンポーネントです。リポジトリは、ドメインモデルとデータストレージとの間の橋渡しとなり、開発者がデータの取得や保存の詳細について心配することなく、ドメインロジックに集中できるようにします。

ファクトリ

ファクトリはエンティティやアグリゲートなどの複雑なドメインオブジェクトを作成し、組み立てる責任があるコンポーネントです。ファクトリは、オブジェクト作成に必要なロジックをカプセル化し、生成されたオブジェクトがドメインのビジネスルールと不変性に準拠していることを保証します。

サービス

サービスはエンティティ、値オブジェクト、またはアグリゲートに自然にフィットしないドメインロジックをカプセル化するステートレスの操作です。通常、ユースケースを実装し、アグリゲート間の相互作用を調整したり、複数のドメインオブジェクトにわたる計算や検証を実行したりするために使用されます。

ドメインイベント
ドメインイベントはドメイン内の重要な発生事象を表し、システムの他の部分に興味を持たせるために使用されます。ドメインイベントは、状態の変化やビジネスルールの変更を他のコンポーネント間で通信するために、しばしば疎結合な方法で使用されます。ドメインイベントは、イベントのソースに強く結びつかずにコンポーネントがイベントに反応できるため、よりモジュラーで柔軟なアーキテクチャを可能にします。

DDDのレイヤー

DDDでは、ソフトウェアシステムを4つの明確なレイヤーに分割し、各レイヤーに独自の責任を持たせます。これらのレイヤーは次のとおりです。

  • ドメインレイヤー
    ビジネスロジックの中心となるレイヤーで、システムの核心を構成するドメインオブジェクト(エンティティ、値オブジェクト、アグリゲート、ドメインイベントなど)を含みます。このレイヤーは、ビジネスルールを強制し、不変性を維持し、システムの状態がドメインの要件と一致していることを保証する責任があります。

  • アプリケーションレイヤー
    ドメインレイヤーの上に位置し、ドメインと他のレイヤーとの間の活動を調整し、データのフローを管理する責任があります。このレイヤーには、ユースケースを定義し、ドメインオブジェクトと外部コンポーネントの相互作用を調整するアプリケーションサービスが含まれます。アプリケーションサービスは、通常ステートレスであり、ビジネスロジック自体は含まず、必要に応じてドメインレイヤーに委任します。

  • インフラストラクチャレイヤー
    システムの他のレイヤーをサポートするために必要な技術的な機能を提供します。これには、リポジトリ、データアクセスメカニズム、メッセージングシステム、外部サービスの統合などのコンポーネントが含まれます。インフラストラクチャレイヤーは、ドメインレイヤーまたはアプリケーションレイヤーで定義されたインターフェースや抽象化を実装することがよくあり、これにより、これらのレイヤーが中心的な責任に集中し、特定の技術的選択に密接に結びつかずに済むようになります。

  • プレゼンテーションレイヤー(またはユーザーインターフェースレイヤー)
    ユーザーに情報を提示し、ユーザーからの入力を取得する責任があります。グラフィカルユーザーインターフェース(GUI)、コマンドラインインターフェース(CLI)、または他のシステムが消費するためのAPIである場合があります。プレゼンテーションレイヤーは、データを取得し、アクションを開始し、結果を表示するためにアプリケーションレイヤーと通信します。ビジネスロジックやドメイン知識を含まないようにすることが重要であり、それによって関心の分離の原則が守られます。

DDDを実装するPythonのディレクトリ構造

DDDの原則を実装するためのPythonの典型的なディレクトリ構造は、以下のようになります。

my_project/
│
├── app/                # Application layer
│   ├── services/
│   │   ├── __init__.py
│   │   ├── account_service.py
│   │   ├── order_service.py
│   │   └── ...
│   ├── views/
│   │   ├── __init__.py
│   │   ├── account_view.py
│   │   ├── order_view.py
│   │   └── ...
│   ├── __init__.py
│   ├── config.py
│   └── main.py
│
├── domain/            # Domain layer
│   ├── aggregates/
│   │   ├── __init__.py
│   │   ├── account.py
│   │   ├── order.py
│   │   └── ...
│   ├── entities/
│   │   ├── __init__.py
│   │   ├── customer.py
│   │   ├── product.py
│   │   └── ...
│   ├── value_objects/
│   │   ├── __init__.py
│   │   ├── address.py
│   │   ├── email.py
│   │   └── ...
│   ├── events/
│   │   ├── __init__.py
│   │   ├── account_events.py
│   │   ├── order_events.py
│   │   └── ...
│   ├── factories/
│   │   ├── __init__.py
│   │   ├── account_factory.py
│   │   ├── order_factory.py
│   │   └── ...
│   └── __init__.py
│
├── infrastructure/   # Infrastructure layer
│   ├── repositories/
│   │   ├── __init__.py
│   │   ├── account_repository.py
│   │   ├── order_repository.py
│   │   └── ...
│   ├── orm/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   └── base.py
│   ├── messaging/
│   │   ├── __init__.py
│   │   ├── event_bus.py
│   │   └── ...
│   ├── __init__.py
│   └── settings.py
│
├── tests/           # Test suite
│   ├── unit/
│   │   ├── __init__.py
│   │   ├── test_account.py
│   │   ├── test_order.py
│   │   └── ...
│   ├── integration/
│   │   ├── __init__.py
│   │   ├── test_account_integration.py
│   │   ├── test_order_integration.py
│   │   └── ...
│   ├── __init__.py
│   └── conftest.py
│
├── .gitignore
├── README.md
└── requirements.txt

この構造は、ドメイン、アプリケーション、およびインフラストラクチャレイヤーなどのDDDアーキテクチャの異なるレイヤーを分離し、アグリゲート、エンティティ、値オブジェクト、イベント、ファクトリなどのドメイン基本要素を専用のディレクトリにまとめます。また、テストスイートは、ユニットテストと統合テストに分割され、システムのさまざまなコンポーネントのカバレッジを提供します。

参考

https://blog.bytebytego.com/p/ep32-how-does-grpc-work
https://www.linkedin.com/pulse/microservices-domain-driven-designdd-ahmed-emad
https://www.thoughtworks.com/en-us/insights/blog/architecture/domain-driven-design-in-functional-programming
https://blog.airbrake.io/blog/software-design/domain-driven-design
https://www.nuits.jp/entry/easiest-clean-architecture-2019-09
https://qiita.com/little_hand_s/items/2040fba15d90b93fc124

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!