277
CHAPTER 6 | Tackle Business Complexity in a Microservice with DDD and CQRS Patterns
The command handler class offers a strong stepping stone in the way to achieve the Single
Responsibility Principle (SRP) mentioned in a previous section.
A command handler receives a command and obtains a result from the aggregate that is used. The
result should be either successful execution of the command, or an exception. In the case of an
exception, the system state should be unchanged.
The command handler usually takes the following steps:
•
It receives the command object, like a DTO (from the
mediator
or other infrastructure object).
•
It validates that the command is valid (if not validated by the mediator).
•
It instantiates the aggregate root instance that is the target of the current command.
•
It executes the method on the aggregate root instance, getting the required data from the
command.
•
It persists the new state of the aggregate to its related database. This last operation is the actual
transaction.
Typically, a command handler deals with a single aggregate driven by its aggregate root (root entity).
If multiple aggregates should be impacted by the reception of a single command, you could use
domain events to propagate states or actions across multiple aggregates.
The important point here is that when a command is being processed, all the domain logic should be
inside the domain model (the aggregates), fully encapsulated and ready for unit testing. The
command handler just acts as a way to get the domain model from the database, and as the final
step, to tell the infrastructure layer (repositories) to persist the changes when the model is changed.
The advantage of this approach is that you can refactor the domain logic in an isolated, fully
encapsulated, rich, behavioral domain model without changing code in the application or
infrastructure layers, which are the plumbing level (command handlers, Web API, repositories, etc.).
When command handlers get complex, with too much logic, that can be a code smell. Review them,
and if you find domain logic, refactor the code to move that domain behavior to the methods of the
domain objects (the aggregate root and child entity).
As an example of a command handler class, the following code shows the same
CreateOrderCommandHandler
class that you saw at the beginning of this chapter. In this case, it also
highlights the Handle method and the operations with the domain model objects/aggregates.
Dostları ilə paylaş: