次の方法で共有


戦術的 DDD を使用したマイクロサービスの設計

Azure Migrate

ドメイン駆動設計 (DDD) は、システム全体に対して単一の統一モデルを持つという考えに反対しています。 代わりに、システムを境界付きコンテキストに分割し、それぞれ独自のモデルを使用することをお勧めします。 DDD の戦略的フェーズでは、ビジネス ドメインをマップし、ドメイン モデルの境界付きコンテキストを定義します。

戦術的 DDD では、ドメイン モデルをより正確に定義します。 戦術的パターンは、1 つの境界付けられたコンテキスト内で適用されます。 各境界付きコンテキストがマイクロサービス候補であるマイクロサービス アーキテクチャでは、エンティティと集計パターンに注意が必要です。 これらのパターンを適用すると、アプリケーション内のサービスの自然な境界を特定するのに役立ちます。 詳細については、「 マイクロサービスの境界を特定する」を参照してください。 一般的な原則として、マイクロサービスは集約よりも小さくなく、バウンデッドコンテキストよりも大きくならないことが望ましいです。

この記事では、戦術的パターンを確認し、ドローン配送アプリケーションの出荷境界コンテキストに適用します。

戦術的パターンの概要

このセクションでは、戦術的な DDD パターンの簡単な概要を示します。 DDD に慣れている場合は、それをスキップすることを選択できます。 これらのパターンの詳細については、Eric Evans の書籍の第 5 章と 6 章と、ヴォーン バーノンによる Domain-Driven デザインの実装 に関するページで詳しく説明されています。

DDD の戦術的パターンの図。

エンティティ: エンティティは、時間の経過に関係なく保持される一意の ID を持つオブジェクトです。 たとえば、銀行取引アプリケーションでは、顧客と口座がエンティティになります。

  • システムでは、エンティティに一意識別子が割り当てられており、エンティティの検索や取得に使うことができます。 この識別子は必ずユーザーに対して直接公開されているわけではありません。 データベースの GUID や主キーがこれに該当します。

  • ID は複数の境界付きコンテキストにまたがる可能性があり、アプリケーションの有効期間を超えて保持される可能性があります。 たとえば、銀行口座番号や政府発行 ID は、特定のアプリケーションに関連付けられません。

  • エンティティの属性は、時間の経過と同時に変化する可能性があります。 たとえば、ユーザーの名前や住所は変更される可能性がありますが、同じ個人のままです。

値オブジェクト: 値オブジェクトには ID がありません。 属性の値によってのみ定義されます。 値オブジェクトは変更できません。 値オブジェクトを更新するために、古いインスタンスを置き換える新しいインスタンスが作成されます。 値オブジェクトにはドメイン ロジックをカプセル化するメソッドを含めることができますが、それらのメソッドは副作用を生成したり、オブジェクトの状態を変更したりしてはなりません。 値オブジェクトの一般的な例としては、色、日付と時刻、通貨値があります。

集約: 集約では、1 つ以上のエンティティを囲む一貫性の境界を定義します。 集約内の 1 つのエンティティはルートです。 ルート エンティティの識別子を使って、検索が行われます。 集約内のその他のエンティティはルートの子であり、ルートからのポインターをたどることによって参照されます。

集約の目的は、トランザクションのインバリアントをモデル化することです。 現実世界のものには複雑な関係があります。 たとえば、顧客が注文を作成し、注文には商品が含まれ、商品には供給業者が存在する、などの関係です。 アプリケーションがいくつかの関連オブジェクトを変更する場合は、どのように一貫性を保証するのでしょうか。 また、インバリアントを追跡して実現するにはどうすればよいでしょうか。

従来のアプリケーションでは、多くの場合、データベース トランザクションを使って一貫性を実現します。 しかし、分散アプリケーションでは、多くの場合、これを実現できません。 1 つのビジネス トランザクションが複数のデータ ストアにまたがる場合、トランザクションの実行時間が長い場合、またはトランザクションにサード パーティのサービスが関与する場合があります。 最終的に、ドメインに必要なインバリアントの実現は、データ レイヤーではなくアプリケーションに依存します。 それが集約によってモデル化されるものです。

注意

集約は 1 つのエンティティで構成され、子エンティティはありません。 エンティティが集約になるために必要なのはトランザクション境界です。

