CQRS Commands and Queries - Do they belong in the domain?

Sam picture Sam · Aug 26, 2015 · Viewed 11.2k times · Source

In CQRS, do they Commands and Queries belong in the Domain?

Do the Events also belong in the Domain?

If that is the case are the Command/Query Handlers just implementations in the infrastructure?

Right now I have it layed out like this:

Application.Common
Application.Domain
  - Model
    - Aggregate
  - Commands
  - Queries
Application.Infrastructure
  - Command/Query Handlers
  - ...
Application.WebApi
  - Controllers that utilize Commands and Queries

Another question, where do you raise events from? The Command Handler or the Domain Aggregate?

Answer

Tomasz Jaskuλa picture Tomasz Jaskuλa · Aug 26, 2015

Commands and Events can be of very different concerns. They can be technical concerns, integration concerns, domain concerns...

I assume that if you ask about domain, you're implementing a domain model (maybe even with Domain Driven Design).

If this is the case I'll try to give you a really simplified response, so you can have a starting point:

  • Command: is a business intention, something you want a system to do. Keep the definition of the commands in the domain. Technically it is just a pure DTO. The name of the command should always be imperative "PlaceOrder", "ApplyDiscount" One command is handled only by one command handler and it can be discarded if not valid (however you should make all the validation possible before sending the command to your domain so it cannot fail)
  • Event: this is something that has happened in the past. For the business it is the immutable fact that cannot be changed. Keep the definition of the domain event it in the domain. Technicaly it's also a DTO object. However the name of the event should always be in the past "OrderPlaced", "DiscountApplied". Events generally are pub/sub. One publisher many handlers.

If that is the case are the Command/Query Handlers just implementations in the infrastructure?

Command Handlers are semantically similar to the application service layer. Generally application service layer is responsible for orchestrating the domain. It's often build around business use cases like for example "Placing an Order". In those use cases invoke business logic (which should be always encapsulated in the domain) through aggregate roots, querying, etc. It's also a good place to handle cross cutting concerns like transactions, validation, security, etc.

However, application layer is not mandatory. It depends on the functional and technical requirements and the choices of architecture that has been made. Your layring seems correct. I would better keep command handlers at the boundary of the system. If there is not a proper application layer, a command handler can play a role of the use case orchestrator. If you place it in the Domain, you won't be able to handle cross cutting concerns very easily. It's a tradeoff. You should be aware of the pro and cons of your solution. It may work in one case and not in another.

As for the event handlers. I handle it generally in

  • Application layer if the event triggers modification of another Aggregate in the same bounded context or if the event trigger some infrastructure service.
  • Infrastructure layer if the event need to be split to multiple consumers or integrate other bounded context.

Anyway you should not blindly follow the rules. There are always tradeoffs and different approaches can be found.

Another question, where do you raise events from? The Command Handler or the Domain Aggregate?

I'm doing it from the domain aggregate root. Because the domain is responsible for raising events. As there is always a technical rule, that you should not publish events if there was a problem persisting the changes in the aggregate and vice-versa I took the approach used in Event Sourcing and that is pragmatic. My aggregate root has a collection of Unpublished events. In the implementation of my repository I would inspect the collection of Unpublished events and pass them to the middleware responsible for publishing events. It's easy to control that if there is an exception persisting an aggregate root, events are not published. Some says that it's not the responsibility of the repository, and I agree, but who cares. What's the choice. Having awkward code for event publishing that creeps into your domain with all the infrastructure concerns (transaction, exception handling, etc) or being pragmatic and handle all in the Infrastructure layer? I've done both and believe me, I prefer to be pragmatic.

To sum up, there is no a single way of doing things. Always know your business needs and technical requirements (scalability, performance, etc.). Than make your choices based on that. I've describe what generally I've done in the most of cases and that worked. It's just my opinion.