Command-Query Separation (CQS) ist Bertrand Meyers Entwurfsregel aus Object-Oriented Software Construction (1988), nach der jede Methode entweder ein Command ist, der Zustand ändert und nichts zurückgibt, oder eine Query, die einen Wert zurückgibt und keinen beobachtbaren Zustand ändert, niemals beides. Eine Frage zu stellen ändert dann die Antwort nicht, deshalb sind Queries wiederholbar und dürfen aus Contracts und Assertions heraus aufgerufen werden. CQS ist eine Regel je Methode, nicht das Architekturmuster CQRS.

CQS (Command-Query Separation)

Details
Vollständiger Name

Command-Query Separation, aus Bertrand Meyers Object-Oriented Software Construction (1988), entstanden zusammen mit Eiffel

Auch bekannt als

CQS, Befehl-Abfrage-Trennung; Fowler zieht „modifiers“ den „commands“ vor, auch „mutators“ ist gängig

Kernkonzepte:

Eine Regel, angewandt auf jede einzelne Methode

Jede Methode ist entweder ein Command, der Zustand ändert und nichts zurückgibt, oder eine Query, die einen Wert zurückgibt und keinen beobachtbaren Zustand ändert. Niemals beides. Fowler nennt beide Hälften: „Queries: Return a result and do not change the observable state of the system (are free of side effects). Commands: Change the state of a system but do not return a value.“

Eine Frage zu stellen ändert die Antwort nicht

Der Gewinn: Eine Query darf zweimal, in beliebiger Reihenfolge, aus einem Logger, einem Debugger oder einer Assertion heraus aufgerufen werden, ohne den Systemzustand zu ändern. Die Signatur verrät, ob ein Aufruf wiederholbar ist — genau die Eigenschaft, die ein Leser sonst nur durch Lesen des Methodenkörpers bekommt.

Das ist nicht CQRS

cqrs ist ein Architekturmuster: getrennte Lese- und Schreibmodelle, oft getrennte Speicher, meist eventual consistency zwischen beiden. CQS ist eine Regel über eine einzelne Methodensignatur und gilt auch in 300 Zeilen Code, die nie zwei Modelle haben werden. Greg Young und Udi Dahan haben Meyers Methodenregel auf Architekturebene gehoben; die Übertragung ersetzt das Original nicht.

Die Motivation aus Design by Contract

design-by-contract ist die Arbeit desselben Autors und der Grund, warum CQS existiert. Vorbedingungen, Nachbedingungen und Invarianten rufen Queries auf. Würde eine Query mutieren, dann änderte das Schreiben eines Contracts gerade das, was der Contract beschreibt — und Assertions ließen sich nicht aus einem Release-Build entfernen.

Seiteneffekte und beobachtbare Seiteneffekte

Eine Query darf einen Cache füllen, einen Zähler erhöhen, eine Verbindung öffnen. CQS fragt nach beobachtbarem Zustand — nach dem, was ein Aufrufer über die Schnittstelle des Objekts feststellen kann. Memoisierung verträgt sich deshalb mit der Regel, sie ist keine Ausnahme davon.

Wo die Regel nachgibt

pop(), next() auf einem Iterator und atomares Compare-and-Set mutieren und geben zurück — mit Absicht. Fowler: „Popping a stack is a good example of a query that modifies state. Meyer correctly says that you can avoid having this method, but it is a useful idiom. So I prefer to follow this principle when I can, but I’m prepared to break it to get my pop.“ Nebenläufigkeit verschärft den Fall: Compare-and-Set in Query plus Command zu zerlegen, erzeugt genau die Race Condition, die die atomare Operation schließen soll.

Der diagnostische Gebrauch

CQS ist so sehr Lesewerkzeug wie Schreibregel. Sortiere die Methoden einer Schnittstelle in Commands und Queries; die, die sich dem Sortieren widersetzen, markieren die unklaren Stellen des Entwurfs — ein gezielter Blick auf code-smells.

Wann zu verwenden:

  • Beim Entwurf oder Review einer Klassen- oder Modulschnittstelle, wenn ein Leser an der Signatur erkennen soll, ob ein Aufruf wiederholbar ist

  • Beim Sortieren einer bestehenden Schnittstelle: Jede Methode, die mutiert und zurückgibt, ist eine offene Frage, nicht automatisch ein Defekt

  • Überall dort, wo Assertions, Contracts oder Invarianten in den Code hineinrufen (design-by-contract)

  • Für Code, den ein Modell erweitern soll: Eine Command/Query-Trennung übersteht das Lesen ohne Kontext besser als eine Konvention im Docstring

  • Um die bewussten Ausnahmen zu benennen, damit pop() eine festgehaltene Entscheidung ist und kein Versehen

  • Je Slice in vertical-slice-architecture, wo die Command/Query-Trennung die natürliche Nahtstelle vor jeder Trennung in CQRS-Größe ist

