Skip to content

Command–query separation

A design principle requiring each method either to change state as a command or return information as a side-effect-free query, but not both.

Version
v3 · 2026-09-19 · History
Domain-specific #
1507
Domain group
Applied Sciences & Engineering
Origin domain
Computer Science & Software Engineering
Subdomain
Imperative and Object Oriented Software Design → Computer Science & Software Engineering
Aliases
CQS, Command–query separation principle

Core Idea

Command–query separation is a design principle requiring each method either to change state as a command or return information as a side-effect-free query, but not both.

Command–query separation classifies operations by their contract: a command changes observable state and returns no informational result, while a query returns information and does not change observable state. Separating mutation from observation makes assertions, reasoning, testing, retries, and interface use more predictable, though controlled exceptions may be justified and documented.

Its operative boundary is not supplied by the name alone. Preserve this identity: A design principle requiring each method either to change state as a command or return information as a side-effect-free query, but not both.

How would you explain it like I'm…

Ask or Tell, Not Both

Imagine a toy robot that has two kinds of buttons. Some buttons make the robot do something, like move its arm. Other buttons only make it tell you something, like how far its arm is up, and pressing them never moves anything. A single button is never allowed to do both.

Change It or Ask It

In a computer program, pieces of code called methods do work when you call them. Command–query separation is a rule that says each method should be one of two kinds. A query answers a question and must not change anything you could notice. A command changes something but doesn't hand back an answer. If a method did both, just looking at a value could secretly change it, which makes bugs hard to find.

Separating Mutation from Observation

Command–query separation (CQS) is a software design principle: each method should be either a command, which changes the program's state and returns no information, or a query, which returns information and causes no observable change, but never both. The benefit is predictability. You can call a query as often as you like, in a test or in a check, without worrying that it changed something behind your back. The key word is 'observable': a query may do hidden internal work like caching, as long as a user of the object cannot see any change. CQS is weaker than full mathematical purity (referential transparency); it only requires that queries do not visibly change state. Sometimes breaking the rule is justified, but then it should be a deliberate, documented exception.

 

Command–query separation (CQS) is a method-level design principle: every operation is classified by its contract as either a command, which changes observable state and returns no informational result, or a query, which returns information and produces no observable state change. The criterion is observable, client-visible state under the declared contract — so internal effects such as caching do not violate CQS, and referential transparency is a stronger, optional purity condition rather than a requirement. Separating mutation from observation makes assertions safe to evaluate, supports local reasoning and testing, makes retries of queries harmless, and makes interfaces more predictable. Violations are operations that both mutate and return observational data. Controlled exceptions are sometimes justified (for example atomic operations where splitting would create races), but they should be deliberate and documented.

Scope of Application

The abstraction recurs literally within imperative methods, object interfaces, APIs, design by contract, and systems where mutation effects must remain legible. The following habitats preserve the same recognition machinery; they are not invitations to extend the name metaphorically.

  • Class interfaces. mutators are separated from observational methods.
  • Design by contract. assertions can invoke queries without changing the state they inspect.
  • API design. clients know whether a call is safe to repeat or reorder.
  • Testing. queries observe postconditions without introducing new effects.
  • Concurrent design. exceptions are evaluated against atomicity and race requirements.

Clarity

The relevant property is observable effect, not return syntax alone. A query that advances a cursor, consumes a stream, changes global state, or performs visible I/O violates strict CQS even if it appears to 'read.' A command may return minimal completion status under a relaxed convention, but that deviation should be named.

Manages Complexity

CQS reduces hidden temporal coupling by making effectful calls visually and contractually distinct. It improves local reasoning at the price of more operations and occasional awkwardness when observation and mutation must be atomic.

The compression remains accountable because each simplification has a named failure condition. Disagreement can be localized to a missing role, an invalid assumption, an ambiguous measurement, or a neighboring abstraction instead of being hidden inside an unanalyzed label.

Abstract Reasoning

R1. Define the observable state from the caller's perspective. R2. Classify each operation by its contractual effect and result. R3. Move observation out of commands where atomicity does not require combination. R4. Test queries for hidden mutation, I/O, cursor movement, and shared-cache effects. R5. Document exceptions with the concurrency or performance reason that justifies them.

Knowledge Transfer

CQS transfers literally across programming languages and APIs that expose operations over state. State transition and separation of concerns are broader parents; a political distinction between asking and ordering is only metaphor.

The transfer boundary is explicit: DOMAIN-SPECIFIC PASS / PRIME FAIL: The principle recurs across methods, classes, APIs, design-by-contract systems, and imperative codebases. Literal recognition retains the specialist vocabulary and validity conditions of imperative software design; outside that setting only broader parent operations transfer.

Relationships to Other Abstractions

Local relationship map for Command–query separationParents appear above the current abstraction, mutual partners to the right, and children below. Node labels state whether each abstraction is prime or domain-specific; colors identify relation types.Command–queryseparationDOMAINPrime abstraction: State and State Transition — presupposesState and StateTransitionPRIMEPrime abstraction: Modularity — is a kind ofModularityPRIME

Current abstraction Command–query separation Domain-specific

Parents (2) — outgoing typed relations

  • Command–query separation is a kind of Modularity Prime

    Modularity (prime:modularity).

  • Command–query separation presupposes State and State Transition Prime

    State and State Transition (prime:state_and_state_transition).

Hierarchy paths (2) — routes to 2 parentless roots

Neighborhood in Abstraction Space

Command–query separation sits in a moderately populated region (57th percentile for distinctiveness): it has near-neighbors but no dense thicket of look-alikes.

Family — Unclustered & Miscellaneous (2769 abstractions)

Nearest neighbors

Computed from structural-signature embeddings · 2026-10-25