Event Sourcing: Aggregates vs Projections

One of the topics that came up a few times (and I noticed quite a number of searches for it) is how the Aggregates and Projections differ or relate to each other. The reason for this confusion is that some parts of the implementation logic are very similar - in particular, the current state of an Aggregate derived from the event log. In this blog post, we will explore the differences and look at some examples. Before we do this, let’s quickly recap what we understand by Aggregates and Projections.

Aggregates

An Aggregate is one of the Tactical Domain-Driven Design patterns - a consistency boundary around a cluster of domain objects such as Entities and Value Objects. It helps us to manage the complexity of software and clearly define which invariants can be enforced and which ones are trued up with corrective policies. In Event Sourcing aggregates are reconstituted from a single fine-grained event stream (e.g. representing an account) and during this operation, a current state of the aggregate is being calculated so that it can be used to handle a command.

In practice the sequence of steps can look similar to this:

  • Receive a command - e.g. withdraw £100 from the account.

  • Read all past events for the aggregate in questions - a sequence of credits and debits for a single account.

  • Reconstitute current state of the aggregate - sum up all credits and debits to get a current balance of the account.

  • Decide how to handle the command - accept (and write new events) if balance is sufficient, reject if not.

The state itself is usually discarded (unless snapshotting is implemented as an optimisation) and rebuilt every time a command is handled. One important trait of the state of the aggregate is that it needs to contain all information required to handle the command. If for example, we expect to receive duplicate commands (e.g. because of at-least-once delivery guarantees), then we can use the state to deduplicate the commands we’ve already handled.

Given all of that, we can treat the internal state of the aggregate as a: projection of a single, fine-grained event stream. It is then used to make a decision whether to accept or reject a command.

Projections

As we can see the conceptually the Aggregate state is a specialised Projection of the event stream, but let’s not confuse the Aggregates itself with a Projection. The Aggregate has the state, but also the logic that allows to handle the commands and defines the consistency boundaries. On the other hand in the Event Sourcing: Projections article we’ve defined the Projection as an answer to a question: “what is the current state derived from the event stream?”.

The state created by Projection can be used as a read model, support process managers or drive some event handlers. Usually, the Projections that create these states subscribe to stream (or some subset) of all events. They aren’t focused only on reading events from a single fine-grained stream like Aggregates do.

Summary

In Event Sourcing, an Aggregate has its internal state, which is a projection of a single fine-grained event stream. On the other hand - the Write Stack Projections can subscribe to streams containing all (or subset of all) events, and be used to create read models or support process managers. I trust this will clarify the issue for the people that start their journey with CQRS and Event Sourcing.