logo

ドメイン駆動設計 (DDD)

ドメイン駆動設計 (DDD) は、ソフトウェア システムが動作する問題ドメインの理解とモデル化に焦点を当てたソフトウェア開発へのアプローチです。ドメインの複雑さと複雑さを深く理解するために、ドメインの専門家と緊密に協力することの重要性を強調しています。 DDD は、開発者がソフトウェア設計でドメインの概念を効果的に捉えて表現できるようにするための一連の原則、パターン、実践方法を提供します。



Pythonソートタプル

ドメイン駆動設計 (DDD) の重要なトピック

ドメイン駆動設計 (DDD) とは何ですか?

ドメイン

これは、ソフトウェア システムが対処するために構築されている主題領域または問題空間を指します。これには、ソフトウェアがモデル化またはサポートすることを目的とした現実世界の概念、ルール、プロセスが含まれます。たとえば、銀行業務アプリケーションの場合、ドメインには、銀行業務に関連する口座、取引、顧客、規制などの概念が含まれます。

ドリブン

「主導的」とは、ソフトウェア システムの設計がドメインの特性や要件によって導かれたり、影響を受けたりすることを意味します。言い換えれば、設計上の決定は、技術的な考慮事項や実装の詳細だけによって決定されるのではなく、ドメインの深い理解に基づいています。



デザイン

設計とは、ソフトウェア システムの計画または青写真を作成するプロセスを指します。これには、システムがどのように構築されるか、さまざまなコンポーネントがどのように相互作用するか、システムがその要求をどのように満たすかについての決定が含まれます。 機能的な そして 機能しない 要件。ドメイン駆動設計のコンテキストでは、ドメインの構造と動作を正確に反映する方法でソフトウェアを設計することに焦点が当てられます。

ドメイン駆動設計はプログラマーによって導入された概念です エリック・エヴァンス 2004年の彼の本の中で ドメイン駆動設計: ソフトウェアの中心部の複雑さへの取り組み

ドメイン知識の重要性

最新の技術スタックとインフラストラクチャをすべて使用してソフトウェアを設計し、ソフトウェア設計アーキテクチャは素晴らしいとします。しかし、このソフトウェアを市場にリリースするとき、システムが優れているかどうかを最終的に決めるのはエンドユーザーです。また、システムがビジネス ニーズを解決できなければ、誰の役にも立ちません。どんなに見た目が美しくても、そのインフラストラクチャがどれほど優れていても。



によると エリック・エヴァンス , ソフトウェアを開発するとき、主にテクノロジーに焦点を当てるのではなく、主にビジネスに焦点を当てる必要があります。覚えて、

顧客が何を望んでいるのかを知るのは顧客の仕事ではない – スティーブ・ジョブズ

ドメイン駆動設計(DDD)における戦略的設計

ドメイン駆動設計 (DDD) における戦略的設計は、問題ドメインに合わせた方法でソフトウェア システムの全体的なアーキテクチャと構造を定義することに重点を置いています。これは、ドメインの概念を整理する方法、システムを管理可能な部分に分割する方法、異なるコンポーネント間に明確な境界を確立する方法など、高レベルの懸念事項に対処します。

ドメイン駆動設計 (DDD) における戦略的設計の主要な概念をいくつか見てみましょう

b+ ツリー

1. 境界のあるコンテキスト

  • 境界コンテキストは、特定のモデルまたは言語が一貫して適用される、問題ドメイン全体内の特定の領域を表します。
  • システムの異なる部分では、同じ用語が異なる意味を持つ場合があり、境界コンテキストは、それらの用語が特定の意味を持つ明示的な境界を定義します。
  • これにより、チームは混乱や不一致を引き起こすことなく、特定のコンテキストに合わせたモデルを開発できます。
  • 境界付きコンテキストは、大規模で複雑なドメインをより小さく管理しやすい部分に分割することで、複雑さを管理するのに役立ちます。

2. コンテキストマッピング

  • コンテキスト マッピングは、異なる境界コンテキスト間の関係と相互作用を定義するプロセスです。
  • これには、コンテキスト間の重複または統合の領域を特定し、それらの間のコミュニケーション チャネルと合意を確立することが含まれます。
  • コンテキスト マッピングは、システムのさまざまな部分が効果的に連携しながら、それらの間の明確な境界を維持できるようにするのに役立ちます。
  • コンテキスト マッピングには、パートナーシップ、共有カーネル、顧客とサプライヤーなど、さまざまなパターンと手法があります。

3. 戦略的パターン

  • 戦略パターンは、問題領域に合わせてソフトウェア システムのアーキテクチャを編成するための一般的なガイドラインまたは原則です。
  • これらのパターンは、複雑なシステムの設計における一般的な課題に対処するのに役立ち、システムを効果的に構築するための実証済みのアプローチを提供します。
  • 戦略的パターンの例には、集約、ドメイン イベント、破損防止レイヤーなどがあります。
  • これらのパターンは、ドメイン駆動設計で繰り返し発生する問題に対する解決策を提供し、システムのアーキテクチャが基礎となるドメインの概念を正確に反映することを保証します。

4. 共有カーネル

  • 共有カーネルは、異なる境界コンテキスト間の共通領域の特定と、複数のコンテキストで使用されるドメイン モデルの共有サブセットの確立を含む戦略的パターンです。
  • この共有サブセット、つまりカーネルは、各コンテキストが独自の異なるモデルを維持できるようにしながら、コンテキスト間のコラボレーションと統合を促進するのに役立ちます。
  • 共有カーネルは、コンテキスト間の依存関係を導入し、慎重に管理しないと結合を引き起こす可能性があるため、慎重に使用する必要があります。

5. 破損防止層 (ACL)

  • 破損防止レイヤーは、異なるモデルや言語を使用する外部システムやレガシー システムの影響からシステムを保護するのに役立つもう 1 つの戦略的パターンです。
  • ACL は、外部システムとコア ドメイン モデルの間の変換層として機能し、互換性を確保するために必要に応じてデータとメッセージを変換します。
  • これにより、必要に応じて外部システムと統合しながら、コア ドメイン モデルを純粋なままにして問題のドメインに集中させることができます。

6. ユビキタス言語

ユビキタス言語とは、ソフトウェア システムの開発に関与するすべての関係者間で一貫して普遍的に使用される共有語彙または言語を指します。この言語は、ドメインの知識と概念を正確に表す用語、フレーズ、概念で構成されています。

ユビキタス言語の重要な原則のいくつかは次のとおりです。

  • 共通理解 : ユビキタス言語の主な目標は、開発者、ドメイン専門家、ビジネス アナリスト、利害関係者を含む開発チームのすべてのメンバーの間で、問題ドメインに関する共通の理解を確立することです。共通言語を使用することで、関係者全員がより効果的にコミュニケーションを図り、ドメインの概念と要件を正確に伝えることができます。
  • 一貫性と明確さ : ユビキタス言語は、正確で明確な用語を使用することにより、コミュニケーションの一貫性と明確さを促進します。言語の各用語やフレーズには、明確で合意された意味がなければなりません。
  • ビジネスコンセプトとの整合性 : DDD で使用される言語は、ビジネス ドメインで使用される用語や概念と密接に一致している必要があります。これは、ドメイン専門家が問題ドメインについてどのように考え、話しているかを反映し、ソフトウェアが現実世界の概念とプロセスを正確に表現していることを保証する必要があります。
  • 進化の性質 : ユビキタス言語は静的なものではなく、チームがドメインをより深く理解し、要件が変化するにつれて時間の経過とともに進化します。新しい洞察、発見、またはビジネスの優先順位の変更を反映するように適応し、開発プロセス全体を通じて言語が関連性があり最新の状態に保たれるようにする必要があります。

ドメイン駆動設計 (DDD) における戦術的設計パターン

ドメイン駆動設計 (DDD) では、戦術的設計パターンは、ソフトウェア システム内のドメイン モデルを構造化および組織化するために使用される特定の戦略または手法です。これらのパターンは、開発者がドメインの複雑さを効果的に把握するのに役立ち、同時に保守性、柔軟性、拡張性も促進します。

DDD の主要な戦術的設計パターンのいくつかを見てみましょう。

1. エンティティ

エンティティは、明確な ID とライフサイクルを持つドメイン オブジェクトです。エンティティは、一意の識別子と変更可能な状態によって特徴付けられます。これらは、ドメイン内の特定の概念に関連する動作とデータをカプセル化します。

たとえば、銀行アプリケーションでは、BankAccount>エンティティには、口座番号、残高、所有者などのプロパティと、資金の入金、引き出し、または転送のメソッドが含まれる場合があります。

2. 値オブジェクト

値オブジェクトは、概念的に不変の値を表すドメイン オブジェクトです。エンティティとは異なり、値オブジェクトには明確なアイデンティティがなく、通常はエンティティの属性またはプロパティを表すために使用されます。値オブジェクトは、そのアイデンティティではなくプロパティに基づいて等価比較可能です。

たとえば、Money>value オブジェクトは、通貨の種類や金額などのプロパティをカプセル化して、特定の金額の通貨を表す場合があります。

3. 集計

  • アグリゲートは、データの一貫性とトランザクションの整合性を目的として単一のユニットとして扱われるドメイン オブジェクトのクラスターです。
  • 集計は 1 つ以上のエンティティと値オブジェクトで構成され、1 つのエンティティが集計ルートとして指定されます。
  • 集約ルートは、集約の内部状態にアクセスして変更するためのエントリ ポイントとして機能します。
  • 集約はドメイン モデル内で一貫性の境界を強制し、関連するオブジェクトへの変更がアトミックに行われることを保証します。

たとえば、電子商取引システムでは、Order>集合体は次のようなエンティティで構成される場合がありますOrderItem>そしてCustomer>、 とともにOrder>集約ルートとして機能するエンティティ。

4. リポジトリ

  • リポジトリは、ドメイン モデルからデータ アクセスと永続化ロジックを抽象化するメカニズムです。
  • リポジトリは、ドメイン オブジェクトのクエリと保存のための標準化されたインターフェイスを提供し、データの取得方法や保存方法の詳細を非表示にします。リポジトリは、ドメイン オブジェクトと、データベースや外部サービスなどの基礎となるデータ ストレージ メカニズムの間で変換するためのロジックをカプセル化します。
  • ドメイン モデルをデータ アクセスの問題から切り離すことで、リポジトリにより柔軟性と保守性が向上します。

たとえば、CustomerRepository>クエリと保存のメソッドを提供する可能性がありますCustomer>エンティティ。

5. 工場

  • 工場というのは、 創作パターン 複雑なドメイン オブジェクトのインスタンスを作成するロジックをカプセル化するために使用されます。ファクトリはオブジェクトのインスタンス化のプロセスを抽象化し、クライアントがその構造の詳細を知らなくてもオブジェクトを作成できるようにします。
  • ファクトリは、複雑な初期化ロジックが必要なオブジェクトや複数のステップが必要なオブジェクトを作成する場合に特に役立ちます。

たとえば、ProductFactory>のインスタンスの作成を担当する可能性がありますProduct>デフォルト構成のエンティティ。

6. サービス

  • サービスは、本来は特定のエンティティや値オブジェクトに属さない動作や操作を表すドメイン オブジェクトです。
  • サービスは、複数のオブジェクト上で動作するドメイン ロジック、またはオブジェクト間の対話を調整するドメイン ロジックをカプセル化します。
  • 通常、サービスはステートレスであり、特定のタスクの実行またはドメイン ルールの適用に重点を置いています。

