Skip to content

Aggregate Design: Using Invariants as a Guide

Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.

Learn more about Software Architecture & Design.
Join thousands of developers getting weekly updates to increase your understanding of software architecture and design concepts.


How do you compose an aggregate? For me, aggregate design involves understanding the invariants. Invariants are business rules that must always be consistent. Understanding the invariants will guide your aggregate design. Everything I seemingly post ends up being about defining boundaries! Aggregates are yet another example of defining boundaries based on invariants and consistency.

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

The example I’m going to use is the concept of a Shipment. You could think of this as a food delivery service. You have food that gets picked up at a restaurant and delivered to your house. The shipment consists of 2 stops. The Pickup, which is the restaurant, and the Delivery which is your house.

Aggregate Design: Using Invariants as a Guide

The important aspect about a stop is they have to go through a state transition. The initial state of a stop is In Transit. Once the delivery person arrives at the restaurant to pick up the food, the stop then enters the Arrived state. Once the delivery person leaves the restaurant with the food and on their way to your house, the stop is now in a Departed state.

Aggregate Design: Using Invariants as a Guide

Invariants

There are a couple of invariants within our shipment.

  1. A stop must progress through its state transitions in the exact order outlined above.
  2. The delivery stop cannot arrive until the pickup stop has departed

The first invariant is fairly easy to control as we can have that logic within the stop itself.

The second invariant that the delivery stop cannot arrive until the pickup start is departed is a bit more difficult.

The issue is that an individual stop does not know about the other stops. Meaning the pickup stop object has no access to the delivery stop object. This is where an aggregate comes in.

Aggregates

An aggregate is a collection of domain objects that form a consistency boundary.

Our aggregate consists of the Shipment and Pickup and Delivery Stops. The Shipment is what is called the Aggregate Root.

The aggregate root is the gateway to all interactions within the aggregate. In other words, you only expose the aggregate root. The calling code cannot access Stops directly. Because of this, you can enforce invariants for the entire aggregate.

In the Arrive() method, we confirming that all prior Stops have been departed. This enforces that the Stops are done in the correct order. Meaning that the Pickup stop is going through its full state progression before we can start the state progression of the Delivery.

Aggregate Design: Invariants

Use invariants as the guide to designing your aggregates. Invariants are business rules that must always be consistent. If you have invariants and are not using an aggregate, I recommend modeling it to try it out for yourself. You’ll have fewer wonders about how the state changed because all interactions must go through the aggregate root. There’s only one-way state can change.

Source Code

Developer-level members of my CodeOpinion YouTube channel get access to the full source for the working demo application available in a git repo. Check out the membership for more info.

Additional Related Posts

Learn more about Software Architecture & Design.
Join thousands of developers getting weekly updates to increase your understanding of software architecture and design concepts.


Leave a Reply

Your email address will not be published. Required fields are marked *