Featured image of post Dive into The CQRS Messaging Pattern

Dive into The CQRS Messaging Pattern

CQRS (Command Query Responsibility Segregation)

Norman Rockwell - Wikipedia

CQRS: Making Software Less Confusing (or More, Depending on Your Perspective)

What is CQRS?

CQRS, short for Command Query Responsibility Segregation, is a fancy way of saying:
“What if we separate the logic that changes data (commands) from the logic that reads data (queries)?”

This pattern is often linked to Martin Fowler (Wikipedia), though Greg Young also played a huge role in its popularization (Wikipedia).

The idea is simple: instead of having one model that does both reading and writing (which is what we usually do), we create two models—one for writes (commands) and one for reads (queries).

Relationship to the Gang of Four Patterns

CQRS is not one of the original Gang of Four patterns (Wikipedia), but it draws inspiration from:

  • Command Pattern (Wikipedia): CQRS commands encapsulate a request to change state.
  • Observer Pattern (Wikipedia): Often used with CQRS for event sourcing.
  • Mediator Pattern (Wikipedia): CQRS can use a mediator to manage communication between commands and queries.

Commands, Queries, Results, and Envelopes

Commands

A command represents an action that modifies the state of the system.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class CreateUserCommand {
    private final String username;
    
    public CreateUserCommand(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }
}

Queries

A query retrieves data without modifying anything.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class GetUserQuery {
    private final String userId;

    public GetUserQuery(String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }
}

Results

A result is what comes back from a query.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class UserResult {
    private final String userId;
    private final String username;

    public UserResult(String userId, String username) {
        this.userId = userId;
        this.username = username;
    }

    public String getUserId() {
        return userId;
    }

    public String getUsername() {
        return username;
    }
}

Envelopes

An envelope wraps commands or queries to add metadata.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Envelope<T> {
    private final T payload;
    private final String correlationId;

    public Envelope(T payload, String correlationId) {
        this.payload = payload;
        this.correlationId = correlationId;
    }

    public T getPayload() {
        return payload;
    }

    public String getCorrelationId() {
        return correlationId;
    }
}

CQRS vs. MVC: The Ultimate Battle

CQRS and MVC (Model-View-Controller) are often compared, so let’s break it down:

FeatureCQRSMVC
Separation of ConcernsStrong separation between commands and queriesEverything handled in one model
ComplexityHigher (more moving parts)Lower (easier to grasp)
ScalabilityVery scalable, ideal for distributed systemsCan be hard to scale when reads/writes compete
Data ConsistencyEventual consistency (when combined with event sourcing)Immediate consistency
Learning CurveSteepEasy (until you realize you’ve overcomplicated your controllers)

Key Takeaways

Key IdeaExplanation
CQRS separates read and write modelsCommands change state, queries fetch data
CQRS is influenced by GoF patternsUses Command, Observer, and Mediator patterns
Envelopes wrap dataAdds metadata for tracking
CQRS vs. MVCCQRS is great for scalability, MVC is simpler but can get messy

References