たとえば、OrderService>注文を処理し、割引を適用し、配送料を計算する方法を提供する場合があります。

ドメイン駆動設計(DDD)の利点

  • 共通理解 :
    • これにより、ドメインの専門家、開発者、関係者間のコラボレーションが促進されます。
    • ユビキタス言語を通じて問題領域の共通理解を促すことで、チームはより効果的にコミュニケーションを図り、ソフトウェアがビジネスのニーズと要件を正確に反映できるようになります。
  • コアドメインに注力 :
    • これは、チームがアプリケーションのコア ドメイン、つまりビジネスに最も価値を提供するシステムの領域を特定し、優先順位を付けるのに役立ちます。開発作業をコア ドメインに集中させることで、チームはビジネス目標に直接取り組み、ソフトウェアを競合他社と差別化する機能を提供できます。
  • 変化に対する回復力 :
    • 問題ドメインに固有の複雑さと不確実性を反映する方法でドメインをモデル化することで、変化に強いソフトウェア システムを設計することに重点を置いています。
    • ソフトウェア開発の自然な部分として変化を受け入れることで、チームは進化するビジネス ニーズや市場状況により効果的に対応できます。
  • 懸念事項の明確な分離 :
    • DDD は、ドメイン ロジック、インフラストラクチャの問題、ユーザー インターフェイスの問題の間で問題を明確に分離することを奨励します。ドメイン ロジックを技術的な詳細やインフラストラクチャの問題から分離することで、チームは、特定の実装の詳細や技術的な選択に依存しない、クリーンで焦点を絞ったドメイン モデルを維持できます。
  • テスト容易性の向上 :
    • これにより、境界と動作が明確に定義されたドメイン オブジェクトの使用が促進され、ドメイン ロジックの正しさを検証する、より適切で焦点を絞ったテストの作成が容易になります。
    • テスト容易性を念頭に置いてソフトウェア システムを設計することで、チームはコードベースへの変更が安全かつ予測可能であることを保証し、回帰や意図しない副作用が発生するリスクを軽減できます。
  • 複雑なビジネスルールのサポート :
    • ドメイン モデル内の複雑なビジネス ルールとワークフローをモデル化して実装するためのパターンとテクニックを提供します。
    • ビジネス ルールをドメイン モデルで明示的に表すことにより、チームはソフトウェアがビジネス ドメインの複雑さを正確に反映し、ドメイン固有の制約と要件を強制することを保証できます。
  • ビジネス目標との整合性 :
    • 最終的には、ソフトウェア開発の取り組みをビジネスの戦略的目標および目的に合わせることを目的としています。問題領域の理解とモデル化に重点を置くことで、チームはビジネス目標を直接サポートし、イノベーションを推進し、利害関係者やエンドユーザーに価値を生み出すソフトウェア ソリューションを提供できます。

ドメイン駆動設計 (DDD) の課題

  • 複雑 :
    • DDD は、特に大規模で複雑なドメインで複雑さを引き起こす可能性があります。
    • 複雑なビジネス ドメインを正確にモデル化するには、そのドメインを深く理解する必要があり、曖昧さや不確実性への対処が必要になる場合があります。この複雑さを効果的に管理するには、慎重な計画、コラボレーション、専門知識が必要です。
  • ユビキタス言語の採用 :
    • ユビキタス言語 (ドメインの概念を正確に表す共有語彙) を確立して維持することは、困難な場合があります。ドメインの用語と意味を特定し、同意するには、開発者とドメインの専門家が協力する必要があります。
    • ユビキタス言語について合意を得るには、コミュニケーションの障壁を克服し、用語や視点の違いを調整する必要があるかもしれません。
  • 境界付きコンテキストの配置 :
    • 大規模で複雑なドメインでは、ドメインのさまざまな部分に個別のモデルと境界のあるコンテキストが存在する場合があります。これらの境界のあるコンテキストを調整し、コンテキスト間の一貫性を確保することは困難な場合があります。
    • 不一致や競合を避けるために、ドメインのさまざまな部分で作業するチーム間での明確なコミュニケーション、コラボレーション、調整が必要です。
  • 技術的な複雑さ :
    • DDD の原則とパターンを効果的に実装するには、新しいテクノロジー、フレームワーク、アーキテクチャ アプローチの採用が必要になる場合があります。 DDD を既存のシステムまたはレガシー コードベースと統合することは複雑になる可能性があり、DDD の原則に合わせて既存のコードをリファクタリングまたは再設計する必要がある場合があります。
    • DDD 導入を確実に成功させるには、パフォーマンス、拡張性、保守性などの技術的な課題に慎重に対処する必要があります。
  • 変化への抵抗 :
    • DDD を導入すると、従来の開発アプローチに慣れているチーム メンバーや、DDD が複雑すぎるまたは非現実的であると認識しているチーム メンバーからの抵抗に遭遇する可能性があります。
    • 変化に対する抵抗を克服するには、DDD の利点を実証し、懸念や懐疑に対処する効果的なコミュニケーション、教育、リーダーシップが必要です。
  • オーバーエンジニアリング :
    • DDD を適用する場合、チームが複雑なドメイン概念のモデル化に集中しすぎて、不必要な抽象化や複雑さを導入するオーバーエンジニアリングのリスクがあります。設計と実装が過度に複雑になるのを避けるためには、シンプルさと表現力の適切なバランスをとることが重要です。

ドメイン駆動設計 (DDD) のユースケース

  • 金融と銀行 :
    • 金融分野では、DDD を使用して、複雑な金融商品、取引、規制要件をモデル化できます。 DDD は、口座、トランザクション、ポートフォリオなどのドメイン概念を正確に表現することで、金融システムの完全性と一貫性を確保するのに役立ちます。また、リスク管理、コンプライアンス、レポートの改善も可能になります。
  • 電子商取引と小売 :
    • 電子商取引プラットフォームは、製品カタログ、在庫管理、価格設定、顧客の注文などの複雑な領域の概念を扱うことがよくあります。 DDD は、これらの概念を効果的にモデル化するのに役立ち、パーソナライズされた推奨事項、動的な価格設定、合理化された注文処理などの機能を有効にします。
  • ヘルスケアとライフサイエンス :
    • ヘルスケアでは、DDD を使用して患者記録、医療診断、治療計画、ヘルスケア ワークフローをモデル化できます。 DDD は、患者の人口統計、病歴、臨床プロトコルなどの領域概念を正確に表現することで、堅牢な電子医療記録 (EHR) システム、医療画像プラットフォーム、遠隔医療アプリケーションの開発を可能にします。
  • 保険 :
    • 保険会社は、さまざまな商品、保険契約、保険金請求、引受プロセスを管理しています。 DDD は、これらの複雑なドメイン概念のモデル化に役立ち、保険契約管理、保険金請求処理、リスク評価、保険数理分析などの機能を有効にします。
  • 不動産および不動産管理 :
    • 不動産および資産管理には、さまざまな不動産、リース、テナント、メンテナンス要求、金融取引の処理が含まれます。 DDD は、これらのドメイン概念を効果的にモデル化するのに役立ち、不動産リスト、リース管理、テナント ポータル、資産追跡などの機能を有効にします。

ドメイン駆動設計 (DDD) の実世界の例

問題文

たとえば、RideX という配車アプリケーションを開発しているとします。このシステムにより、ユーザーが配車をリクエストし、ドライバーが配車リクエストを受け入れることができ、ユーザーとドライバー間の配車調整が容易になります。

jQueryとは何ですか

