Aggregate roots coordinating their entities in an event sourcing system

2,173 views
Skip to first unread message

@neilbarnwell

unread,
Feb 8, 2013, 4:23:04 AM2/8/13
to ddd...@googlegroups.com
Say I have a SalesOrder aggregate with the SalesOrder at the root. The process is - pick items, print dispatch note, pick items, print dispatch note. I was thinking that the DispatchNote could be an entity within the SalesOrder aggregate. Since I'd only be allowed to hold a reference to the SalesOrder, I would be calling SalesOrder.AddItemsToDispatchNote().

Thing is, I'm not sure what events are generated, where they come from and how they are captured for storage. Using Greg's typical pattern of Load AR, invoke behaviour, collect, store and publish events generated by that AR as a result, I'm not sure which option to take:
  1. Application service calls SalesOrder.AddItemsToDispatchNote(), which calls SalesOrder._dispatchNote.AddItems(), captures the dispatch note's events and saves them in it's own event stream. Replaying of events when loading the AR would then need to pass on dispatch note events to the dispatchnote's event replaying.
  2. Don't actually have a DispatchNote class, and just have the SalesOrder AR deal with it all using private fields etc.
  3. Make DispatchNote it's own AR, therefore it's own event stream, though possibly give it the SalesOrder's ID for future reference.
So you see the question is around storing what would be a full object graph, in a non-ES system. I have done talks using a ES-based SalesOrder AR that has no SalesOrderLines in it, but it would be nice in this case to model (i.e. encapsulate) the DispatchNote behaviour in it's own class.

Many thanks in advance.

Neil.

Neil Barnwell.
Twitter: @neilbarnwell
web: http://www.neilbarnwell.co.uk

@neilbarnwell

unread,
Feb 8, 2013, 7:08:52 AM2/8/13
to ddd...@googlegroups.com
I've thought of another way to pose my question:

Intro

This question is about DDD and Event Sourcing where entities within an Aggregate other than the Aggregate Root itself have event-generating behaviour. Whether this is appropriate, and if so how to implement it.

Detail

I'm trying to model a DeliveryRun Aggregate Root (AR), which is the trip a vehicle makes to perform a delivery. Before it departs, it must have an up to date DeliveryManifest. The "up-to-dateness" of it suggests to me that the DeliveryManifest be an entity within the DeliveryRun consistency boundary defined by the AR.

Okay so far.

I'm using an Event Sourcing approach for this - the approach as taught by Greg Young and implemented in the Regalo library. This means the AR (DeliveryRun) need not actually have any entities if there is no behaviour for them (e.g. a SalesOrder may not have SalesOrderLines, because it records events such as ItemsAdded/ItemsRemoved instead).

However, there is to be some logic around the DeliveryManifest. Specifically, once the manifest has first been requested, when items are added to the delivery, a new version of the manifest needs to be created. This means we can ensure drivers don't depart without the most up-to-date manifest available.

