スキップしてメイン コンテンツに移動

CQRSパターンとは?CQRSパターンの説明とメリットまとめ

 

CQRS Pattern


こちらは勉強のため翻訳したポストです。
元のページはこちらをクリック


アプリケーションで読み取り書き込みを分離することをCQRSパターンという。

CQRSパターン物理的論理的に分けることができ、次のような長所を持つ。

・複雑度の管理
・パフォーマンスの向上
・拡張性
・柔軟性
・保安性


CQRSパターンが何か?

Command Query Responsibility Segregation。

直訳すると命令クエリ責任分離で、データを読み込みと書き込みをそれぞれのモデルを使用するという意味である。

標準とされてきた方式としては、同一のモデルを用いてデータを読み上げアップデートしていたが、この方式は簡単で、ほとんどのCRUD作業に適している。 しかし、複雑なアプリケーションでは維持管理が難しくなる。

データの書き込みのために複雑なビジネスロジックや有効性検査を行うこともあり

データを読み取るためには、さまざまなクエリを実行する必要がある場合がある。


また、どのようにデータモデルを作成するかを考慮する必要がある。 SQL データモデリングのベストプラクティスは正規化されたデータベースが提供されるが、これは一般的には問題ないが、データを書くことに最適化されている。


コマンドとクエリをそれぞれのモデルとして使用すると、個別に拡張することができる。 同じデータベースを使用するとしても論理的に分離できる。 コマンド(命令)およびクエリに対する下位システムをそれぞれのサービスに分割することができる。 また、データの書き込み、読み取りに最適化された複数のデータベースを使用することもできる。


CQSとはどう違うか?

CQS (Command Query Separtion) : 命令クエリ分離


基本前提はオブジェクトのメソッドをコマンドクエリに分割したこと。


コマンド :システムのステータスを変更するが、値を返さない。

クエリ:値を返すが、システムの状態を変更しない。 (サイドエフェクトなし)


コマンドからは値を返せないという意味ではない。 
一般的な例としては、値を返した後にシステムの状態を変更するスタックから値を引き出してくる場合がある。
CQRSはCQSが進化したもので、CQRSはアーキテクチャレベルで動作する。 同時に、CQS はメソッド(あるいはクラス)レベルで動作する。


CQRSの多様な選択

以下は、複数のデータベースを使用するCQRSシステムのハイレベル概要である。
コマンドは、「書き込み」データベースを更新し、「読み取り」データベースを同期する必要がある。これにより、CQRSシステムに最終一貫性が導入される。 

最終的な一貫性により、アプリケーションの複雑さを大幅に増加させるが、同期プロセスが失敗するとどうなるかを考慮し、耐欠陥性戦略(fault tolerance strategy)を持たなければならない。




このようなアプローチには様々なものがある。

・書くためのSQLデータベースと読むためのNoSQLデータベース

・書くためのイベントソーシングと読むためのNoSQLデータベース

・読み取りのためのRedisの使用またはその他の分散キャッシュのキャッシュ


読み書きのためのデータを分離すると、要求事項に最適なデータベースを選択することができる。




論理的CQRSアーキテクチャ

CQRSパターンをシステムにどのように適用できるか?

書き込みの側面では、一般的にEF Core と rich ドメイン モデルを使用してビジネスロジックをカプセル化する。 命令の流れはEFを使ってメモリに読み込み、ドメインロジックを実行し、変更点をデータベースに保存する。

読み取りの側面では可能な限り間接的なものを追求するべきで、Dapperを使用して原始的なSQLクエリを使用することは良い選択であると言える。 データベースにviewを生成したり、クエリを作成することができる。 またはEF Coreを使ってプロジェクションでクエリを実行することもできる。



まとめ

コマンドとクエリを分離することで、長期的にはパフォーマンスとスケーラビリティを向上させることができる。また要求事項に応じて命令とクエリをそれぞれ最適化することができる。


コマンドは複雑なビジネス論理と検証をカプセル化することができる。 EF Core や rich ドメイン モデルを使用することは素晴らしいソリューションの一つである。

クエリは性能に関するものであるため、最もパフォーマンスの良いものを使用するためにDapperを使用する。 EF Core プロジェクションやRedis、原始的なSQLクエリを使用することができる。








コメント

このブログの人気の投稿

Entity Framework Coreの概念 / メリット / コード例 / 使用方法 / データのインポート、修正、削除 / サンプルコード

  EF Core? EF Coreは [Entity Framework]を軽量化したバージョンで、.NET Core 及び.NET 5 以上で使用できる。 データベースとの相互作用を単純化し、開発者がデータベースに対するクエリおよび操作を行うことができるORM(Object-Relational Mapping)ツールである。 主な機能 データベースに対するCRUD(Create、Read、Update、Delete)作業を支援する。 LINQ(Language Integrated Query)を使ってデータベースクエリを作成することができる。 データベーススキーマをコードで定義できるCode Firstアプローチを提供する。 多様なデータベースシステムと互換性がある。 EF Coreのメリット 開発者がデータベースとの相互作用を容易にすることができる。 データベースに対する抽象化階層を提供し、メンテナンスと拡張性を向上できる。 多様なデータベースシステムとの互換性を提供する。 LINQを使って簡単にデータベースクエリを作成することができる。 EF Coreの限界 EF Core は、まだすべてのEntity Framework の機能をサポートしない。 一部の高度なデータベース機能に対するサポートが制限されているケースがある。 性能の側面で、一部の状況では原始SQLクエリを作成する方がより効率的である可能性がある。 EF Coreの使い方 プロジェクトにEF Core NuGet パッケージを追加する。 DbContextクラスを作成し、データベース接続情報を設定する。 モデルクラスを作成し、データベース テーブルとマッピングする。 LINQを使用してデータベースクエリを作成して実行する。 変更内容をデータベースに保存または更新する。 Entity Framework Coreを使ったデータベースのインストール SQL Serverのインストール dotnet add package Microsoft.EntityFrameworkCore.SqlServer テストのためのInMemoryインストール dotnet add package Microsoft.EntityFrameworkCore.InMemory DbContext サブクラス...

VueJSのPiniaのまとめ【基礎編】

  目次 Vue 基本構造 Pinia 基本構造 State (Vue) State (Pinia) Getters (Vue) Getters (Pinia) Actions (Vue) Actions (Pinia)     Vue 基本構造 基本構造説明 - Composition API 方式( 別の方式ではOption API方式がある export default{} ) <script setup> // storeを import import { useTodosStore } from '@/stores/todos' // 宣言 const todos = useTodosStore() // --- stateの値をレスポンシブで参照する方法 const { todos, count } = storeToRefs(todos) // --- actionは分割代入して使える const { increment } = todos // --- stateの修正方法3つ // 1. 修正 counter.count++ // 2. $patch 利用 counter.$patch({ count: counter.count + 1 }) // 3. action 이용 counter.increment() </script> <template> <!-- Storeのstateに直接アクセス --> <div>Current Count: {{ counter.count }}</div> </template>   Pinia 基本構造 基本構造説明 Option Store方式 既存と同様state, getters, actionsを直感的に表現する stores/todos-store.js import { defineStore } from 'pinia' export const useTodosStore = defineStore('todos', { //-- storeの名前 state: () =...