CQRS & Event Sourcing Code Walk-Through

Want to see an example of how CQRS & Event Sourcing work together? Here’s a code walk-through that illustrates sending commands to your domain that stores Events in an Event Store. The Events are then published to Consumers that updated Projections (read models) that are then consumed by Queries. This is the stereotypical set of patterns used when using CQRS and Event Sourcing together.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

CQRS & Event Sourcing

Because CQRS and Event Sourcing are so often talked about or illustrated together, you’ll end up seeing a diagram like the one below.

This is the stereotypical diagram to illustrate both concepts together. Unfortunately there often isn’t a distinction between what portion is CQRS and what portion is Event Sourcing. And as you’ll see later in this post, there’s another concept involved as well in this diagram as well.

CQRS

Command Query Responsibility Segregation (CQRS) is simply the separation of Writes (Commands) and Reads (Queries). In the diagram above, that’s illustrated by the horizontal paths on the top and bottom. I’ve talked about the simplicity of CQRS and the 3 Most Common Misconceptions.

Event Sourcing

Event Sourcing is about how you record state. It’s a different approach to persistence since most applications are built to only record the current state. Event sourcing is about using a series of events (facts) that represent all the state transitions that get you to the current state. If you want more of the basics, check out my post Event Sourcing Example & Explained in plain English.

Simplest Possible Thing

I’m going to use Greg Young’s Simplest Possible Thing sample that illustrates both CQRS, Event Sourcing, and Projections. This sample is rather old so I’ve upgraded it to .NET 6 and Razor pages.

The sample app is just showing an Inventory Item and has various commands that mutate state, queries that return current state, and event sourcing is used as a way to persist state.

Commands & Events

Commands are handled by Command Handlers. In this example, they are simply using a repository to get out the InventoryItem which is a domain object, and then invoke the proper method on the InventoryItem. The Repository.Save() will persist all the events (generated though ApplyChange() on the InventoryItem you will see below) to an in-memory event stream (collection).

The Inventory Item domain objects contain all the behavior for doing any state transitions.

The AggregateRoot base class contains the ApplyChange method, which stores the event being applied. It also calls the appropriate Apply() method on the InventoryItem. You will notice there are Apply() methods for only some of the events. This is because our InventoryItem only cares about maintaining its internal state (projection) that is required to perform logic.

What all this code is illustrating is the Command side of CQRS as well as Event Sourcing. Commands are explicit actions that we handle to perform some type of state change. For state changes, we’re using explicit events to capture what actually occurred from the result of a command.

CQRS & Event Sourcing Code Walk-Through

Projections

Before I illustrate the Query side of CQRS, first we’re going to build a Projection that acts as a read model representing the current state of the Events.

When events are saved by the Repository, it then dispatches the events to consumers. In this example, it is done in-memory however if you were using an actual Event Store, you’d likely be using a subscription model to have your projections run in isolation asynchronously.

Consumers handle the events to update the read model (projection). In this example, there are two different consumers for updating two different projections. One projection is for showing a list of Inventory Items, the other is for showing an individual Inventory Item.

This is just using a FakeDatabase that is really just an in-memory collection & dictionary.

CQRS & Event Sourcing Code Walk-Through

Query

Now that we have projections (read models) we can look at how the Query side of CQRS uses the projections.

The razor page is using the ReadModelFacade (and underlying FakeDatabase) that has the projection for our InventoryItem details.

CQRS & Event Sourcing Code Walk-Through

CQRS & Event Sourcing

Hopefully, this illustrated the differences between CQRS, Event Sourcing, and how they are used together while also using Projections. While this diagram is often used to describe CQRS, realize there are multiple aspects that are at play and not just CQRS.

Source Code

Developer-level members of my YouTube channel or Patreon get access to the full source for any working demo application that I post on my blog or YouTube. Check out the YouTube Membership or Patreon for more info.

Related Links

Follow @CodeOpinion on Twitter

Software Architecture & Design

Get all my latest YouTube Vidoes and Blog Posts on Software Architecture & Design

Event Sourced Aggregate Design: Focus on Business Logic

Separating data and behaviors can have a pretty profound impact on your design. An Event Sourced Aggregate allows you to focus on business logic by having capabilities to produce data (Events). Event Sourcing does exactly this by limiting the amount of state you require only to that needed for business logic within an Aggregate.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Shipment

Before jumping in code, the example I’m going to use is of a shipment. The simple setup is you have a shipment that has two stops. The first stop is the Pickup and the last stop is the Delivery. You could think of this as a food delivery service where the shipment is of your food. A delivery driver goes to the Pickup Stop, which is the restaurant that you’re ordering from, and the delivery stop is your house.

Each stop will go through a transition in its status. At first, a stop will be “In Transit” and then will progress to “Arrived” once the delivery driver has reached the stop. Once the driver leaves the stop and heads to the next stop, the status will change to “Departed”. Once each stop goes through its transition, the shipment is completed.