If I were to encapsulate the logic inside the DeliveryManifest object (which won't be serialised and stored; we're using Event Sourcing and it's not the AR), how do I capture events?

Options I'm considering

  • Should the events be generated by the DeliveryManifest entity, but saved against theDeliveryRun itself (which would then need to know how to replay those events into theDeliveryManifest when loaded from the event store)?

  • Should there be no DeliveryManifest (except perhaps as a data structure) and all the logic/events be implemented directly by the DeliveryRun?

  • Should the DeliveryManifest be it' own AR and make sure the DeliveryRun is told of the current manifest's ID? Since that takes the manifest object outside the consistency boundary of theDeliveryRun, I would need to build some event handling to subscribe to changes in theDeliveryRun that are relevant to the manifest so it can be updated/invalidated etc accordingly.

  • Implement a different style for capturing the events similar to Udi's DomainEvents pattern. This means changing the Regalo library, though I think it could be made to support both patterns fairly easily. This would allow all events generated by all entities within the aggregate to be captured so they can be saved against the AR. I'd need to think of a solution for loading/replaying though...

JCW

unread,
Feb 9, 2013, 8:10:48 PM2/9/13
to ddd...@googlegroups.com
Neil it sounds like you are struggling with how entities fit into ES as well as how you should model aggregates.  What I would recommend is checking out an example that was written for Vaughn Vernon's new book Implementing Domain-Driven Design.  This example does not use entities but Aggregates plus Event Sourcing (A+ES) and I find it very easy to understand.  With this approach you are actually replaying the events to the AR and to projections.  The events are used to construct the Aggregate State which acts as an entity when you are going to apply commands to the aggregate thru the Application Service.  The projections become the read model to be used by the end user application. 

Now as far as designing Aggregates I would recommend reading three documents written by Vaughn Vernon on this very subject and of course his book.  I would also suggest checking out a great project called Being The Worst which is a podcast slash online class on applying DDD.  Greg Young has actually been a guest of the podcast.  It's founder Rinat Abdullin has a great blog and open source library called Lokad CQRS which has been an inspiration to me.  What I like about RInat's approach is it simplicity and expressiveness.  Lokad CQRS is very mature and is used by his company Lokad and by my others.

Good luck and hopefully there is something useful that you can take away from here.  Do not worry I did not answer your questions this is such a great community I am sure someone will be able to help.

A Plus,

Jason

@neilbarnwell

unread,
Feb 11, 2013, 4:21:03 AM2/11/13
to ddd...@googlegroups.com
Thanks. I had read Vaughn's stuff a few months back, but on reading it still doesn't answer the crucial question of whether behaviour within an aggregate should exist only in the AR or be spread across other entities within the aggregate. Since my aggregates have no external public state (except for Id and a method to retrieve uncommitted events) there would seem to be no reason to implement the other entities. On the other hand, SOLID principles (particularly SRP) would suggest that the logic should be broken up into smaller, more cohesive classes. That would point to making additional aggregates, but then I'm taking the Manfiest outside the consistency boundary of the DeliveryRun that it's supposed to be representative of. I'm now beginning to think that, while I *may* choose to build a (private) object graph within my aggregates such that the state is more expressive, any actual behaviour will be limited to the AR itself. If *behaviour* is required on an entity, I'll just have to make it an AR in it's own right and have messages passed between ARs (something I'm already doing, particularly with sagas for long-running processes spanning many ARs).

Neil.

@yreynhout

unread,
Feb 11, 2013, 6:17:41 AM2/11/13
to ddd...@googlegroups.com
Neil, designing and testing entities in isolation, even having them adhere to some SOLID, has little to do with aggregates as consistency boundaries. Seems you are struggling with object oriented programming in general.

public class DeliveryRun : AggregateRootEntity, IEventRecorder  {

// wrapping the behavior of manifest

  public void SomeManifestBehaviorHere() {
     _manifest.SomeBehaviorHere();
  }

// or this approach if you want client code to call the manifest directly (the parent, DeliveryRun will still be notified)

  public Manifest AttachedManifest {
     get {
        return _manifest;
     }
  }

  void Apply(ManifestAttachedToRun @event) {
    _manifest  = new Manifest(this);
  }

  void IEventRecorder.Record(object @event) {
    _uncommittedEvents.Add(@event);
  }
}

public class Manifest {
  public Manifest(IEventRecorder recorder) {
    _recorder = recorder;
  }

  public void SomeBehaviorHere() {
     //Guard
     ApplyEvent(new SomethingHappened());
  }

  void ApplyEvent(object @event) {
    Play(@event); //dispatches to a handler residing on manifest.
    Record(@event);
  }

  void Record(object @event) {
    _recorder.Record(@event);
  }
}

How hard would it be to mock IEventRecorder and test Manifest in isolation? Whether at that point Manifest is an entity or a value object is a different discussion, but from a mechanical point of view, I don't see how this could be perceived as "difficult" or "unnatural". There are many ways you could implement this (e.g. using a lambda recorder Action<object> that wraps the DeliveryRun's protected Record - or as in the SO answer I gave you where the dispatching is done at the root level (preferred, root is the boss)).

