eShopOnContainers の DDD マイクロサービスに CQRS および CQS のアプローチを適用する

ヒント

このコンテンツは eBook の「コンテナー化された .NET アプリケーションの .NET マイクロサービス アーキテクチャ」からの抜粋です。.NET Docs で閲覧できるほか、PDF として無料ダウンロードすると、オンラインで閲覧できます。

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

eShopOnContainers 参照アプリケーションの注文マイクロサービスの設計は、CQRS 原則に基づいています。 ただし、使用されているのは最もシンプルなアプローチ、つまり、コマンドからクエリを分離し、両方のアクションで同じデータベースを使用するというアプローチです。

これらのパターンの本質である重要なポイントは、クエリはべき等であるということです。つまり、システムにクエリを実行する回数にかかわらず、システムの状態が変わることはありません。 つまり、クエリによって生じる副作用はありません。

このため、注文マイクロサービスで使用されるデータベースが同一であっても、トランザクション ロジック「書き込み」ドメイン モデルとは異なる「読み取り」データ モデルを使用できます。 したがって、これは簡略化された CQRS アプローチです。

一方、コマンド (トランザクションとデータ更新をトリガーする) はシステムの状態を変更します。 コマンドを使用する場合は、複雑さと、常に変化するビジネス ルールの扱いに注意する必要があります。 ここで DDD の技法を適用すると、システムのモデル化を改善できます。

このガイドで示す DDD パターンを所かまわず適用すべきではありません。 これらのパターンは設計上の制約をもたらします。 こうした制約には、時間経過とともに品質が向上するなどの利点が伴います。システム状態を変更するコマンドや他のコードでは特にそう言えます。 しかし、データの読み取りとクエリはこれらの制約によって複雑さが増し、利点はわずかです。

そうしたパターンの 1 つは集計パターンです。これについては、後のセクションでさらに説明します。 簡単に言うと、集約パターンでは、多数のドメイン オブジェクトがドメイン内で互いに持つリレーションシップの結果として、1 つの単位として処理されます。 このパターンを採用しても、クエリに利点があるとは限りません。クエリ ロジックの複雑さが増す可能性があります。 読み取り専用クエリの場合、複数のオブジェクトを単一の集計として扱う利点はありません。 複雑さが増すだけです。

前のセクションの図 7-2 に示されているように、このガイドでは、DDD パターンをマイクロサービスのトランザクション/更新領域 (つまり、コマンドによってトリガーされる部分) にのみ使用することを提案しています。 クエリはよりシンプルなアプローチに従うことができ、CQRS アプローチに従ってコマンドから分離する必要があります。

「クエリ サイド」を実装する場合、EF Core、AutoMapper プロジェクション、ストアド プロシージャ、ビュー、具体化されたビュー、マイクロ ORM など本格的な ORM の多様なアプローチから選択できます。

このガイドと eShopOnContainers (具体的には注文マイクロサービス) では、Dapper のようなマイクロ ORM を使用して直接的なクエリを実装します。 このガイドでは、SQL ステートメントに基づくクエリを実装でき、オーバーヘッドが小さい軽量フレームワークのおかげで、最良のパフォーマンスが得られます。

このアプローチを使用するにあたり、モデルに加える更新が原因で SQL データベースにエンティティを保持する方法に影響が及ぶ場合は、Dapper など、クエリ実行のための独立した (EF 以外の) アプローチで使用される SQL クエリにも、別途更新が必要になります。

CQRS パターンと DDD パターンは最上位のアーキテクチャではない

CQRS とほとんどの DDD のパターン (DDD レイヤー、集約を伴うドメイン モデルなど) はアーキテクチャ スタイルではなく、アーキテクチャ パターンに過ぎないことを理解するのは重要です。 マイクロサービス、SOA、イベント駆動型アーキテクチャ (EDA) はアーキテクチャ スタイルの例です。 これらは、多くのマイクロサービスなどの多数のコンポーネントで構成されるシステムを記述します。 CQRS パターンと DDD パターンは、1 つのシステムまたはコンポーネント内にあるもの (この場合は、マイクロサービス内にあるもの) を記述します。

境界付けられたコンテキスト (BC) が異なると、採用されるパターンも異なります。 それぞれ責任が異なり、異なる解決策に至ります。 強調する価値がある点として、至る所で同じパターンを無理に当てはめると失敗に至ります。 所かまわず CQRS パターンと DDD パターンを使用しないようにしてください。 多くのサブシステム、BC、マイクロサービスはよりシンプルであり、シンプルな CRUD サービスや別のアプローチを使うとより簡単に実装できます。

存在するアプリケーション アーキテクチャは 1 つだけです。つまり、自分が設計しているシステムまたはエンドツーエンド アプリケーションのアーキテクチャです (たとえば、マイクロサービス アーキテクチャ)。 しかし、そのアプリケーション内の境界付けられているコンテキストまたはマイクロサービスのそれぞれの設計には、アーキテクチャ パターン レベルの独自のトレードオフや内部設計の決定が反映されます。 CQRS や DDD と同じアーキテクチャ パターンを所かまわず適用しないようにしてください。

その他の技術情報