Atomic domain events?

219 views
Skip to first unread message

Sebastian Good

unread,
Dec 20, 2011, 2:23:30 PM12/20/11
to DDD/CQRS
We are struggling with a modeling problem to which I suspect there
isn't an absolutely correct answer, but I'm eager for some feedback
from the members of the group.

Take a classic example of the difference between a simple CRUD-based
event and an event with true domain meaning: CustomerAddressCorrected
vs. CustomerMoved. Both update a customer's address, but one indicates
a typo was fixed, and one indicates that the person moved. They have
radically different business meaning.

But the raw content of the events may well be identical. No problem,
we have a common object like AddressUpdated, which is a member of both
events

AddressUpdated: { Street:string; State:enum } // etc
CustomerAddressCorrected: { CustomerId:CustomerId;
AddressUpdated:AddressUpdated }
CustomerMoved: { CustomerId:CustomerId; AddressUpdated:AddressUpdated}

This isn't particularly difficult, but it does cause what might be
considered laborious investigation of the domain model (as exposed in
its events) to see this duplicated data. For instance, a read model
projection which was only concerned with tracking the customer's
current address would have to match on both CustomerAddressCorrected
and CustomerMoved, pull the same object out of both, and hand it to a
similar handler.

But a concept I see trafficked with increasing regularity is the
notion that domain events come in self-consistent batches, e.g.
Commits. One command handler might emit multiple events, and those
events should be considered together, or not at all. It's easy to
understand this if the events appear to be totally unrelated
(CustomerMoved and AccountClosed), but why not take advantage of this
to simplify our modeling language? What if we just had

AddressUpdated: { CustomerId:CustomerId; Street:string;
State:enum } // etc
CustomerAddressCorrected: { CustomerId:CustomerId; }
CustomerMoved: { CustomerId:CustomerId; }

Where a single commit from the "MoveCustomer" command would contain
both the "CustomerMoved" event and the "AddressUpdated" event?
Obviously the "CustomerMoved" event no longer stands on its own, but
we admitted as much when we allowed events to travel in packs anyway.

I can see pros and cons to both approaches. The former approach seems
to result in significant redundancy in events which accomplish similar
things but come from different stimuli. The latter approach likely
makes projections easier to write as the events are simpler and less
repetitive. The latter approach may too easily lead to a degradation
of everything to a simple list of CRUD commands.

(Note, I am still assuming this is the event stream of a single
aggregate root. On our project at least, we don't really make it
possible to fold together events from multiple aggregates into a
single commit, which is essentially how we ensure each aggregate is a
transactional boundary)

What are peoples' experience with relying on multiple domain events to
capture a transactional change to an aggregate root?

Peter Ritchie

unread,
Dec 20, 2011, 2:48:09 PM12/20/11
to ddd...@googlegroups.com
I've seen this sort of thing done with event hierarchies.  i.e. a CustomerMoved event would have a base of CustomerAddressUpdated.  (or they both share a common base; but, you get the idea) Therefore emitting a single CustomerMoved event would trigger handlers of CustomerAddressUpdated events if no CustomerMoved event handlers existed.  The handler would then handle the CustomerMoved event when it wanted to deal with the moved-specific details and could chain out to the same code that processes an address updated event--if that were appropriate.

There could be some benefit to having two events for a MoveCustomer command; but, if you don't know what they are, then it may not be important in your domain.  But, if you do have two events then you'll have to commit to transactions at some level or possibly event ordering (i.e. should a move occur before an update?  Depends on how you deal with a "transaction"...).  If it's not apparent what the benefits are of multiple events in this case, you may be needlessly complicating your domain.

Cheers -- Peter

Nils Kilden-Pedersen

unread,
Dec 20, 2011, 3:33:17 PM12/20/11
to ddd...@googlegroups.com
On Tue, Dec 20, 2011 at 1:23 PM, Sebastian Good <seba...@palladiumconsulting.com> wrote:
Take a classic example of the difference between a simple CRUD-based
event and an event with true domain meaning: CustomerAddressCorrected
vs. CustomerMoved. Both update a customer's address, but one indicates
a typo was fixed, and one indicates that the person moved. They have
radically different business meaning.

But the raw content of the events may well be identical. No problem,
we have a common object like AddressUpdated, which is a member of both
events

AddressUpdated: { Street:string; State:enum } // etc
CustomerAddressCorrected: { CustomerId:CustomerId;
AddressUpdated:AddressUpdated }
CustomerMoved: { CustomerId:CustomerId; AddressUpdated:AddressUpdated}

I would have a single AddressUpdated event with a Reason enum attached. I prefer this to an event hierarchy where the event matching can become ambiguous/unpredictable/error prone.

to simplify our modeling language? What if we just had

AddressUpdated: { CustomerId:CustomerId; Street:string;
State:enum } // etc
CustomerAddressCorrected: { CustomerId:CustomerId;  }
CustomerMoved: { CustomerId:CustomerId; }

Where a single commit from the "MoveCustomer" command would contain
both the "CustomerMoved" event and the "AddressUpdated" event?

It feels wrong, probably because the address update is a single event. The follow-on events are merely qualifiers for the previous event, so why not model it as such?

@yreynhout

unread,
Dec 21, 2011, 4:09:19 AM12/21/11
to DDD/CQRS
Use polymorphic events (ala NSB): http://www.udidahan.com/2011/01/13/polymorphism-and-messaging/

On 20 dec, 20:23, Sebastian Good <sebast...@palladiumconsulting.com>
wrote:
Reply all
Reply to author
Forward
0 new messages