コマンドクエリ分離(コマンドクエリぶんり、英: Command-query separation, 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; // by some mechanism
x = x + 1;
int x_copy = x;
unlock x; // by some mechanism
return x_copy;
}
以下はCQS完全な例である。注意すべきは、これはシングルスレッドなアプリケーションでのみ安全に利用できるということである。マルチスレッドなプログラムにおいては、呼び出し元において increment() と
value()
が呼び出される間に競合状態が発生する。
private int x;
public int value() {
return x;
}
void increment() {
x = x + 1;
}
シングルスレッドのプログラムにおいても、クエリとコマンドが一体化したメソッドが非常に便利である場合がある。マーティン・ファウラーはその例として、スタックに対する pop()
メソッドを挙げている。