次の方法で共有


ドメイン分析を使用したマイクロサービスのモデル化

マイクロサービスの最大の課題の 1 つは、個々のサービスの境界の定義です。 原則として 1 つのサービスは "1 つのこと" を行う必要がありますが、その実現のためには慎重な検討が必要です。 "適切" な設計を作り出す機械的なプロセスはありません。 ビジネス ドメイン、要件、アーキテクチャの特性 (非機能要件とも呼ばれます) と目標について深く考える必要があります。 そうしないと、好ましくない特徴 (サービス間の非表示の依存関係、密結合、不完全なデザインのインターフェイスなど) を持つ場当たり的な設計になる可能性があります。 この記事では、マイクロサービスを設計するためのドメイン駆動のアプローチについて説明します。 サービス境界の評価は、進化するワークロードに対する継続的な取り組みです。 評価の結果、既存の境界の定義が再定義され、変更に対応するために追加のアプリケーション開発が必要になることがあります。

この記事では、継続的な例としてドローン配送サービスを使用します。 シナリオおよび対応する参照実装の詳細については、こちらを参照してください。

はじめに

マイクロサービスは、データ アクセスやメッセージングなどの水平レイヤーではなく、ビジネス機能に基づいて設計する必要があります。 また、マイクロサービスには疎結合と機能の高い凝集度が必要です。 他のサービスを同時に更新せずにサービスを変更できる場合、マイクロサービス同士はゆるやかに結び付いています。 明確に定義された 1 つの目的 (ユーザー アカウントの管理、配送履歴の追跡など) を持つマイクロサービスは高凝集です。 サービスはドメイン ナレッジをカプセル化し、クライアントからそのナレッジを抽象化する必要があります。 たとえば、クライアントは、スケジューリング アルゴリズムの詳細やドローン フリートの管理方法を知らなくてもドローンのスケジュールを設定できる必要があります。 アーキテクチャの特性は、システム全体に対して定義されるのではなく、そのドメインの懸念事項に合わせてマイクロサービスごとに定義する必要があります。 たとえば、顧客向けのマイクロサービスには、パフォーマンス、可用性、フォールト トレランス、セキュリティ、テスト容易性、機敏性が必要な場合があります。 バックエンド マイクロサービスには、フォールト トレランスとセキュリティのみが必要な場合があります。 マイクロサービスが相互に同期通信を行っている場合、それらの間の依存関係により、多くの場合、同じアーキテクチャ特性を共有する必要があります。

ドメイン駆動設計 (DDD) は、適切に設計された一連のマイクロサービスを作り出すためのフレームワークを提供します。 DDD には 2 つの異なるフェーズ (戦略と戦術) があります。 戦略的 DDD では、システムの大規模な構造を定義します。 戦略的 DDD は、アーキテクチャがビジネス機能に焦点を当てた状態を維持するために役立ちます。 戦術的 DDD は、ドメイン モデルの作成に使うことのできる一連の設計パターンを提供します。 これらのパターンには、エンティティ、集約、およびドメイン サービスがあります。 このような戦術的パターンを使うと、疎結合および高凝集のマイクロサービスを設計できます。

ドメイン駆動設計 (DDD) プロセスの図

この記事と次の記事では、以下の手順について説明し、それらをドローン配送アプリケーションに適用します。

  1. 最初にビジネス用ドメインを分析し、アプリケーションの機能的な要件を理解します。 この手順により、正式でないドメインの記述が生成されます。この記述をより正式なドメイン モデルのセットに作り替えることができます。

  2. 次に、ドメインの境界付けられたコンテキストを定義します。 境界付けられた各コンテキストには、大規模なアプリケーションの特定のサブドメインを表すドメイン モデルが含まれています。

  3. 境界付けられたコンテキスト内で、戦術的 DDD パターンを適用して、エンティティ、集約、およびドメイン サービスを定義します。

  4. 前の手順の結果を使って、アプリケーションのマイクロサービスを識別します。

この記事では、DDD と主に関連のある最初の 3 つの手順について説明します。 マイクロサービスの識別は次の記事で行います。 ただし、DDD は反復的かつ継続的なプロセスであることを覚えておいてください。 サービスの境界は固定されていません。 アプリケーションの進化に伴って、1 つのサービスを複数の小さなサービスに分割することができます。

注意

この記事では、ドメインの完全かつ包括的な分析については説明しません。 主要なポイントを示すために、あえて簡単な例を取り上げています。 DDD の詳しい背景情報については、この用語を最初に紹介した Eric Evans 氏の著書『Domain-Driven Design』をお読みになることをお勧めします。 その他の参考資料としては、Vaughn Vernon 氏の著書『Implementing Domain-Driven Design』があります。

シナリオ:ドローン配送

Fabrikam, Inc. は、ドローン配送サービスを開始しようとしています。 同社は、ドローン機団を管理しています。 企業がサービスに登録すると、ユーザーは、ドローンで商品を集荷して配送するように依頼できます。 顧客が集荷のスケジュールを設定すると、バックエンド システムによってドローンが割り当てられ、推定配送時刻がユーザーに通知されます。 配送中、ETA は常時更新され、顧客はドローンの場所を追跡できます。

このシナリオには、かなり複雑なドメインが含まれます。 ビジネスに関する懸念事項には、ドローンのスケジュール設定、荷物の追跡、ユーザー アカウントの管理、履歴データの保存と分析などもあります。 さらに、Fabrikam が求めているのは、迅速に市場に出し、迅速に反復して、新機能を追加することです。 アプリケーションは、高いサービス レベル目標 (SLO) に基づいてクラウド スケールで動作する必要があります。 また、Fabrikam は、システムの部分ごとに、データ ストレージとクエリの要件がまったく異なることを予期しています。 Fabrikam はこれらをすべて考慮した結果、ドローン配送アプリケーションにマイクロサービス アーキテクチャを選択します。

ドメインを分析する

DDD アプローチを使うと、各サービスがビジネスの機能的な要件に適合するようなマイクロサービスを設計できます。 また、組織の境界やテクノロジの選択が設計に影響するというトラップを回避できます。

コードを記述する前に、作成するシステムを俯瞰する必要があります。 DDD では、最初にビジネス用ドメインをモデリングして、ドメイン モデルを作成します。 ドメイン モデルはビジネス用ドメインの抽象化モデルです。 このモデルはドメイン ナレッジを抽出して整理し、開発者やドメイン エキスパートに共通の言語を提供します。

最初に、すべてのビジネス機能とその関係をマッピングします。 これは、ドメイン エキスパート、ソフトウェア アーキテクト、およびその他の関係者が関与する共同作業になる可能性があります。 特定の形式を使う必要はありません。 図をスケッチするか、ホワイトボードに描画します。

図を描画したら、個別のサブドメインの識別を開始できます。 密接に関連している機能はどれか、 ビジネスの中核となる機能はどれか、付帯的なサービスを提供する機能はどれか、 依存関係グラフとは何かを確認します。 この最初のフェーズでは、テクノロジや実装の詳細を気にすることはありません。 とは言え、アプリケーションを外部システム (CRM、支払い処理、請求システムなど) と統合する必要のある場所について注意する必要があります。

例:ドローン配送アプリケーション

最初のいくつかのドメイン分析の完了後、Fabrikam のチームはドローン配送ドメインを示すおおまかなスケッチを作成しました。

ドローン配送ドメインの図

  • 出荷はビジネスの中核であるため、図の中央に配置します。 図のそれ以外の要素は、この機能を実現するために存在します。
  • ドローンの管理もビジネスの中核です。 ドローン管理と密接に関連する機能には、ドローンの修理、および予測分析によるドローンの付帯サービスとメンテナンスが必要な時期の予測があります。
  • ETA 分析は集配の時間を見積もります。
  • サード パーティの輸送では、荷物をドローンで出荷できない場合の代替輸送方法をアプリケーションでスケジュールできます。
  • ドローンの共有は、コア ビジネスを拡張するものです。 企業では、ドローンが空きがある期間に、使われていないドローンを貸し出すことができます。 この機能は、初期リリースには含まれていません。
  • ビデオ監視は、企業が後から展開する可能性のあるもう 1 つの分野です。
  • ユーザー アカウント請求、およびコール センターは、コア ビジネスをサポートするサブドメインです。

プロセスのこの時点では、実装やテクノロジに関する決定を行っていません。 一部のサブシステムには、外部のソフトウェア システムやサード パーティのサービスが含まれている可能性があります。 その場合でも、アプリケーションはこれらのシステムやサービスとやり取りする必要があるため、ドメイン モデルにシステムやサービスを追加することが重要です。

注意

アプリケーションが外部システムに依存する場合は、外部システムのデータ スキーマや API がアプリケーションに漏えいし、最終的にアーキテクチャの設計が損なわれるというリスクがあります。 これは、最新のベスト プラクティスに従っていない、および複雑なデータ スキーマや古い API を使っている従来のシステムに特に当てはまります。 その場合は、これらの外部システムとアプリケーション間の境界を明確に定義することが重要です。 そのためには、ストラングラー フィグ パターン破損対策レイヤー パターンの使用を検討してください。

境界付けられたコンテキストを定義する

ドメイン モデルには、世界中に存在する実際のもの (ユーザー、ドローン、荷物など) の表現が含まれます。 ただし、同じものについてシステム全体で同じ表現を使わなければならないというわけではありません。

たとえば、ドローンの修理と予測分析を扱うサブシステムでは、ドローンの多くの物理的特性 (メンテナンス履歴、マイレージ、年数、モデル番号、性能特性など) を表す必要があります。 しかし、配送をスケジュールするときは、それらについて考慮しません。 スケジューリング サブシステムでは、ドローンが使用可能か、および集配の ETA だけを把握する必要があります。

これらの 2 つのサブシステムに対して 1 つのモデルを作成しようとすると、不必要に複雑なモデルになります。 また、変更を行う場合に複数のチームが個々のサブシステムに対して作業を行う必要があるため、時間の経過と共にモデルの進化が難しくなります。 そのため、多くの場合、現実世界のエンティティ (ここではドローン) を 2 つの異なるコンテキストで表す個別のモデルを設計することをお勧めします。 各モデルには、特定のコンテキスト内に関連する機能と属性だけが含まれます。

ここで、境界付けられたコンテキストという DDD の概念が作用します。 境界付けられたコンテキストは、特定のドメイン モデルが適用されるドメイン内の単なる境界です。 前述の図では、さまざまな機能が 1 つのドメイン モデルを共有するかどうかに従って機能をグループ化できます。

境界付けられたコンテキストの図

境界付けられたコンテキストは、必ずしも互いに分離された状態である必要はありません。 この図では、境界付けられたコンテキストを結ぶ実線は、2 つの境界付けられたコンテキストがやり取りする場所を表します。 たとえば、"出荷" は顧客の情報を取得するために "ユーザー アカウント" に依存し、フリートのドローンをスケジュールするために "ドローン管理" に依存します。

Eric Evans 氏は、著書『Domain Driven Design』で、別の境界付けられたコンテキストとやり取りする際にドメイン モデルの整合性を維持するための複数のパターンについて説明しています。 マイクロサービスの主要な原則の 1 つは、明確に定義された API を通じてサービスがやり取りするということです。 このアプローチは、Evans 氏が Open Host Service および Published Language と呼ぶ 2 つのパターンに対応します。 Open Host Service では、サブシステムが他のサブシステムとやり取りするための正式なプロトコル (API) を定義します。 Published Language は、他のチームがクライアントを記述するために使うことのできる形式で API を発行することにより、この考え方を拡張したものです。 「Designing APIs for microservices」(マイクロサービス用 API の設計) の記事では、OpenAPI 仕様 (旧称 Swagger) を使って、JSON または YAML 形式で表現された、REST API 用の言語に依存しないインターフェイスの記述を定義する方法について説明します。

この記事の以降の部分では、境界付けられたコンテキスト "出荷" について重点的に説明します。

次のステップ

ドメイン分析の完了後、次の手順では戦術的 DDD を適用して、より高い精度でドメイン モデルを定義します。