HTH,
Yves.

JCW

unread,
Feb 11, 2013, 7:10:33 PM2/11/13
to ddd...@googlegroups.com
Neil I would really suggest you play with the code example I link to in my previous post.  One of the issues that I personally had with modeling aggregates was disconnecting my thinking about modeling data.  When you come from a purely relational DB point of view you have a tendency to think it terms of entities as records in a table.  A storage first kind of mentality.  An aggregate is much more then that.  It is about modeling the real world.  Let say we are modelling you.  Would you define yourself simply as Neil, adult male, developer from the UK?  No, you are the sum of all your life's experiences or events like your parents meeting, you being born, your first day of school, etc, etc.  The aggregate represents you and to determine your current state we enumerate through all the events of life. 

Since the state is only available within the aggregate you can use projections to project information that might be needed by an end user application.  The projection can be represent something else other than then the aggregate.  Lets go back to the example of you as an aggregate to explain what I mean.  Let's say you are a loyal fan of Manchester United and you watch or attend every single match and at the end of every match you record the result in your journal.  That act of you recording the score still is a part of your state but now it's possible project the event of you recording the result to create a new read model of the team's current record in the Premier League.  So the first match creates the entity and each subsequent event are like updates to that entity.

I hate to use Star Wars but just let go and clear your mind and let go. 

Good Luck,

Jason
 
P.S.

Take the time to check out http://beingtheworst.com it will most definitely help you.


 


On Friday, February 8, 2013 4:23:04 AM UTC-5, @neilbarnwell wrote:

@neilbarnwell

unread,
Feb 11, 2013, 8:01:23 PM2/11/13
to ddd...@googlegroups.com
I don't mean to be funny but I'm pretty up to speed with the bigger picture of ES and read store projections etc, having attended Greg's course and even presenting on the topic at user groups and a DeveloperDeveloperDeveloper conference.

My issue was specifically around the implementation of aggregates containing more than one entity, and whether entities within the aggregate other than the root should implement domain logic/invariants and record events. Yves has confirmed for me that the approach I had already considered is suitable (using the AR as the recorder of all event). Any "sub-entity" classes I create for SRP/encapsulation/cohesion purposes actually have their events recorded against the AR, and the AR knows how to re-build those (private) classes from the aggregate event stream ready for further behaviours to be invoked.

All my events are captured, stored to the event store and then published on (both synchronously and asynchronously using an ESB) for the purposes of updating read stores etc, that much is fine. It was just this very detailed point I wanted to get feedback on.

Cheers,

Neil.

JCW

unread,
Feb 13, 2013, 5:44:50 PM2/13/13
to ddd...@googlegroups.com
Sorry for the misunderstanding and I apologize if my comments came across the wrong way. Sometimes it takes me several exchanges to get some context about someone on users forums. User Groups are not always the easiest method for getting to know people.

So basically you decided since the AR is the transactional boundary that is where you should enforce your invariants for your entities. Is that correct? This is just to better my understanding.

A Plus,

Jason

Marijn Huizendveld

unread,
Feb 8, 2013, 5:10:29 AM2/8/13
to ddd...@googlegroups.com
Would SaleOrder have one or many dispatch notes? Do they differ from one another in meaning? When would the dispatch note itself be "created"? What would be a good term for that in your domain?

What I usually do is pass a reference of the root to the entity. All methods related to recording the event stream are dispatched to the AggregateRoot. The AggregateRoot is responsible for routing the events to the appropriate entities on replay.

Is that of any help?

Neil Barnwell

unread,
Feb 15, 2013, 5:59:10 AM2/15/13
to ddd...@googlegroups.com
Yeah that's pretty much what Yves suggested and what I'm going with. Might try and implement it in Regalo to DRY it up a bit, so I'm not doing it by hand in each AR I write. :)


Neil Barnwell.
Mobile: 07900 221457
Twitter: @neilbarnwell
e-mail: mai...@neilbarnwell.co.uk
web: http://www.neilbarnwell.co.uk



--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Reply all
Reply to author
Forward
0 new messages