バックグラウンド
リファレンスエンジニアリングアーキテクチャを開発する理由
DDD を実装するためにチームによって採用されるアプリケーション アーキテクチャ スタイルは異なる場合があり、統一された標準的な DDD エンジニアリング アーキテクチャは存在しません。古典的な DDD 4 層アーキテクチャまたは改良された DDD 4 層アーキテクチャを採用するチームもあれば、レイヤード アーキテクチャ、ニート アーキテクチャ、ヘキサゴナル アーキテクチャなどのさまざまなアーキテクチャ スタイルを包括的に検討するチームもあり、問題を解決するために実際に CQRS を導入するチームもいます。読み取りの問題、モデルと書き込みモデルの違いなど。たとえ共通の標準的なエンジニアリング アプリケーション アーキテクチャを策定することが不可能であっても、チームのドメイン駆動設計アイデアに従うリファレンス アーキテクチャを開発することは依然として価値があります。次のような理由からです。
- DDD を実践するためのチームの戦術設計のためのクイックスタート エンジニアリング リファレンスを提供します。
- プロジェクトの多数の命名および構造上の決定を参照し、DDD の関連概念を明示的に反映し、チームが DDD の戦術的実装について合意に達するのを支援します。
- 同時に、リファレンス アーキテクチャは、ドメイン駆動設計に関するチームの考えとベスト プラクティスの一部を促進するのに役立ちます。
リファレンスアーキテクチャの考慮事項
完全に一般的な DDD リファレンス アーキテクチャを定式化することは不可能ですが、特定のコンテキストでリファレンス アーキテクチャを定式化することは可能であり、実用的です。コンテキストの選択は、実際のエンジニアリング実践シナリオに可能な限り近づけ、多次元の要素を考慮する必要があります。
この記事で説明するリファレンス エンジニアリング アーキテクチャは、次の原則に従っています。
- ドメイン駆動設計の基本的な考え方に従ってください
- 業務システム構築の特性を十分に考慮
- 依存関係を最小限に抑え、軽量に保ちます
エンジニアリング参照アーキテクチャが次の領域をカバーすることが期待されます。
- ビジネス領域と技術領域の分離
参照アーキテクチャはテクノロジーとビジネスの分離の特性に従っている必要があり、さまざまなアーキテクチャ スタイルを参照できます。ビジネスと技術の分離は DDD に特有の機能ではなく、ヘキサゴナル、クリーン アーキテクチャ、オニオン アーキテクチャでもこの重要な原則が踏襲されています。
- 複数の境界付きコンテキストのシナリオ
ほとんどのチームが DDD に基づいてマイクロサービスを分割する場合、特にシステム構築の初期段階では、単一のマイクロサービス アプリケーション内の境界付きコンテキストの粒度を考慮する必要があります。チームの組織構造要因とマイクロサービスのコストの問題により、通常、単一のアプリケーションは複数の制限されたコンテキスト (理想的には 1:1) に対応します。これらの境界付きコンテキストは、その後の増分反復によりスタンドアロン アプリケーションに移行される可能性があります。したがって、リファレンス アーキテクチャでは、マルチコンテキスト アプリケーションのシナリオを重要な考慮事項として考慮しています。
- 明確なコンポーネント、責任の境界、依存関係
- ドメイン レポート シナリオのサポート: レポート シナリオはビジネス システムで一般的ですが、DDD はこのシナリオの処理方法を反映しません。エンジニアリングのリファレンスアーキテクチャとしては、やはり実際の業務からスタートして、ライティングモデルやレポートモデルの表示対応を反映させていきたいと考えています。
- 外部依存関係を最小限に抑える: 不要な依存関係を排除し、エンジニアリング アーキテクチャを軽量に保つ必要があります。
リファレンス アーキテクチャの構造
アプリのマルチコンテキスト構造
上記の原則に基づいて、リファレンス プロジェクトでは、モジュール性、サービスの粒度、コストの間でトレードオフを行うために、単一のアプリケーション内の複数のコンテキストのシナリオを検討します。複数のコンテキストをサポートするアプリケーション アーキテクチャの概略図を以下に示します。ソリューション ドメインが境界付きコンテキストを識別して分割した後、複数のコンテキストは、ビジネスの結合性と関連性に基づいて単一のエンジニアリング アプリケーションに実装されます。単一のアプリケーション内で複数の境界付きコンテキスト間で対話が行われる場合があり、対話の形式はイベント駆動型呼び出しまたはインプロセス呼び出しに基づくことができます。イベント駆動型アプローチではコンテキスト間の結合は低くなりますが、一般にイベント バス サポートの導入が必要であり、追加コンポーネントの導入により必然的に複雑さが増加します。インプロセス呼び出しは結合度が高くなりますが、実装の観点から見ると複雑さは低くなります。具体的にどの方法を選択するかは、開発者が実際の状況に基づいてトレードオフを行うことができます。
このアプリケーション アーキテクチャの決定は多要素のトレードオフであり、1:1 のサブドメインと制限されたコンテキストの理想的な実践と一致しないことを再度説明する必要があります。
次の図に示すように、上記の論理概略図からさらに 1 レベル深く進み、詳細なアプリケーション アーキテクチャのプレゼンテーション形式を階層化された次元から分析してみましょう。
重層的な懸念
クライアント
クライアントはアプリケーションとは別のプロセスにあり、アプリケーション機能の利用者であり、実際のプロジェクトでは、APP、PC、アプレット、公式アカウント、またはサードパーティのビジネス呼び出し元である可能性があります。
アクセス層
アクセス層は、外部システムとアプリケーションの内部ビジネス機能の間の中間層であり、アプリケーション層の外部ファサードであり、現在のアプリケーションがビジネス機能を外部に公開するための入り口です。この層の構成は、外部から提供される HTTP インターフェイス宣言、分散タイミング タスク スケジューリング、メッセージ リスナー、RPC サービスなどです。その重要な役割には、基本的なパラメータの検証、入力パラメータの適応とサービス ルーティング (第 1 層のアプリケーション サービスへの転送)、および外部システムからの要求に対する応答データの適応が含まれます。
ビジネス層:
この層は、アプリケーションのビジネス ロジックが存在する層であり、アーキテクチャ スタイル全体がモジュール式の単一スタイルを採用しており、この層のさまざまな境界コンテキストがさまざまなモジュールとして具体化されます。階層化されたアーキテクチャが各境界コンテキストで採用され、アプリケーション層、ドメイン層、ゲートウェイ層に独立して分割されます。
アプリケーション層:
ドメイン オブジェクト、ドメイン サービス、または外部依存サービスを調整して、ビジネス ユース ケースを完了します。この層は機能を調整するだけで、ドメイン ロジックは処理しません。
ドメイン層:
ドメイン層は階層化全体の中核であり、技術的な実装とは何の関係もありません。主にドメイン モデル、ドメイン イベント、ドメイン サービス定義、ビジネス関連の外部サービスとウェアハウス インターフェイスのインターフェイス抽象化を担当します。
ドメイン層とアプリケーション サービスの本質的な違いは、アプリケーション層にはドメイン ロジックが含まれておらず、すべてのドメイン ロジックが実装のためにドメイン層に降格されることです。
ゲートウェイ層:
ゲートウェイ層の位置付けは、アプリケーションの出力ゲートウェイであり、アプリケーションと外部インフラストラクチャ間の相互作用のための耐食層であり、すべての技術関連の実装を処理します。
このコンポーネントに名前を付ける方法はたくさんあります。たとえば、「rpc」という名前を付けるチームもあれば、「インフラストラクチャ」という名前を付けるチームもあります。異なる名前は、その背後にあるメタファーのチームの選択を反映しています。この記事のリファレンス アーキテクチャでは、ゲートウェイ - ゲートウェイという名前を選択しましたが、その理由は、境界付けられたコンテキスト自体の凝集性が高く、外部との相互作用には統一された出口が必要であるためです。統一輸出の概念を適切に表現しています。ファサード レイヤーがアプリケーションのノースバウンド ゲートウェイである場合、それは外部システム リクエストが内部に入る入り口になります。このときのゲートウェイは、内部アプリケーションが外部に接続するための出口となる、有界コンテキストの南向きゲートウェイを表します。
コンポーネントと依存関係
マクロの階層化から、さらに深く各層のコンポーネント分割を見てみましょう。以下に示すように:
コンポーネントを開始します:
アプリケーション全体の起動エントリ、アプリケーション構成情報のロードなど。
共通コンポーネント
Command、Query、Event、Entity、ValueObject の一般的な抽象化など、異なる境界コンテキスト間で再利用されるドメイン モデル要素の抽象化を提供します。もちろん、ドメイン モデルの一般的な抽象化を Common コンポーネントで再利用する必要はなく、独立した境界付きコンテキストとして使用し、カーネルを共有することで他のコンテキストと共有したり、独立したコンテキストとして実装したりすることもできます。 jarパッケージコンポーネント。
APIコンポーネント
RPC型サービスのインターフェース宣言コンポーネントで、社内で利用するJSFを例に、外部システムに公開するJSF APIを適用するコンポーネントです。このコンポーネントは独立したプロジェクトにすることができますが、チームによってはモジュールとしてアプリケーション プロジェクトに含めることもあります。
統合されたファサードコンポーネント: ファサード
外部クライアントのアプリケーション システムへの入り口は、ヘキサゴナル アーキテクチャ スタイルのアダプターと同様に、内部アプリケーション サービスの統一されたファサードでもあります。さまざまなシナリオに基づいて、リファレンス アーキテクチャは、プロバイダー (RPC サービス)、タスク (スケジュールされたタスク)、リスナー (MQ モニタリング)、レスト (http インターフェイス) などのいくつかのサブパッケージに分割されています。外部リクエストがシステムに入ると、Facade コンポーネントは入力パラメータの基本的な検証、入力パラメータの変換、サービス ルーティング、出力パラメータの変換などの操作を完了します。さらに、ログイン ステータス、認証、ログの処理などの関連機能も実行できます。
アプリケーションサービスコンポーネント: アプリケーションサービス
アプリケーション サービスは、ユース ケースとシステムの動作を表します。アプリケーション サービスは、ドメイン層とインフラストラクチャ層 (リファレンス アーキテクチャのゲートウェイ コンポーネント) に委任することにより、ユース ケースのアプリケーション ロジック処理を完了します。アプリケーション サービスはドメイン層のクライアントであると理解できます。。このコンポーネントの一般的な責任:
ストレージ層からドメイン オブジェクトをロードし、ドメイン ロジックを実行するためにドメイン オブジェクトを委任し、ドメイン オブジェクトを保存します。
- 重要なイベントの外部への通知
- 入力パラメータと出力パラメータの変換と適応
- トランザクション処理外部
- 非ドメインロジックのサービスコール
外部API
アプリケーション サービスのロジックは、ドメイン層を調整する必要があるだけでなく、場合によっては外部のサードパーティ サービスに依存する必要もあります。外部 API コンポーネントは、特定の実装を行わずに、これらの外部サービスのインターフェイス宣言と定義を担当します。
アプリケーション サービス コンポーネントは、これらの外部サービスの実装に直接依存するのではなく、そのインターフェイスの抽象化に依存します。同時に、ここでのモデル定義は、外部モデルへの適応である、境界付きコンテキストのセマンティクスに基づいています。
このコンポーネントは他のコンポーネントには依存せず、アプリケーション サービス コンポーネントとゲートウェイ コンポーネントによってのみ依存します。ゲートウェイ コンポーネントは、外部 API コンポーネントのインターフェイス宣言に依存して、基礎となるテクノロジ実装を提供します。また、アプリケーション サービス コンポーネントは、そのインターフェイスに依存し、IOC メソッドを通じて特定の実装を挿入してサービス呼び出しを完了します。
このコンポーネントが依存するサービスにはドメイン ロジックは含まれませんが、アプリケーション サービスのオーケストレーションをサポートするためにのみ使用されることに注意してください。ドメイン ロジックが関与する場合、外部サービスに依存するインターフェイス定義をドメイン層に下げる必要があります。
クエリ
クエリ コンポーネントは、ドメイン関連のレポート クエリ シナリオを解決し、制限されたコンテキスト内のアプリケーション サービスと同等のコンポーネントとして存在し、それぞれビジネス クエリとコマンド ロジックを担当します。
クエリ コンポーネントはレポート シナリオのサポートを提供するために導入されましたが、CQRS モデルは完全には導入されていませんでした。多くの資料では、CQRS と DDD が同時に言及される可能性が比較的高くなります。DDD では、複雑なドメイン指向の記述モデルが解決されているためですが、レポートのシナリオでは、このリッチ ドメイン モデルが最適ではない可能性があります。選択。読み取り側と書き込み側の両方が統一ドメイン モデルに基づいている場合、通常、ドメイン モデルの設計が妥協することになります。クエリ側の要件を満たすために、ドメイン モデルは追加のドメインに依存しない属性を導入する必要があるため、ドメイン モデルの汚染が発生します。
ドメイン
ドメイン コンポーネントはドメイン ロジックの中核であり、システム全体のドメイン ロジックの実現を担当し、ドメイン モデル、ドメイン サービス、ドメイン イベント、およびストレージ層の抽象化を定義します。このコンポーネントは、他のコンポーネント (共通ドメイン モデル抽象化コンポーネント Common を除く) に依存しません。
上の図に具体化された参照アーキテクチャでは、集約、エンティティ、値オブジェクト、ストレージ、ファクトリ、ドメイン イベントなど、DDD の戦術設計の古典的なモデリング要素が使用されています。実際の実装プロセスでは、これらの設計要素の抽象化には特定の課題があり、設計プロセスでは継続的な分析、トレードオフ、再構築を経て、設計の核となるモデリングを完了する必要があります。
ゲートウェイ
ゲートウェイ層は、技術的な相関関係全体の実現を担当し、内部アプリケーションの出口ゲートウェイです。
技術的な依存関係は、ゲートウェイ コンポーネントを他のコンポーネントから区別する基本的な機能です。外部サービス、ミドルウェア、DB などとの対話など、技術的な実装の詳細はすべてこのコンポーネントで処理する必要があります。同時に、ドメインコンポーネントと外部APIコンポーネントのインターフェース抽象化と連携し、システムと外部依存関係(外部サービスやアプリケーション依存のミドルウェア、DB、その他のインフラストラクチャを含む)との間の防食層機能を共同で引き受けます。内部モデルから外部モデルへの変換、外部モデルから内部モデルへの変換、および特定の相互作用を担当します。ゲートウェイ コンポーネントの特性に基づいて、この層での統合外部サービス データ キャッシングやダウングレード ヒューズ処理にも非常に適しています。
ゲートウェイ層は、ドメイン、アプリケーション サービス、外部 API、およびクエリ コンポーネントに依存し、上記の 4 つのコンポーネントによって定義されたインターフェイスの実装を担当します。Gateway コンポーネントでは、実装はサブパッケージを通じて分離されています。
- クエリ: サービスコンポーネントの実装をクエリします。
- external: 外部サービスに依存する外部 API コンポーネントのインターフェイス実装
- リポジトリ: ストレージ インターフェイスの実装
やっと
アプリケーション アーキテクチャ パターンの選択は、システム アーキテクチャ設計の重要な側面の 1 つであり、その構造は単なるパッケージ構造と名前付けではなく、多くの実践と知識を含むトップレベルの抽象化を伝えます。チームに適したエンジニアリングリファレンスアーキテクチャを開発し、チームメンバー間で合意を得ることが非常に重要です。ドメイン駆動設計には統一された汎用アーキテクチャがなく、標準アーキテクチャを定義しようとすることは非現実的です。この記事で説明するエンジニアリング アーキテクチャはあくまで参考であり、実際にはチームの状況に応じて異なりますが、原則としてビジネスドメインと技術ドメインを分離するという中心的な概念に従う必要があります。
著者: Ni Xinming、Jingdong Technology
コンテンツソース: JD Cloud 開発者コミュニティ