Overview of CQRS / Event Sourcing
CQRS (Command/Query Responsibility Segregation) and Event Sourcing are two separate architectural patterns that work
together very nicely as a whole system.
Command Query Responsibility Segregation
CQRS is the practice of separating "write" operations (as in, that result in affected state), and "read" operations (as
in, observing the current state of a system). This is typically done using "Commands" and "Queries", hence the naming.
A command has a single responsibility: to instruct, with obvious and detailed intent, the application to perform an
operation that may or may not result in a state change. If the command results in a state change, the chosen
persistence should be modified. The query part is simply an interface exposed to the application layer that results in
a "read model"; that is a read-only representation of the current state in question.
Terms commonly used
- Command: instruction to the system to perform an action. In real terms, these are immutable value objects that
could be serialised (especially in a service oriented architecture)
- Command bus: a term used to describe where the commands are sent to for handling. A command bus can handle
temporal decoupling (e.g. serializing a command and sending to a message broker) or simply invoke a command handler
for immediate (synchronous) execution
- Command handler: a class that executes a command. This would be invoked by a command bus, and the command is
passed as the only parameter.
- Finder or query interfaces: interfaces exposed to the application layer that allow looking up the current
state of an entity. Implementation typically looks up data in persistence (e.g. an RDBMS database)
- Read model: the current state of an entity. Should be read-only.
Event Sourced Systems
Event Sourcing is used to replace storage of current "state" with a history of deltas or changes of entities with the
application. Instead of storing a table with the current state of something, for example a table might have an ID,
username and login count columns. In an event sourced system, no such table needs to exist. Merely a list of
events that have happened, which can be replayed to form an ephemeral "current state", e.g.:
By reading the list of events that have affected the user with ID
123, we can see that the user is named
they have logged in twice. When coupled with a CQRS system, we can create "projectors" which create current state
tables for an entity, which is what we are used to in a traditional RDBMS system (i.e. a table with user ID, name and
login count columns in this example).
Terms commonly used
- Event: description of something that has happened in the system. Typically these produce a change of state.
- Aggregate: a collection of events that relate to a single entity in a domain. In very simple terms, you can
think of an aggregate or an entity as interchangeable (but realistically there are important differences).
- Aggregate Root: similar in concept to aggregate, but is intended as a "top level" container for other entities
and attributes. This would typically be the most important and relevant entity in your domain.
- Event bus: when an event happens in the system, it is sent to the event bus. The event bus distributes the event
to anything important, such as event store, event handlers or projectors.
- Event store: handles persisting and serialising events to the persistence layer. Also provides repository to
fetch an aggregate with it's current event stream.
- Event handler: listens for events to be raised. Intended to produce side-effects, such as creating a command in
response to an event.
- Projector: listens for events to be raised. Must never produce side-effects, and is intended to be used to
create, update, or delete a current state representation (known as a read model)