コマンドクエリ分離(コマンドクエリぶんり、: Command-query separation, CQS)は命令型プログラミングにおける原則である。バートランド・メイヤーによってEiffel言語における先駆的な仕事の一環として考案された。

この原則は、全てのメソッドはアクションを実行する"コマンド"か、呼び出し元にデータを返す"クエリ"のどちらかであるべきで、その両方を行ってはならないと述べている。言い換えれば、質問をすることが答えを変えてはならない[1]ということである。 より形式的には、メソッドは参照透過性を持ち、副作用を持たない場合のみ値を返すべきだということである。

契約プログラミングとのつながり

編集

コマンドクエリ分離は、契約プログラミング(DbC)の手法に非常によく適している。DbCでは、プログラムの設計はソースコードに埋め込まれた表明によって表現され、特定の重要な時点においてのプログラムの状態を記述する。DbCにおいて、表明はプログラムロジックでなく、設計のアノテーションとして見做されるため、その実行はプログラムの状態に影響を与えてはならない。CQSでは値を返すあらゆるメソッド(=クエリ)はプログラムの状態を変更する心配なしにどの表明からも呼び出すことができるため、DbCにとって有益である。

理論的には、健全性の尺度を確立するものであり、これにより同時に状態を変更することなくプログラムの状態を推論することができる。実際の利用においては、CQSは動作中のシステムにおける全ての表明チェックを、システムの振る舞いを意図せずして変更することを防ぎながら、パフォーマンス向上のためにスキップすることを可能にする。CQSはまた、特定の種類のハイゼンバグの発生を防ぐこともある。

ソフトウェア工学における広範なインパクト

編集

契約プログラミングとのつながりを超えて、CQSはその信奉者によって、プログラムをシンプルにする効果があり、(クエリを通じて)プログラムの状態を、(コマンドを通じて)状態の変更をさらにわかりやすくすることができると考えられている。[要出典]

CQSはオブジェクト指向的な手法によく適しているが、オブジェクト指向以外においても適用することができる。副作用と値の返却を分離することは本来オブジェクト指向に限って適用される考え方ではなく、CQSは副作用に関する推察が必要になるあらゆるプログラミングパラダイムに対して有効に適用することができる。[要出典]

コマンドクエリ責任分離

編集

コマンドクエリ責任分離 (CQRS) はCQSの概念をサービスのアーキテクチャのレベルにまで拡張したものであり、「クエリ」と「コマンド」でそれぞれ異なるインターフェースとデータモデルを用意し、データ取得にはクエリを、データ変更にはコマンドを用いるという形でCQS原則を適用している。[2][3]

他のアーキテクチャパターン

編集
  • CRUDを経由してやり取りを行うような単一的な表現から離れることで、タスクベースなUIへと容易に移行できる。 
  • CQRSはイベントベースなプログラミングモデルによく適しいる。CQRSシステムがイベントコラボレーション(Event Collaboration)により連携する個別のサービスに分割されていることは一般的である。これらのサービスはイベント駆動アーキテクチャの利点を容易に活用できる。
  • 分割されたモデルを持つことはモデルの一貫性を保つことがいかに難しいかということについての問題を提起し、最終的に一貫性が保たれる可能性が高まる。
  • 多くの事業領域においては、データを更新する際に多くの必要な手続きを経由する必要があるため、クエリ側のモデルを簡素化するために事前読み込み計算(Eager Read Derivation)を用いることが理に適っているかもしれない。
  • 書き込みモデルが全ての更新においてイベントを生成する場合、読み込みモデルをイベントポスター(Event Poster)として構造化して、これをメモリイメージ(Memory Images)とすることができ、データベースと多くのやり取りをすることを回避できる。
  • CQRSはドメイン駆動設計から恩恵を受けるような複雑な事業領域に適している。[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() メソッドを挙げている。

関連項目

編集

出典

編集
  1. ^ Meyer. “Eiffel: a language for software engineering”. p. 22. 2014年12月16日閲覧。
  2. ^ Young. “CQRS Documents”. 2012年12月28日閲覧。
  3. ^ a b Fowler. “CQRS”. 2011年7月14日閲覧。

参考文献

編集
  • Meyer, Bertrand (September 1994) [1988]. Object-oriented Software Construction. Prentice Hall. ISBN 0-13-629049-3 

外部リンク

編集