architect-handbook

Software Architect Handbook

View on GitHub

CQRS: Command and Query Responsibility Segregation

CQRS is a pattern that separates read and update operations for a data store. It allows a system to better evolve over time and prevents update commands from causing merge conflicts at the domain level.

Context and problem

In traditional architectures, the same data model is used to query and update a database. That’s simple and works well for basic CRUD operations.

However, as the system evolves, the data model and the queries become more complex. On the read side, the application may perform many different queries, returning DTOs with different shapes. On the write side, the model may implement complex validation and business logic.

Solution

CQRS separates reads and writes into different models, using commands to update data, and queries to read data.o

The models can then be isolated, although that’s not an absolute requirement.

Advantages

Issues and considerations

When to use

When not to use

Consider applying CQRS to limited sections of your system where it will be most valuable.

Implementation details

Separate data stores

For greater isolation, you can physically separate the read data from the write data. In that case, the read database can use its own data schema that is optimized for queries.

For example, it can store a materialized view of the data, in order to avoid complex joins or complex ORM mappings. It might even use a different type of data store. For example, the write database might be relational, while the read database is a document database.

If separate read and write databases are used, they must be kept in sync. Typically this is accomplished by having the write model publish an event whenever it updates the database. This must occur in a single transaction.

See Event-driven architecture style.

Event sourcing

CQRS is often used along with the Event Sourcing pattern. The store of events is the write model, and is the official source of information. The read model of a CQRS-based system provides materialized views of the data, typically as highly denormalized views. These views are tailored to the UI, which helps to maximize both display and query performance.

Using the stream of events as the write store, rather than the actual data at a point in time, avoid updates conflicts on a single aggregate and maximizes performance and scalability. The events can be used to asynchronously generate materialized views of the data.

Because the event store is the official source of information, it is possible to delete the materialized views and replay all past events to create a new representation of the current state when the system evolves, or when the read model must change.

When using CQRS combined with Event Sourcing, consider the following: