コマンド・クエリ分離(CQS )は、命令型プログラミングの原則の一つです。これは、ベルトラン・メイヤーがEiffelプログラミング言語に関する先駆的な研究の一環として考案したものです。
すべてのメソッドは、アクションを実行するコマンドであるか、呼び出し元にデータを返すクエリのいずれかであるべきであり、両方であってはならないと規定されています。言い換えれば、質問をしても答えが変わってはならないということです。[ 1 ]より厳密には、メソッドは参照透過性があり、副作用がない場合にのみ値を返す必要があります。
コマンドクエリ分離は、特に契約による設計(DbC)手法に適しています。DbCでは、プログラムの設計は、特定の重要な時点でのプログラムの状態を記述するアサーションとしてソースコードに埋め込まれます。DbCでは、アサーションはプログラムロジックではなく設計注釈とみなされるため、その実行はプログラムの状態に影響を与えてはなりません。CQSは、任意の値を返すメソッド(任意のクエリ)を、プログラムの状態を変更することを恐れることなく任意のアサーションから呼び出すことができるため、DbCにとって有益です。
理論的には、これは健全性の基準を確立するものであり、プログラムの状態を同時に変更することなく、その状態について推論することを可能にする。実際的には、CQSは動作中のシステムにおいてすべてのアサーションチェックをバイパスすることを可能にし、意図せず動作を変更することなくパフォーマンスを向上させる。CQSは、特定の種類のハイゼンバグの発生を防ぐ可能性もある。
契約による設計との関連性にとどまらず、CQSの支持者からは、プログラムの簡素化効果があり、クエリによる状態遷移やコマンドによる状態変化がより理解しやすくなると考えられている。
CQSはオブジェクト指向手法に非常に適していますが、オブジェクト指向プログラミング以外の分野にも適用可能です。副作用と戻り値の分離は本質的にオブジェクト指向的な概念ではないため、副作用に関する推論を必要とするあらゆるプログラミングパラダイムにCQSを有効に適用できます。
コマンドクエリ責任分離(CQRS)は、アーキテクチャレベルでCQSをサービスに一般化したものです。クエリとコマンドのインターフェースと通常はデータモデルを別々に使用することで、それぞれデータの取得と変更にCQSの原則を適用します。 [ 2 ] [ 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()が呼び出される箇所で競合状態が発生します。
private int x ; public int value () { return x ; } void increment () { x = x + 1 ; }シングルスレッドのプログラムであっても、クエリとコマンドを組み合わせたメソッドの方がはるかに便利な場合がある。マーティン・ファウラーはスタックpop()のメソッドを例として挙げている。 [ 4 ]