コマンド・クエリ分離( CQS ) は、命令型 コンピュータ プログラミングの原則です。これは、 Eiffel プログラミング言語に関する先駆的な研究の一環として、Bertrand Meyerによって考案されました。
これは、すべてのメソッドがアクションを実行するコマンドか、呼び出し元にデータを返すクエリのいずれかであるべきであり、両方ではないことを示しています。言い換えれば、質問をしても答えが変わってはならないということです。[1]より正式には、メソッドは参照透過性があり、副作用がない場合にのみ値を返す必要があります。
契約による設計との関連
コマンドとクエリの分離は、契約による設計(DbC) 方法論に特に適しています。この方法では、プログラムの設計はソース コードに埋め込まれたアサーションとして表現され、特定の重要な時点でのプログラムの状態が記述されます。DbC では、アサーションはプログラム ロジックではなく設計注釈と見なされるため、アサーションの実行によってプログラムの状態が影響を受けることはありません。CQS は、値を返すメソッド (クエリ) を任意のアサーションから呼び出すことができ、プログラムの状態が変更される心配がないため、DbC にとって有益です。
理論的には、これによって健全性の尺度が確立され、プログラムの状態を同時に変更することなく、プログラムの状態について推論できるようになります。実際的には、CQS により、動作中のシステムですべてのアサーション チェックをバイパスして、動作を誤って変更することなくパフォーマンスを向上させることができます。CQS は、特定の種類のハイゼンバグの発生を防ぐこともできます。
ソフトウェアエンジニアリングへの幅広い影響
契約による設計との関連を超えて、CQS はプログラムを簡素化する効果があり、状態 (クエリ経由) と状態変更 (コマンド経由) をより理解しやすくすると考えられています。[引用が必要]
CQS はオブジェクト指向の方法論に適していますが、オブジェクト指向プログラミング以外にも適用できます。副作用と戻り値の分離は本質的にオブジェクト指向ではないため、CQS は副作用についての推論を必要とするあらゆるプログラミング パラダイムに適用できます。[引用が必要]
コマンドクエリ責任分離
コマンドクエリ責任分離(CQRS)は、アーキテクチャレベルでCQSをサービスに一般化します。これは、クエリとコマンドの別々のインターフェースと通常はデータモデルを使用して、それぞれデータの取得と変更を行うことでCQSの原則を適用します。 [2] [3]
その他の建築パターン
- CRUDを介して対話する単一の表現から離れていくと、タスクベースの UI に簡単に移行できます。
- CQRS は、イベントベースのプログラミング モデルに適しています。CQRS システムは、イベント コラボレーションと通信する個別のサービスに分割されるのが一般的です。これにより、これらのサービスはイベント駆動型アーキテクチャを簡単に活用できます。
- 別々のモデルを持つことで、それらのモデルの一貫性を維持するのがいかに難しいかという疑問が生じ、結果的一貫性を使用する可能性が高まります。
- 多くのドメインでは、必要なロジックの多くは更新時に必要となるため、Eager Read Derivation を使用してクエリ側のモデルを簡素化することが理にかなっている場合があります。
- 書き込みモデルがすべての更新に対してイベントを生成する場合は、読み取りモデルをイベント ポスターとして構造化してメモリ イメージにすることができ、多くのデータベース操作を回避できます。
- CQRSは複雑なドメインに適しており、ドメイン駆動設計の恩恵も受けます。[3]
制限事項
CQS は、再入可能およびマルチスレッドソフトウェアを正しく実装するための複雑さをもたらす可能性があります。これは通常、コマンドとクエリの分離を実装するために非スレッドセーフ パターンが使用される場合に発生します。
以下は CQS に従っていない簡単な例です。これはプログラムの他のすべての部分のロックの複雑さを解決するため、マルチスレッド ソフトウェアには便利ですが、そうすることで関数が状態を変更してそれを返すため、CQS に従っていません。
private int x ; public int incrementAndReturnX () { lock x ; // 何らかのメカニズムによりx = x + 1 ; int x_copy = x ; unlock x ; // 何らかのメカニズムによりreturn x_copy ; }
以下は CQS 準拠バージョンです。シングルスレッド アプリケーションでのみ安全に使用できることに注意してください。マルチスレッド プログラムでは、呼び出し元で競合状態が発生し、 とincrement()がvalue()呼び出されます。
プライベートint x ;パブリックint value () { return x ; } void increment () { x = x + 1 ; }
シングルスレッドのプログラムでも、クエリとコマンドを組み合わせたメソッドの方がはるかに便利であると言える場合があります。Martin Fowlerはスタックpop()メソッドを例として挙げています。 [4]
参照
- 冪等性
- ドメイン駆動設計
- 作成、読み取り、更新、削除(CRUD)
参考文献
- ^ Meyer, Bertrand. 「Eiffel: ソフトウェア エンジニアリングのための言語」(PDF) p. 22 。2014 年12 月 16 日閲覧。
- ^ Young, Greg. 「CQRS ドキュメント」(PDF) 。2012 年 12 月 28 日閲覧。
- ^ ab Fowler, Martin. 「CQRS」 . 2011年7月14日閲覧。
- ^ Fowler, Martin. 「CommandQuerySeparation」 . 2005 年12 月 5 日閲覧。
さらに読む
- マイヤー、バートランド(1994年9月)[1988]。オブジェクト指向ソフトウェア構築。プレンティスホール。ISBN 0-13-629049-3。
外部リンク
- マーティン・ファウラーのブリキの説明
