アプリケーションを分析し、分解の境界を特定する
アプリケーションをマイクロサービス アーキテクチャに移行するには、Fabrikam は現在のアプリケーションを評価し、各マイクロサービスのスコープと境界を決定する必要があります。 この評価では、 ドメイン駆動設計 (DDD) フレームワークを使用します。 アプリケーションに適用する方法を見てみましょう。
注
この記事では、ドメインの完全かつ包括的な分析については説明しません。 この例を意図的に簡潔にして、主な点を説明しました。 DDD の詳細については、このモジュールの最後にある概要の「詳細情報」セクションを参照してください。
ドメイン駆動型設計とは
DDDは、2005年にErik Evansが2005年の書籍「 Domain-Driven デザイン:ソフトウェアの中心における複雑さに取り組む」で最初に紹介したシステムデザインのアプローチです。 このアプローチには、次の 3 つの重要な要素が含まれます。
- コア ドメインとドメイン ロジックに焦点を当てます。
- ドメインのモデルで設計を構成します。
- 技術チームとビジネス パートナー間の反復的なコラボレーションを推進して、システムを絶えず改善します。
DDD には、適切に設計されたマイクロサービスのセットへのほとんどの方法を利用できるフレームワークが用意されています。 戦略 と 戦術の 2 つの異なるフェーズ があります。 戦略的 DDD では、システムの大規模な構造を定義します。 戦略的 DDD は、アーキテクチャがビジネス機能に焦点を当てた状態を維持するために役立ちます。 戦術的 DDD は、ドメイン モデルの作成に使うことのできる一連の設計パターンを提供します。 これらのパターンには、エンティティ、集約、およびドメイン サービスがあります。 これらの戦術的パターンは、疎結合でまとまりのあるマイクロサービスを設計するのに役立ちます。
DDD の戦略的フェーズでは、ビジネス ドメインをマップし、ドメイン モデルの境界付きコンテキストを定義します。 戦術的 DDD では、ドメイン モデルをより正確に定義します。 戦術的パターンは、1 つの境界付けられたコンテキスト内で適用されます。 マイクロサービス アーキテクチャでは、エンティティと集計パターンに関心があります。 これらのパターンを適用すると、アプリケーション内のサービスの自然な境界を特定するのに役立ちます。 一般的な原則として、マイクロサービスは集約よりも小さくなく、バウンデッドコンテキストよりも大きくならないことが望ましいです。
大まかに言うと、このプロセスを次の 4 つの手順に分割できます。
- ビジネス ドメインを分析して、アプリケーションの機能要件を理解します。 この手順により、正式でないドメインの記述が生成されます。この記述をより正式なドメイン モデルのセットに作り替えることができます。
- ドメインの境界付けられたコンテキストを定義します。 境界付けられた各コンテキストには、大規模なアプリケーションの特定のサブドメインを表すドメイン モデルが含まれています。
- 境界付けられたコンテキスト内で、戦術的 DDD パターンを適用して、エンティティ、集約、およびドメイン サービスを定義します。
- 前の手順の結果を使用して、アプリケーション内のマイクロサービスを特定します。
これらの各手順で何が起こるかを詳しく見てみましょう。
ビジネス ドメインの分析
DDD は、まずビジネス ドメインをモデル化し、ドメイン モデルを作成します。 ドメイン モデルはビジネス用ドメインの抽象化モデルです。 ドメインの知識を蒸留して整理し、開発者とドメインの専門家に共通の言語を提供します。
最初に、すべてのビジネス機能とその関係をマッピングします。 この分析は、ドメインの専門家、ソフトウェア アーキテクト、およびその他の利害関係者が関与する共同作業です。 特定の形式を使う必要はありません。 図面をスケッチするか、ホワイトボードに描画します。
図を入力すると、個別のサブドメインの識別が開始される場合があります。 密接に関連している機能はどれか、 ビジネスの中核となる機能はどれか、付帯的なサービスを提供する機能はどれか、 依存関係グラフとは何かを確認します。 この最初のフェーズでは、テクノロジや実装の詳細を気にすることはありません。 ただし、アプリケーションを外部システム (CRM、支払処理、課金システムなど) と統合する必要がある場所に注意する必要があります。
境界付けられたコンテキストを定義する
ドメイン モデルには、ユーザー、ドローン、パッケージなど、世界の実際の物の表現が含まれています。 ただし、同じものについてシステム全体で同じ表現を使わなければならないというわけではありません。
たとえば、ドローンの修理と予測分析を処理するサブシステムは、ドローンの多くの物理的特性を表す必要があります。 これらの特性には、メンテナンス履歴、走行距離、年齢、モデル番号、およびパフォーマンスの詳細が含まれます。 しかし、配送をスケジュールするときは、それらについて考慮しません。 スケジューリング サブシステムは、ドローンが使用可能かどうかと、集荷と配送の推定到着時間 (ETA) のみを把握する必要があります。
両方のサブシステムに対して 1 つのモデルを作成しようとすると、必要以上に複雑になります。 また、変更が個別のサブシステムで動作する複数のチームを満たす必要があるため、モデルの進化は時間の経過とともに困難になります。 多くの場合、2 つの異なるコンテキストで同じ現実世界のエンティティ (この場合はドローン) を表す個別のモデルを設計することをお勧めします。 各モデルには、特定のコンテキスト内に関連する機能と属性だけが含まれます。
このアプローチでは、境界付けられたコンテキストの DDD の概念が有効になります。 境界付けられたコンテキストは、特定のドメイン モデルが適用されるドメイン内の単なる境界です。 前の図を見ると、さまざまな関数が 1 つのドメイン モデルを共有しているかどうかに応じて機能をグループ化できます。
エンティティ、集計、およびサービスを定義する
戦術的 DDD では、ドメイン モデルをより正確に定義します。 戦術的パターンは、1 つの境界付けられたコンテキスト内で適用されます。 マイクロサービス アーキテクチャでは、エンティティと集計パターンに関心があります。 これらのパターンを適用すると、アプリケーション内のサービスの自然な境界を特定するのに役立ちます。 一般的な原則として、マイクロサービスは集約よりも小さくなく、境界づけられたコンテキストよりも大きくないようにします。
考慮すべき戦術的な DDD パターンがいくつかあります。
- エンティティ: エンティティは、時間の経過と共に保持される一意の ID を持つオブジェクトです。 たとえば、銀行アプリケーションでは、顧客と口座はエンティティです。
- 値オブジェクト: 値オブジェクトに ID がありません。 その属性の値によって定義され、不変です。 値オブジェクトの一般的な例として、色、日付と時刻、通貨の値が挙げられます。
- 集計: 集計では、1 つ以上のエンティティに関する整合性境界が定義されます。 集約の目的は、トランザクションのインバリアントをモデル化することです。 現実世界のものには複雑な関係があります。 たとえば、顧客が注文を作成し、注文には商品が含まれ、商品には供給業者が存在する、などの関係です。 アプリケーションがいくつかの関連オブジェクトを変更する場合は、どのように一貫性を保証するのでしょうか。 また、インバリアントを追跡して実現するにはどうすればよいでしょうか。
- ドメインおよびアプリケーション サービス: DDD の用語では、サービスは状態を保持せずに何らかのロジックを実装するオブジェクトです。 Evans は、ドメイン ロジックをカプセル化するドメイン サービスと、技術的な機能を提供するアプリケーション サービスを区別します。 通常、アプリケーション サービスには、ユーザー認証や SMS メッセージの送信などの技術的な機能が含まれます。 ドメイン サービスは、多くの場合、複数のエンティティにまたがる動作のモデル化に使われます。
- ドメイン イベント: ドメイン イベントは、何かが発生したときにシステムの他の部分に通知するために使用できます。 その名前が示すように、ドメイン イベントはドメイン内で発生するイベントです。 たとえば、"テーブルにレコードが挿入されました" はドメイン イベントではありません。 "配信が取り消されました" はドメイン イベントです。 ドメイン イベントはマイクロサービスのアーキテクチャに特に関連します。 マイクロサービスは分散型であり、データ ストアを共有しないので、ドメイン イベントはマイクロサービスが互いに連携するための方法を提供します。
そのシステムで、Fabrikam 開発チームは次のエンティティを特定しました。
- 配達
- 荷物
- ドローン
- アカウント
- 確認
- 通知
- タグ
最初の 4 つのエンティティ (配信、パッケージ、ドローン、アカウント) はすべて、トランザクションの整合性境界を表す集計です。 確認と通知は配送の子エンティティです。 タグはパッケージの子エンティティです。
このデザインの値オブジェクトには、Location、ETA、PackageWeight、PackageSize が含まれます。
次の 2 つのドメイン イベントがあります。
- ドローンの飛行中、ドローン エンティティはドローンの位置と状態を説明する DroneStatus イベント (たとえば、飛行中) を送信します。
- 配信エンティティは、配信のステージが変更されるたびに DeliveryTracking イベントを送信します。 これらのイベントには、DeliveryCreated、DeliveryRescheduled、DeliveryHeadedToDropoff、DeliveryCompleted などがあります。
これらのイベントは、ドメイン モデル内で意味のある内容を示しています。 これらはドメインに関する何かを記述し、特定のプログラミング言語コンストラクトに関連付けられません。
開発チームは、これまでに記述されたどのエンティティにも当てはまらないもう 1 つの機能分野を識別しました。 システムの一部では、配送のスケジューリングまたは更新に関連するすべての手順を調整する必要があります。 開発チームは、設計に 2 つのドメイン サービスを追加しました。 Scheduler によってステップが調整されます。 Supervisor は、ステップが失敗したかタイムアウトしたかを検出するために、各ステップの状態を監視します。
マイクロサービスを識別する
これで、ドメイン モデルからアプリケーション設計に進む準備ができました。 ドメイン モデルからマイクロサービスを派生させるために使用できるアプローチを次に示します。
- 境界付きコンテキストから始めます。 一般に、マイクロサービスの機能は、複数の境界付けられたコンテキストにまたがるべきではありません。 定義上、境界付きコンテキストは、特定のドメイン モデルの境界をマークします。 マイクロサービスが異なるドメイン モデルを混在させる場合は、ドメイン分析を調整する必要がある兆候です。
- 次に、ドメイン モデルの集計を確認します。 多くの場合、集計はマイクロサービスの候補として適しています。 適切に設計された集計は、適切に設計されたマイクロサービスの特性の多くを示しています。
- 集計は、データ アクセスやメッセージングなどの技術的な問題ではなく、ビジネス要件から派生します。
- 集計には、高い機能の凝集性が必要です。
- 集約は永続化の境界です。
- 集計は疎結合する必要があります。
- ドメイン サービスは、マイクロサービスの候補としても適しています。 ドメイン サービスは、複数の集計にわたるステートレス操作です。 一般的な例は、複数のマイクロサービスを含むワークフローです。 後で、ドローン配送アプリケーションのドメイン サービスの例を確認します。
- 最後に、機能しない要件を検討します。 チーム サイズ、データ型、テクノロジ、スケーラビリティ要件、可用性要件、セキュリティ要件などの要因を確認します。 これらの要因により、マイクロサービスをさらに 2 つ (またはそれ以上) 小さなサービスに分解したり、逆の処理を行って複数のマイクロサービスを 1 つに結合したりする可能性があります。
実用的であることが重要であり、ドメイン駆動型の設計は反復的なプロセスであることを覚えておいてください。 不明な場合は、より粗いマイクロサービスから始めます。 複数の既存のマイクロサービス間で機能をリファクタリングするよりも、マイクロサービスを 2 つの小さなサービスに分割する方が簡単です。
ドメイン駆動設計をドローン アプリケーションに適用する
Fabrikam のアプリケーションの場合、これらのサービスはすべて既存のモノリシック アプリケーションに存在します。 アプリケーションをマイクロサービスに分解できる場所を特定したら、パッケージ サービスから開始します。
パッケージ サービスには現在、重点を置いた開発チームがあり、スケーラビリティに関連するパフォーマンスの問題が示されており、アプリケーションの分解を開始するのに最適な候補です。