Skip to content
Federico Biccheddu edited this page Jun 11, 2018 · 7 revisions

When you're working with event sourcing and a rich domain model centered around aggregate roots, you and your code need to satisfy the following conditions:

  • Performing actions in the domain results in emitting one or more events
  • Those events are collected and are the only things that are actually persisted

and it follows from this that

  • Your domain needs to be able to rebuild its state completely and solely from events

because events are the only thing that are actually persisted.

So how do we do that?

At the moment, we know of no better way than to use the Emit/Apply pattern. With this pattern, we ensure that the aforementioned conditions hold, while still providing a tolerable experience for the programmer.

This is how it's done:

  • Aggregate root provides a method that can be called
  • Aggregate root does NOT change itself inside this method - instead it emits one or more events by calling Emit on itself
  • An emitted event is immediately dispatched to the aggregate root's appropriate Apply method
  • Aggregate root mutates itself to reflect the state that follows as a natural consequence of the applied event
  • Emitted events are accumulated during the "unit of work" and are saved to the event store if all went well
  • Events must never be emitted as a consequence of applying another event

This way, a framework is free to create a fresh instance of an aggregate root and apply any number of the previously emitted events in order to make the aggregate root reflect any point in time.

Show me

With Cirqus, you do it like this - create an aggregate root by creating a class that is derived off of AggregateRoot, like this:

public class Beetroot : AggregateRoot { }

Now, when I have a Beetroot, I want to be able to squash it - so I add a method that squashes this particular beetroot (and the squashing degree can be varied by supplying a value for the howMuch parameter):

public class Beetroot : AggregateRoot {
    public void Squash(decimal howMuch) { }
}

And then the rules state that we must only mutate ourselves as a consequence of an event, so we emit an event:

public class Beetroot : AggregateRoot {
    public void Squash(decimal howMuch) { 
        Emit(new BeetrootSquashed { SquashingDegree = howMuch });
    }
}

and we must declare an appropriate domain event in order to be able to do this:

public class BeetrootSquashed : DomainEvent<Beetroot> {
    public decimal SquashingDegree { get; set; }
}

If you run the program we have so far with Cirqus, you'll get an error that tells you that you cannot emit events of a particular type from an aggregate root unless you state your intent by implementing an appropriate IEmit<> interface - in this case, we must do it like this:

public class Beetroot : AggregateRoot, IEmit<BeetrootSquashed> {
    public void Squash(decimal howMuch) { 
        Emit(new BeetrootSquashed { SquashingDegree = howMuch });
    }

    public void Apply(BeetrootSquashed e) {
        // in here, we can mutate ourselves!
    }
}

So, let's imagine a world where beetroots start out with a structural stamina of 1 and then, whenever they're squashed, their stamina is reduced by that number - that world could be implemented like this:

    public class Beetroot : AggregateRoot, IEmit<BeetrootSquashed> {
        decimal _structuralStamina = 1;

        public void Squash(decimal howMuch) { 
            Emit(new BeetrootSquashed { SquashingDegree = howMuch });
        }

        public void Apply(BeetrootSquashed e) {
            _structuralStamina -= e.SquashingDegree;
        }
    }

See how the aggregate root is free to keep a truly private variable private as long as it's adhering to the Emit/Apply Pattern? Last thing is that beetroots (in our world) must tell the world when they're completely crushed, which they must do by emitting an appropriate event.

Since we must never emit an event as a consequence of another event, we take advantage of the fact that emitted events are immediately applied, which means that the private _structuralStamina has been changed after the first Emit - therefore, we extend the beetroot to do this:

public class Beetroot : AggregateRoot, 
        IEmit<BeetrootSquashed>,
        IEmit<BeetrootCompletelyCrushed>
{
    decimal _structuralStamina = 1;

    public void Squash(decimal howMuch) { 
        Emit(new BeetrootSquashed { SquashingDegree = howMuch });

        // if we haven't been completely crushed, just return
        if (_structuralStamina > 0) return;

        Emit(new BeetrootCompletelyCrushed());
    }

    public void Apply(BeetrootSquashed e) {
        _structuralStamina -= e.SquashingDegree;
    }

    public void Apply(BeetrootCompletelyCrushed e) {
    }
}

so that an appropriate BeetrootCompletelyCrushed is emitted when the stamina is no longer greater than zero.

Conclusion

The Emit/Apply Pattern enables rich domain models with complicated logic to be built from events and to reflect all work in the form of events, while still providing a useful state snapshot that can be utilized in computations and logic.

Combined with a framework that takes care of event application and all the other stuff around the aggregate root, this provides a powerful model for creating event-driven models.