Implementing an Event Sourced Aggregate

So after completing either one extensive Design Level EventStorming session, or multiple small sessions applied to each Bounded Context, the Team feels ready to implement a working prototype of the the Domain Model to show to Nick and get feedback on their attempt to codify the Ubiquitous Language that they have learned together.

The Team decides to take a Behavior-Driven Design approach to implementing the Domain Model. This fits well with Domain-Driven Design in that it focuses on the business’s acceptance of the functionality of the software and not the technical implementation.

We’ll use the Given When Then style of BDD, but we won’t use any BDD-centric test frameworks. We’ll simply structure our xUnit tests in a BDD way.

So let’s take our first Use Case and try working that into a BDD Specification:

Scenario: Setting up a brand new roast schedule
    Given there is no roast schedule created for next week
        When I start creating a roast schedule
        Then an empty roast schedule is created

We’ll write this test after we structure our project and get the ball rolling with the Roast Schedule Entity. This isn’t necessarily test first development, but we will use tests to guide us in our implementation.

Vertical Slice

Besides implementing an actual UI, we’re going to try to do as much of a “Vertical Slice” through this first Use Case as we can. For more detail on what a Vertical Slice is, check out Growing Object Oriented Software Guided by Tests.

We have dubbed the Roast Schedule an Aggregate Root. This means that we are going to maintain a transactional consistency boundary strictly within this Entity and any of its own elements as defined by the Ubiquitous Language. From Vaughn Vernon’s Domain Driven Design Distilled:

Each Aggregate forms a transactional consistency boundary. This means that within a single Aggregate, all composed parts must be consistent, according to business rules, when the controlling transaction is committed to the database

What we’ve also decided is that we’re going to take an Event Sourcing approach to persisting the Roast Schedule Aggregate Root. Whether or not the complexity of this approach is appropriate for this project is not certain yet. The goal of this demonstration is, however, to show how Event Storming can help us to quickly achieve a Domain Model that lends toward a system that uses CQRS and Event Sourcing.

Here’s a quick definition of Event Sourcing from Michael Müller’s paper, Enabling Retroactive Computing Through Event Sourcing:

Event sourcing (ES) describes a style of architecture wherein each state altering operation in an application is captured as an immutable event [1]. These events are appended to an event log. Once appended they can never be deleted, the event log possesses a write-once, append-only restriction. The current state of an application is derived from this series of events. When replayed, this series of events always leads to the exact same state of the application.

Even if Event Sourcing is not how the Team decides to persist the Roast Schedule, they would still benefit from the speed at which they identified the Aggregates and Messages that the system will be built around. This is because they didn’t begin with a data-centric approach to the Domain Model, they began with a behavioral approach through EventStorming.

Let’s look back at our Specification:

Scenario: Setting up a brand new roast schedule
    Given there is no roast schedule created for next week
        When I start creating a roast schedule
        Then an empty roast schedule is created

Since the Roast Schedule Aggregate Root is going to be Event Sourced, we’ll create a base class that tracks Domain Events and allows for re-constitution of the Aggregate’s state via a left fold over its Event history.

For a quick, in-memory prototype of this Event Sourced Aggregate, we’ll use Greg Young’s SimplestPossibleThing project for most of the implementation. As we continue, through my blog and other resources I’ll be working on, I will explore actual implementations using other Event Storage infrastructures too.

The Aggregate Root Base Class

For an Event Sourced Aggregate, there are a variety of ways to make sure the appropriate Event Handlers are called when an Aggregate is sent a Command. Take a look at this article by Jérémie Chassaing for more about what options we have for Event dispatching.

For an example of a more robust solution for Event sourced Aggregates, take a look at Mark Nijhof’s sample app Fohjin. This uses an Event Handler registration approach to replaying Events. We will be refactoring this app to use a more production-ready solution when the time comes.

Greg Young’s SimpleCQRS uses the DLR (Dynamic Language Runtime) in combination with a solution by David Ebbo called ReflectionMagic. You can read more here. ReflectionMagic simply allows you to access private and internal members in other assemblies through reflection. The reason it’s useful here is that our Aggregate Root Base Class will use private void Apply() methods to affect the state of our Aggregate Root with the Domain Events that result from Commands.

A CreateRoastSchedule Command gets sent to the Roast Schedule Aggregate Root. The Command method call, if successful, will transition the Command message to a RoastScheduleCreated Event. The use of .AsDynamic() from ReflectionMagic allows us to match an Apply(EventType e) method on our Aggregate Root to actually make the Aggregate Root state transition. In an Event Sourcing style of architecture, the Aggregate Root is where Commands transition to Events - however not all Events are created by Commands.

Here’s Greg’s Aggregate Root base class that we are going to use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ReflectionMagic;

namespace Common.Domain.Model {
    public abstract class AggregateRoot : Entity {
        private readonly List<Event> _changes = new List<Event>();

        public Guid Id { get; protected set; }
        public int Version { get; internal set; }

        public IEnumerable<Event> GetUncommittedChanges() {
            return _changes;
        }

        public void MarkChangesAsCommitted() {
            _changes.Clear();
        }

        public void LoadsFromHistory(IEnumerable<Event> history) {
            foreach (var e in history) ApplyChange(e, false);
        }

        protected void ApplyChange(Event @event) {
            ApplyChange(@event, true);
        }

        // push atomic aggregate changes to local history for further processing (EventStore.SaveEvents)
        private void ApplyChange(Event @event, bool isNew) {
            this.AsDynamic().Apply(@event);
            if (isNew) _changes.Add(@event);
        }
    }
}

We’ll address the other plumbing pieces of this base class soon, but for now let’s get some code written and our test to pass….


continue reading…

previous…


I will be releasing most of this content only to subscribers. Make sure you sign up by clicking the big red button!


Related Posts:

Tweet
comments powered by Disqus