Häufige Missverständnisse:

  • ❌ „CQS und CQRS sind dasselbe, eins ist nur die Abkürzung“ — CQS ist Meyers Methodenregel von 1988, CQRS das Architekturmuster mit zwei Modellen

  • ❌ „CQS heißt getrennte Lese- und Schreibdatenbank“ — das ist CQRS; CQS kostet architektonisch nichts und braucht keinen zweiten Speicher

  • ❌ „Eine Query darf überhaupt keine Seiteneffekte haben“ — sie darf keine beobachtbaren haben; Cache und Zähler sind erlaubt

  • ❌ „Die Regel ist absolut“ — Fowler bricht sie für pop() mit Absicht, und atomares Compare-and-Set kann sie nicht befolgen, ohne die Race Condition zurückzuholen

  • ❌ „Ein Command darf einen Statuscode zurückgeben“ — einen Fehler oder Status zurückzugeben ist die übliche, vertretbare Beugung; die ID der erzeugten Entität zurückzugeben ist die umstrittene

  • ✓ „Jede Methode ist Command oder Query, und die Ausnahmen sind benannt“ — die Regel plus ihre benannten Ausnahmen ist die ganze Praxis

Kritik:

  • Der Autor der bekanntesten modernen Darstellung folgt ihr selbst nicht absolut. Martin Fowlers Bliki-Eintrag schreibt den Begriff Meyer zu — „The term 'command query separation' was coined by Bertrand Meyer in his book 'Object Oriented Software Construction'“ --, bestätigt den Nutzen, „it’s extremely handy if you can clearly separate methods that change state from those that don’t“, und verweigert dann die reine Position: „So I prefer to follow this principle when I can, but I’m prepared to break it to get my pop.“ Fowler, „CommandQuerySeparation“ (5. Dezember 2005).

  • Die von der Datenbank erzeugte ID ist das stehende Gegenbeispiel — und kostet in beide Richtungen. Mark Seemann benennt den Zusammenstoß: eine Repository-Methode, die eine neue Entität speichert und die von der Datenbank vergebene ID zurückgibt. „The problem with this design, obviously, is that it violates CQS. The Create method ought to be a Command, but it returns a value.“ Seine Lösung übergibt die ID — void Create(Guid id, T item) — und er nennt den Preis: „Most software design decisions involve trade-offs, and so does this one. You gain better encapsulation for potentially worse performance.“ Seemann, „CQS versus server generated IDs“ (11. August 2014).

  • Vladimir Khorikov hat geantwortet, der Preis sei zu hoch. Direkt gegen Seemann: „While this solution clearly solves the problem of violation CQS, it does it at a high cost.“ Sein konkreter Einwand ist nicht ästhetisch: „Besides the fact that this design results in two calls instead of one, GUIDs hurt performance of inserts.“ Khorikov, „CQS with Database-Generated Ids“ (15. November 2014). Der Austausch ist die nützlichste verfügbare Kritik, weil beide Seiten die Regel anerkennen und nur darüber streiten, was ihre Befolgung kostet.

  • Keine namentliche deutschsprachige Kritik gefunden. Gesucht wurde auf Englisch und Deutsch nach dokumentierten Einwänden gegen CQS als Methodenregel. Das deutschsprachige Material, das auftaucht, ist einführend oder übersetzt — Definitionen und Tutorials, kein zitierbarer Kritiker. Das ist ein Suchergebnis mit angehängtem Rahmen, kein Beweis der Abwesenheit: Der Begriff wird üblicherweise auf Englisch diskutiert.

Aktueller Stand:

  • CQS blieb Methodenregel, während CQRS die Aufmerksamkeit bekam. Das Akronym, dem die meisten Teams zuerst begegnen, ist CQRS, und das methodennahe Original wird oft für dessen Abkürzung gehalten. Fowlers Eintrag von 2005 ist weiterhin die gängige moderne Referenz für die ursprüngliche Regel, und der Austausch zwischen Seemann und Khorikov von 2014 ist nach wie vor der Ort, an dem der harte Fall verhandelt wird.

  • Das nackte Akronym ist sicher, und das Benennen partitioniert eine Schnittstelle. Gemessen auf claude-haiku-4-5 im Clean Room am 3. Oktober 2026: Auf die Frage, woran ein Entwickler vor dem Aufruf einer von zwölf Methoden erkennen soll, ob der Aufruf umkehrbar ist — eine Aufgabe ohne jedes Vokabular von CQS --, antwortete die Baseline mit JavaDoc-Annotationen und einer Namenskonvention. Mit CQS benannt, wurden die zwölf in Queries, die nichts ändern, und Commands, die void zurückgeben, zerlegt. Auch das nackte Akronym hält: Auf „What is CQS?“ gab die schwache Stufe Meyers Regel zurück, ohne zu CQRS abzudriften.