Command handlers and infrastructure ignorance, how much is too much

386 views
Skip to first unread message

Bennie Copeland

unread,
Dec 26, 2015, 11:54:50 AM12/26/15
to DDD/CQRS
If my understanding is correct, command handlers are part of the domain and therefore should be ignorant of the infrastructure and only interact with interfaces that are defined in the domain model. How then could I take advantage of the features in NEventStore like using the commit headers to store contextual information like IP address, correlation ID, user, etc. These are all things that I think are outside the responsibilities of the command handler to generate, and how would I write the interface for the eventstore? IEventStore.Add(model, headers) seems to assume too much of what every eventstore supplies. In a normal repository there are methods like Add, GetById, etc, but nothing that assumes anything deep about the infrastructure. Should I just wrap the command handlers in a "context builder handler"? I've had similar thoughts about message buses and keeping my command handlers pure.

Greg Young

unread,
Dec 26, 2015, 1:03:49 PM12/26/15
to ddd...@googlegroups.com
1) if you are using an event store why are you using a service bus?
2) Is a dictionary (key,value) for headers really a large dependency
or assumption on infrastructure?
> --
> 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/d/optout.



--
Studying for the Turing test

Bennie Copeland

unread,
Dec 26, 2015, 2:09:12 PM12/26/15
to DDD/CQRS
1. I should have clarified. I'm using a simple in process bus(mediator?) in my controllers to dispatch commands to the command handlers. The command handlers themselves do not use the bus. But when looking at real buses like NServiceBus or MassTransit it seems that they have their own interfaces to implement for their message handlers. If I want to keep the handlers pure, I have to wrap them with another handler that implements that interface, which is fine as I value that separation. But then how do I utilize the context in the message headers? Just pass a dictionary in with the command? I haven't used messaging before, so I am fairly ignorant about it. It's one of the topics I first encountered while learning about DDD before moving on to CQRS and ES, but having never used it I've been sort of mystified on how you take advantage of it while keeping your application services/command handlers ignorant.

2. Probably not, if I assume that every implementation of an eventstore has headers. In the .net world, yours and Jon Olivers are the only eventstores I'm aware of. Thinking about it now, even if I encountered an eventstore that didn't support it, I could just wrap it in my own envelope type before saving. But the other side of that question, is the command handler really the place to be looking up the IP, grabbing the process ID, username, etc. to be stored in those headers, or do you usually put that code elsewhere?

Greg Young

unread,
Dec 26, 2015, 2:19:16 PM12/26/15
to ddd...@googlegroups.com
"2. Probably not, if I assume that every implementation of an
eventstore has headers. In the .net world, yours and Jon Olivers are
the only eventstores I'm aware of. Thinking about it now, even if I
encountered an eventstore that didn't support it, I could just wrap it
in my own envelope type before saving. But the other side of that
question, is the command handler really the place to be looking up the
IP, grabbing the process ID, username, etc. to be stored in those
headers, or do you usually put that code elsewhere?"

You can wrap a composite pretty easily to track this kind of stuff.

On Sat, Dec 26, 2015 at 7:09 PM, Bennie Copeland

Bennie Copeland

unread,
Dec 26, 2015, 2:42:33 PM12/26/15
to DDD/CQRS
Thank you. I thought that might be the case, but needed some confirmation. And I have to say, your videos have been an invaluable help to me getting my head around this stuff.

A couple of final questions:
1. I've been trying to find a video you did where you showed the event denormalizers with some sql code and talked about saving the company money by getting rid of DBA's. Do you remember what that video was called or have a link to it? I can't seem to recall which one it was.
2. I've always thought that projections are the read models, but in GES it seems they are very different beasts. Was my assumption wrong or is this just an overloaded term now?

Greg Young

unread,
Dec 26, 2015, 2:44:30 PM12/26/15
to ddd...@googlegroups.com
A couple of final questions:
1. I've been trying to find a video you did where you showed the event
denormalizers with some sql code and talked about saving the company
money by getting rid of DBA's. Do you remember what that video was
called or have a link to it? I can't seem to recall which one it was.

Poison pill architecture/stepping stone architecture.

2. I've always thought that projections are the read models, but in
GES it seems they are very different beasts. Was my assumption wrong
or is this just an overloaded term now?

There are differences between internal projections in GES and external
projections. They are mostly useful for re-indexing or doing SEP/CEP
type queries.

On Sat, Dec 26, 2015 at 7:42 PM, Bennie Copeland

Sabrina Munch Hansen

unread,
Mar 19, 2016, 10:23:48 AM3/19/16
to DDD/CQRS


Den lørdag den 26. december 2015 kl. 20.19.16 UTC+1 skrev Greg Young:
"2. Probably not, if I assume that every implementation of an
eventstore has headers. In the .net world, yours and Jon Olivers are
the only eventstores I'm aware of. Thinking about it now, even if I
encountered an eventstore that didn't support it, I could just wrap it
in my own envelope type before saving. But the other side of that
question, is the command handler really the place to be looking up the
IP, grabbing the process ID, username, etc. to be stored in those
headers, or do you usually put that code elsewhere?"

You can wrap a composite pretty easily to track this kind of stuff.


Does anyone have an example on how to do this?

Greg Young

unread,
Mar 19, 2016, 10:39:16 AM3/19/16
to ddd...@googlegroups.com
of how to use metadata? or?

Sabrina Munch Hansen

unread,
Mar 26, 2016, 12:52:45 PM3/26/16
to DDD/CQRS
Yes, and on how to pass the metadata from the commands to the events (circumventing the domain model)?

Sabrina Munch Hansen

unread,
Mar 26, 2016, 12:59:55 PM3/26/16
to DDD/CQRS
Right now I have this code at the end of the Handle methods in my command handlers

myDomainObject.UncommittedEvents = myDomainObject.UncommittedEvents.WithMetadata(myCommand.Metadata);
myRepository.Add(myDomainObject);

Where the first line creates copies of the uncommitted events, but now decorated with the metadata from the commands.

However, it seems wrong that one has to remember to write this line of code, though I can't think of anywhere else in the code where we have access to both the events and the command.

Peter Hageus

unread,
Mar 26, 2016, 1:06:38 PM3/26/16
to ddd...@googlegroups.com
Why not let repository.Add take both aggregate and metadata? (metadata isn’t necessarily coupled to the command, it could just be a dictionary like Greg said)

This is my eventstore abstraction:
Save(StreamId id, IEvent[] events, EventMetadata metadata);

How metadata is built will differ if it’s an aggregate, or just events appended to a stream.

/Peter

Reply all
Reply to author
Forward
0 new messages