5

In domain driven design based on domain events, I have the impression that several sources pronounce the rule that

  • aggregates consume commands and produce events
  • process managers consume events and produce commands

I am aware that in event sourcing, the aggregate must consume events as well, but then they are usually the events produced by the aggregate itself. So I don't see this as a contradiction.

My question would be: What is the foundation for this rule?

For example: Which negative consequences would an aggregate have, that directly consumes events produced by another aggregate? Is it the same if the aggregates are located in different bounded contexts and therefore have separate languages?

2 Answers 2

6

aggregates consume commands and produce events: What is the foundation for this rule?

In DDD, the Aggregates are the only one that are allowed to mutate the system state, so they are the only one that receive and execute commands and produce the state mutations. This is because they need to enforce the business rules.

The state mutations are then returned to the caller, most probable an Application service that persist them in a database.

In Event sourcing, the state mutations are the domain events.

process managers consume events and produce commands

The Process managers/Sagas use the state to decide what is the next course of actions for the business processes that they manage.

In Event sourcing, the state is built from the events, that's why they consume events -> to build their needed state.

Which negative consequences would an aggregate have, that directly consumes events produced by another aggregate?

It is like the two aggregates would share the same table, or parts of it, in a non-event-sourced architectural style, which is very bad. The Aggregate must own its state and it must be independent of external state or services.

Is it the same if the aggregates are located in different bounded contexts and therefore have separate languages?

Yes, but I wouldn't say a different bounded context but a different context. An Aggregate could receive data that is owned by a different Aggregate, but only after it is translated to its language (its command) by the caller, that could be an Application service, a Process manager/saga etc.

2

I think it is important to keep in mind that the primary difference between a Command and an Event is semantics.

Hohpe:

Messages are ultimately just bundles of data, but the sender can have different intentions for what it expects the receiver to do with the message. It can send a Command Message specifying a function or method on the receiver that the sender wishes to invoke.... it can send an Event Message, notifying the receiver of a change in the sender.

CommandReceived is an event; handleEvent is a command.

A key distinction between the two is this

  • commands travel toward the authority for some given state
  • events travel away from the authority for some given state

With that in mind, let's take a look at the players

Aggregates are a component of the domain model, responsible for ensuring that changes to the domain state satisfy the business invariant. The domain model's reason for existing at all is to stand as the authority for that state. So we would expect messages sense to the domain model (and therefore, to the aggregate) to be commands.

Process managers don't actually interact with domain state directly. They are orchestration components that react to messages from other authorities. So we would expect these incoming messages to be events. In reacting to these messages, process managers are usually sending messages to domain models (or other facilities, like email gateways). These outbound messages would be commands.

Which negative consequences would an aggregate have, that directly consumes events produced by another aggregate?

"directly" can mean a lot of different things here. Conceptually, there's nothing wrong with a command like

void placeOrder( OrderFormSubmitted event )

Where things get interesting is figuring out whether or not to include different messages within the same transaction. Udi Dahan's discussion of domain events uses event handlers that run in the same thread / same transaction as the initial command; so the entire orchestration is going to succeed or fail together.

Furthermore, because you really want to avoid two-phase commit if you can possibly help it, you really need to be sure that all of the aggregates involved in the orchestration can participate in the same transaction (ie: are stored in the same database).

More recent writings tend to assume that the aggregates may be distributed, in which case you really want to separate the transactions.

Typically, if you are going to be doing an orchestration across multiple bounded contexts, you are going to want separate transactions anyway.

An additional problem with handling events "directly" is preventing changes to your messages from forcing a cascading upgrade across your system. Greg Young's Versioning in an Event Sourced System is a great read, but the high level summary is that events are messages from the old model to the new, so you should be investing early design capital in ensuring that your message schema are designed with change support in mind.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.