Current State

Here’s an example using only the current state without event sourcing. The state is represented by properties on the ShipmentAggregateRoot and the list of Stops.

The primary reason we have this aggregate is to control the invariants and create a consistency boundary. Check out my post Using Invariants as a Guide when designing aggregates. In this case, we have a few invariants but the one I want to point out is in the Arrive() method. We need to check that all other previous stops have Departed and gone through their full progression before we can call Arrive on the next stop.

Event Sourced Aggregate

The first step in moving our aggregate towards event sourcing is actually creating events.

The next step is defining the state that we need in our aggregate. This is the key point of this post. The state we need is only for our invariants (business logic) in the aggregate. We do not need any other data in our state other than what we use for business logic.

Finally, here is the new Aggregate that is using the defined Events and the ShipmentState.

If you compare the Event Sourced version with the previous version, you will notice that we’re sorely focused on the behavior methods and the business logic. The projection/state we’re recording is much slimmer as it’s now recorded separately in the events.

Our tests are incredibly simple as we don’t really need to build up a large data model for our aggregate.

Source Code

Developer-level members of my CodeOpinion YouTube channel get access to the full source for any working demo application that I post on my blog or YouTube. Check out the membership for more info.

Related Posts

Follow @CodeOpinion on Twitter

Software Architecture & Design

Get all my latest YouTube Vidoes and Blog Posts on Software Architecture & Design

Testing your Domain when Event Sourcing

How do you test your domain when Event Sourcing? I find testing aggregates with Event Sourcing to be simpler than testing if you’re storing the current state. The inputs to your aggregate are events and the output of your aggregate are events.

Given a stream of events
When a valid command is performed
Then new event(s) occurs

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Event Sourcing

I’ve covered Event Sourcing in my Event Sourcing Example & Explained in plain English post. So check that out if you need a more detailed primer.

Generally, I use Aggregates as a way to model my domain. The aggregate is what exposes commands and if those commands are called/invoked will result in creating new events. This general concept is how testing in event sourcing becomes simple.

In order to use an aggregate, you first need to pull all the existing events from the Event Store, replay them within the Aggregate to get to the current state, then return the Aggregate to the caller. To do this, I generally use a Repository that will do this work and build the Aggregate.

To illustrate this, we have client code that is using the repository to get the Aggregate. The repository calls the Event Store to get the existing Events (if any) for this specific aggregate.

Testing your Domain when Event Sourcing

At this point the Repository will create an empty aggregate and replay all the events it received from the Event Store.

Testing your Domain when Event Sourcing

Once it has rebuilt the aggregate, it then returns it back to the Client. The client at this point will likely call various methods/commands on the aggregate.

This was the first stage of the process. I call this the rehydrating stage. You’re rehydrating your aggregate back to its current state with all the past events. Remember this first stage as the “Given” as we start testing in event sourcing.

Creating Events

The rest of the example is using a Warehouse Product, which is the concept of a product that is in a warehouse.

Now that the client code has an aggregate, it will likely perform one or more commands on the aggregate.

If the client calls ShipProduct() command on the aggregate, and the aggregate is in a valid state to do so and passes all invariants, then it will create a new event that it will keep internally within it.

If the client code then called another command, another event would be appended to the internal list.

This is the second stage of the process where we’ve created new events which are the result of calling commands on our aggregate. Remember this second stage as the “When” stage of testing with event sourcing.

Saving Events

The last step is taking the newly created events that are in the aggregate and persisting those to the event store.

Testing your Domain when Event Sourcing

This means the client code will call back to our Repository passing it the Aggreagate.

Testing your Domain when Event Sourcing

The repository will get the new events and append those to the Event Store for that specific aggregates event stream.

Remember this stage as the “Then” in our tests when Event Sourcing.

Given, When, Then

If you take that basic 3 steps of loading an aggregate, calling commands, saving the new events, you can boil that down to:

Given a stream of events
When a valid command is performed
Then new event(s) occurs

You can use this as the testing strategy for testing your Aggregates.

The WarehouseProduct above has 3 commands: ShipProduct, ReceiveProduct, and AdjustInventory. All of which result in creating their respective events if they passed any invariants.

To illustrate this Given, When, Then for the ShipProduct command, which should create a ProductShipped Event.

While that does satisfy our goal, it’s a bit cumbersome to have to write this to verify the event. To simply and make this a bit more natural to read, I created a base class to use within our tests.

Now using this abstract class, here are all the tests for the WarehouseProduct.

Source Code

Developer-level members of my CodeOpinion YouTube channel get access to the full source for any working demo application that I post on my blog or YouTube. Check out the membership for more info.

Follow @CodeOpinion on Twitter

Software Architecture & Design

Get all my latest YouTube Vidoes and Blog Posts on Software Architecture & Design