ドメイン サービスとアプリケーション サービス: DDD の用語では、サービスとは、状態を保持せずにいくつかのロジックを実装するオブジェクトです。 Evans 氏は、ドメイン ロジックをカプセル化するドメイン サービスと、技術的な機能 (ユーザー認証や SMS メッセージの送信など) を提供するアプリケーション サービスを区別しています。 ドメイン サービスは、多くの場合、複数のエンティティにまたがる動作のモデル化に使われます。

注意

ソフトウェア開発においては、サービスという用語に過剰な負荷がかかっています。 ここで使用する定義は、マイクロサービスに直接関連していません。

ドメイン イベント: ドメイン イベントは、何かが発生したときにシステムの他の部分に通知できます。 名前が示すように、ドメイン イベントはドメイン内で意味のあるものを表す必要があります。 たとえば、"テーブルにレコードが挿入されました" はドメイン イベントではありません。 "配信が取り消されました" はドメイン イベントです。 ドメイン イベントは、マイクロサービス アーキテクチャで特に重要です。 マイクロサービスは分散され、データ ストアを共有しないため、ドメイン イベントによってサービス間の調整が可能になります。 非同期メッセージングの詳細については、「 サービス間通信」を参照してください。

ファクトリ、リポジトリ、モジュールなど、ここでは取り上げない DDD パターンがいくつかあります。 これらのパターンは、マイクロサービスを実装する場合に役立ちますが、マイクロサービス間の境界を設計する場合は関連性が低くなります。

ドローン配送:パターンの適用

最初に、境界付けられたコンテキスト "出荷" が処理する必要のあるシナリオを見てみましょう。

  • 顧客は、ドローン配送サービスに登録された企業からドローンで商品を集荷するよう依頼できます。
  • 荷送人は、タグ (バーコードまたは RFID) を生成して荷物に取り付けます。
  • ドローンが集荷先から荷物を集荷して、配送先に届けます。
  • 顧客が配送をスケジュールするときに、システムはルート情報、気象条件、履歴データに基づいて ETA を提供します。
  • ドローンの飛行中、ユーザーは現在地と最新の ETA を追跡できます。
  • ドローンによる荷物の集荷が完了するまで、顧客は配送をキャンセルできます。
  • 配送が完了すると、顧客に通知が送信されます。
  • 荷送人は、署名またはフィンガープリントの形式で顧客から配送の確認を要求できます。
  • ユーザーは、完了した配送の履歴を検索できます。

これらのシナリオから、開発チームは以下のエンティティを識別しました。

  • 配送
  • パッケージ
  • ドローン
  • アカウント
  • 確認
  • 通知
  • タグ

最初の 4 つ (配送、荷物、ドローン、アカウント) はすべて、トランザクションの一貫性の境界を表す集約です。 "確認" と "通知" は "配送" の子エンティティです。"タグ" は "荷物" の子エンティティです。

この設計の値オブジェクトには Location、ETA、PackageWeight、および PackageSize があります。

"配送" 集約の UML 図を次に示します。 この集約は、他の集約 (アカウント、荷物、ドローン) への参照を保持します。

配信集計の UML 図。

次の 2 つのドメイン イベントがあります。

  • ドローンの飛行中、"ドローン" エンティティはドローンの場所と状態 (飛行中、着陸) を示す DroneStatus イベントを送信します。

  • "配送" エンティティは、配送の段階が変わるたびに DeliveryTracking イベントを送信します。 DeliveryTracking イベントには、DeliveryCreated、DeliveryRescheduled、DeliveryHeadedToDropoff、DeliveryCompleted が含まれます。

これらのイベントは、ドメイン モデル内で意味のある内容を示しています。 これらはドメインに関する情報を示すものであり、特定のプログラミング言語コンストラクトに関連付けられません。

開発チームは、これまでに記述されたどのエンティティにも当てはまらないもう 1 つの機能分野を識別しました。 システムの一部では、配送のスケジューリングまたは更新に関連するすべての手順を調整する必要があります。 そのため、開発チームは 2 つの ドメイン サービス を設計に追加しました。手順を調整する Scheduler と、ステップが失敗したかタイムアウトしたかを検出するために、各ステップの状態を監視する Supervisor です。この方法は、 Scheduler Agent Supervisor パターンのバリエーションです。

変更後のドメイン モデルの図。

次のステップ

次の手順では、各マイクロサービスの境界を定義します。