2026年4月10日金曜日

💎コマンド・クエリ分離( Command–query separation CQS)すべてのメソッドは、アクションを実行するコマンドか、呼び出し元にデータを返すクエリのどちらかであるべきで、両方であってはならない

 コマンド・クエリ分離(Command Query Separation: CQS)は、オブジェクト指向設計の原則の1つで、Bertrand Meyerによって提唱されました。この原則は、オブジェクトの操作に関する方法論として、次の2つの主要な操作を明確に区別することを推奨します:

  1. コマンド(Commands): オブジェクトの状態を変更する操作。返り値を持たない(voidまたは同等のもの)。

  2. クエリ(Queries): オブジェクトの状態を参照または取得する操作。オブジェクトの状態を変更しない。

この原則の主な要点は、単一の操作がコマンドとクエリの両方の役割を果たさないようにすることです。つまり、状態を変更する操作は、それに関する情報や結果を返してはいけません。同様に、情報を取得する操作は、オブジェクトの状態を変更してはいけません。

コマンド・クエリ分離(CQS)とは、命令型コンピュータ・プログラミングの原則の一つである。Bertrand MeyerがEiffelプログラミング言語の先駆的な研究の一環として考案した。
すべてのメソッドは、アクションを実行するコマンドか、呼び出し元にデータを返すクエリのどちらかであるべきで、両方であってはならない、というものである。言い換えれば、質問をしても答えが変わってはいけないということである[1]。より正式には、メソッドは参照透過的で副作用がない場合のみ値を返すべきである。

https://en.wikipedia.org/wiki/Command%E2%80%93query_separation

CQSは契約による設計との関連性を超えて、その信奉者の間では、(クエリによる)状態や(コマンドによる)状態の変化をより理解しやすくして、プログラムを単純化する効果があると考えられている。
CQSはオブジェクト指向の方法論に適しているが、オブジェクト指向以外のプログラミングにも適用できる。副作用と戻り値の分離は本質的にオブジェクト指向ではないので、CQSは副作用についての推論を必要とするあらゆるプログラミングパラダイムに有益に適用できる。

CQRS(Command query responsibility segregation)は、CQSをメッセージ駆動型およびイベント駆動型アーキテクチャに一般化したもので、データの取得と変更にそれぞれ別のQueryメッセージとCommandメッセージを使用することでCQSの原理を適用しています。

CQRSはイベントベースのプログラミングモデルと相性が良い。CQRSのシステムはEvent Collaborationで通信する個別のサービスに分かれているのが一般的です。これにより、これらのサービスはEvent Driven Architectureを容易に利用することができます。

CQRSは複雑なドメイン、つまりドメイン駆動設計の恩恵を受けるようなドメインに向いています。

画像
この例では、deposit と withdraw メソッドがコマンドとして機能し、システムの状態(この場合は銀行口座の残高)を変更します。これらのメソッドは値を返しません。一方、getBalance メソッドはクエリとして機能し、システムの状態を変更せずに現在の残高を返します。このように、CQSはメソッドの役割を明確にし、副作用を管理しやすくすることを目指します
画像
https://amzn.to/3PwMGC2

コマンド・クエリ分離の利点

  1. 予測性: CQSに従ったシステムは、動作が予測しやすくなります。なぜなら、あるメソッドが状態を変更するのか、あるいは単に情報を返すのかを明確に知ることができるからです。

  2. 再入性: 状態を変更しないクエリメソッドは、しばしば再入可能であるため、マルチスレッドの環境での実行が容易になります。

  3. 可読性と保守性: クエリとコマンドが分離されていると、コードの意図が明確になり、それによってコードの読みやすさや保守性が向上します。


画像
https://amzn.to/48x8J4e



画像

コマンドクエリが愛した数式

CQSを採用する主な利点は、副作用の管理と予測可能性の向上です。数式でこれを表現するには、システムの状態を数学的な集合としてモデル化し、コマンドとクエリの操作を関数として表現することから始めることができます。


画像

状態Sを考え、コマンドを関数C:S×A→S(ここでAはアクションの集合)、クエリを関数Q:S→V(ここでVは値の集合)とモデル化します。

コマンドクエリ分離の利点は、次のような性質を持つシステム設計に現れます:

  1. 予測可能性と再現性: Q(S)は、与えられた状態Sに対して常に同じ結果Vを返します。これはクエリが状態を変更しないため、副作用がないことを意味します。

  2. 副作用の分離: C(S,A)は新しい状態′S′を生成しますが、この操作がクエリの結果に直接影響を与えることはありません(コマンドの実行前後でクエリを実行した場合を除く)。このように、副作用はコマンドによってのみ引き起こされ、クエリ操作によって予期せぬ状態変化を避けることができます。

この説明は数式で直接的な「表現」というよりは、CQSの概念を数学的な用語で説明しています。CQSの利点は、プログラムの理解、保守、デバッグが容易になることにより、より直接的にソフトウェアの品質と開発の効率性に関連します。

副作用が起きる場合の数式を考えるには、状態の変更が読み取り操作(クエリ)に影響を与えるようなシステムをモデル化する必要があります。副作用は、ある操作がシステムの状態を変更し、その結果として他の操作の結果に影響を与える場合に発生します。このような場合、クエリ操作自体が状態を変更するか、あるいはコマンドがクエリの結果に間接的に影響を与えることがあります。

以下のようなモデルを考えます:


画像

副作用を伴う場合、コマンドCまたはクエリQが状態Sを変更することにより、後続の操作結果が変わることがあります。つまり、コマンドやクエリの実行は、システムの状態に影響を及ぼし、その結果、後続のクエリの結果が変わる可能性があります。

副作用を含むクエリの場合、次のような関数′Q′を考えることができます:


画像

こで、′Q′は状態を変更し(Sから新しい状態′S′へ)、同時に値Vを返します。この関数は、クエリ操作が副作用を持つ(状態を変更する)場合の振る舞いを示しています。

また、コマンドが副作用を引き起こす場合、コマンドの後に続くクエリの結果が異なる可能性があります。例えば、コマンドCの実行後にクエリQを実行すると、異なる結果が得られることがあります:


画像

この式は、コマンドCの実行が状態Sを変更し、その結果としてクエリQの結果が変わることを示しています。これは副作用の一例です。
副作用を含むシステムでは、操作の順序が結果に大きく影響するため、プログラムの予測性と再現性が低下することが一般的です。これは、特に複雑なシステムや並行性が関与する場合に、デバッグや保守を困難にします。