ユビキタス言語

  1. ユーザー : RideX プラットフォームを通じて配車をリクエストする個人を指します。
  2. 運転者 : RideX プラットフォームを介してユーザーに配車を提供する個人を指します。
  3. 乗車リクエスト : 乗車場所、目的地、乗り物の好みなどの詳細を指定して、ユーザーの乗車リクエストを表します。
  4. 乗る : 乗車と降車の場所、運賃、所要時間などの詳細を含む、乗車の 1 つのインスタンスを表します。
  5. 乗車状況 : リクエスト済み、承認済み、進行中、完了などの配車の現在のステータスを表します。

境界のあるコンテキスト

  1. 乗車管理コンテキスト : 配車リクエスト、ドライバーへの配車割り当て、配車ステータスの更新など、配車のライフサイクルの管理を担当します。
  2. ユーザー管理コンテキスト : ユーザー認証、登録、乗車履歴や支払い方法などのユーザー固有の機能を処理します。
  3. ドライバー管理コンテキスト : ドライバーの認証、登録、空き状況、および収益や評価などのドライバー固有の機能を管理します。

エンティティと値オブジェクト

  1. ユーザーエンティティ : ユーザー ID、電子メール、パスワード、支払い情報などのプロパティを持つ、RideX プラットフォームの登録ユーザーを表します。
  2. ドライバーエンティティ : ドライバー ID、車両の詳細、ドライバーのステータスなどのプロパティを含む、RideX プラットフォームに登録されているドライバーを表します。
  3. 乗車リクエストエンティティ : リクエスト ID、乗車場所、目的地、乗車設定などのプロパティを含む、ユーザーの配車リクエストを表します。
  4. ライドエンティティ : 乗車 ID、乗車場所と降車場所、運賃、乗車ステータスなどのプロパティを含む、乗車の単一インスタンスを表します。
  5. 位置値オブジェクト : 緯度や経度などのプロパティを使用して地理的位置を表します。

集合体

  1. ライドアグリゲート : 集約ルートとしての乗車エンティティと、乗車リクエスト、ユーザー、ドライバー エンティティなどの関連エンティティで構成されます。 Ride Aggregate は、配車リクエストの処理、ドライバーの割り当て、配車ステータスの更新など、配車のライフサイクルを管理するためのロジックをカプセル化します。

リポジトリ

  1. ライドリポジトリ : 乗車の詳細の取得、乗車ステータスの更新、データベースへの乗車関連データの保存など、乗車関連エンティティのクエリと保存のためのメソッドを提供します。

サービス

  1. 配車サービス : ドライバーの空き状況、乗車場所への近さ、ユーザーの好みなどの要素に基づいて、利用可能なドライバーを配車リクエストに割り当てる責任を負います。
  2. 決済サービス : 完了した乗車の支払い処理、運賃の計算、支払いの処理、およびユーザーとドライバーの支払い情報の更新を処理します。

ドメインイベント

  1. 乗車リクエストイベント : ユーザーが配車をリクエストしたときにトリガーされるイベントを表します。これには、配車リクエストの詳細やユーザー ID などの情報が含まれます。
  2. RideAcceptedイベント : ドライバーが配車リクエストを受け入れたときにトリガーされるイベントを表します。これには、配車 ID、ドライバー ID、乗車場所などの情報が含まれます。

シナリオ例

  1. 配車をリクエストするユーザー : ユーザーは、乗車場所、目的地、乗車希望を指定して配車をリクエストします。 RideX は新しい乗車リクエスト エンティティを作成し、RideRequestedEvent をトリガーします。
  2. 乗車を受け入れるドライバー : ドライバーは RideX プラットフォームからの乗車リクエストを受け入れます。 RideX は、乗車ステータスを Accepted に更新し、ドライバーを乗車に割り当て、RideAcceptedEvent をトリガーします。
  3. 走行中 : ユーザーとドライバーが乗車を調整し、ドライバーが乗車場所に到着すると、乗車ステータスが「受付済み」から「進行中」に移行します。
  4. 乗車完了 : 目的地に到着すると、乗車ステータスが完了に更新されます。 RideX は運賃を計算し、支払いを処理し、それに応じてユーザーとドライバーの支払い情報を更新します。