Are CQRS commands part of the domain model?



I published an online course about CQRS a couple months ago, and since then I realized that there are some topics I didn’t put enough emphasize on in that course, or didn’t cover at all. In the next several blog posts, I’m going to fill this gap.

This article is about CQRS commands and whether they are part of the domain model.

CQRS commands and the onion architecture

So, are CQRS commands part of the domain model? They are. Here’s the onion architecture diagram I’ve been using for several years now:

The onion architecture

The onion architecture

It’s a bit simplified: there are only three layers. I also added a separation between pure and impure domain services, i.e. those services which refer to the external world such as a database, the file system, and those which don’t.

Commands belong to the core domain (just like domain events). They play an important role in the CQRS architecture – they explicitly represent what the clients can do with the application. Just like events represent what the outcome of those actions could be.

Commands and events are two ends of the same stick, they reside at the same abstraction level. Commands are what triggers a reaction in the domain model. And events are the result of that reaction.

Commands trigger a reaction. Events are the result of that reaction.

Commands trigger a reaction. Events are the result of that reaction.

The only difference between them is that the commands follow the push model while the events – the pull one. The push model means that it’s someone else, not your application, that raises the commands. The pull model is the opposite of that – it’s your application that is responsible for raising the events.

By the way, queries are not on these diagrams because they don’t belong to the onion architecture. Domain modeling is for writes, not reads. Reading data is simple, you don’t need DDD to do that. But you do need a rich and highly encapsulated domain model for data modification. It has a potential for data corruption that you need to have a good protection from.

Commands vs DTOs

A lot of people are hesitant to treat commands as part of the core domain, though. And that’s understandable given how commands are often used:

In the above example, the command serves as a data container for the incoming request. Which is clearly not what you want your domain classes to be used as. Data that comes from external applications should be represented by a special type of classes – Data Transfer Objects (DTOs for short). I wrote about DTOs in detail in this article: DTO vs Value Object vs POCO.

Here’s how the controller method should look instead:

This version contains an explicit mapping between the incoming data (represented by the DTO) and the command. You shouldn’t skip this mapping stage. Otherwise, it would indeed be problematic to treat commands as part of the core domain model.

Why? Because commands and DTOs are different things, they tackle different problems. Commands are serializable method calls – calls of the methods in the domain model. Whereas DTOs are the data contracts. The main reason to introduce this separate layer with data contracts is to provide backward compatibility for the clients of your API.

Without the DTOs, the API will have breaking changes with every modification of the domain model. Or you won’t be able to properly evolve the domain model because of the constraints imposed by the backward compatibility. Either way, using the commands in place of DTOs forces you to choose one of the two sub-optimal design decisions.

On the other hand, the DTOs and the mapping between them and the commands ensure that your application will be both backward compatible and easy to refactor.

Using commands in place of DTOs is akin to using domain entities for the same purpose, which is extremely harmful for the encapsulation of your application. The use of commands is not as bad of course, because the commands themselves don’t contain any business logic, but the drawbacks are similar – the use of entities or commands in place of DTOs hinders your ability to refactor the domain model.

Let’s say for example that you decide to split the student name into first and last names:

Commands are bad at preserving backward compatibility

Commands are bad at preserving backward compatibility

If you use the commands to store the data of incoming requests, you won’t be able to modify the command itself. This would violate the backward compatibility. You need to keep two versions of the command and be able to process both.

It’s much cleaner and more maintainable to just have two layers: the DTOs and the commands, each playing their own part. DTOs for backward compatibility where you can have as many versions of the data contracts as you want, and commands for the explicit representation of what the clients can do with the application. It’s much easier to implement the mapping between the two than to try to lump all these responsibilities into the commands.

Having all that said, it’s fine to use commands in place of DTOs if you don’t need backward compatibility in your application. For example, if both the UI and the backend are hosted in the same process (see: a desktop application), or you develop the API and the clients of that API yourself (see: most enterprise-level web applications), then it means you can deploy both at the same time. Therefore, breaking changes are not an issue since all clients and the API itself will have the latest version deployed simultaneously, you won’t end up in a situation where you have an old version of the client talking to the new version of the API.

But keep in mind that it’s an edge case. Treat it as a code complexity optimization technique. In a case of publicly available API, or if you cannot deploy the client and the API simultaneously, you do need both the DTOs and the commands.

Summary

Alright, that was a rather long version of “Yes” to the question of “Are CQRS commands part of the domain model?”. Let’s summarize:

  • Commands are part of the core domain model. Just like events
  • Commands represent what the clients can do with the application. Just like events represent what the outcome of those actions could be
  • Commands are what triggers a reaction in the domain model. Events are the result of that reaction
  • Commands follow the push model. Events – the pull one
  • Have both commands and DTOs by default
    • View commands as serializable method calls
    • View DTOs as data contracts that help you achieve backward compatibility
  • You can use commands in place of DTOs if you don’t need backward compatibility

Related

Other articles in the series

Share




  • Nikola Yankov

    Great article, Vlad, as always. I really enjoy the way you explain this complex topic. All your posts and courses are helping me a lot. Keep it up.

    And in order to not be quite off-topic let me clarify something for myself. The commands are part from the Core domain, what about command handlers?
    My guess is that they are Non-core domain services, but I will be glad to hear your opinion.

    • Luís Barbosa

      The command handlers doesn’t make any business decisions, it delegates those decision to the domain model. The domain model comprises the core and non-core domain. They are comparable to the application services. Here is a tipical flow inside a command handler:

      – Prepare all information needed for a business operation: load participating entities from the database and retrieve any required data from other external sources.

      – Execute the operation. The operation consists of one or more business decisions made by the domain model. Those decisions result in either changing the model’s state, generating some artifacts, or both.

      – Apply the results of the operation to the outside world.

      More info: https://enterprisecraftsmanship.com/2016/09/08/domain-services-vs-application-services/

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      The line is often blurred but I would attribute handlers to the app services layer.

  • Amir Shitrit

    Thanks for the great post.
    A few questions:
    1. Commands are serializable, but if they aren’t sent over the wire (we have DTOs for that), why should they be serializable?
    2. What if commands are read from a queue instead of being translated from a DTO? Do we still need this separation of commands and DTOs?
    Thanks.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      1. The point about serializable method calls is more of a metaphor, to help build the mental picture. In the general case, commands shouldn’t be converted into strings. You are right that we have DTOs for that (assuming we need to have these two layers separated).

      2. Reading from a queue entails a requirement of maintaining backward compatibility, so you’d definitely need DTOs here.

      • Amir Shitrit

        OK. Sounds good.
        Does the same go for events?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Yep, it does.

  • Jedielson Nakonieczni

    Thanks for your article!!!

    A little question.

    Are command handlers part of domain or can they be considered an application service?

    Thanks!!!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Command handlers are part of the application services layer.

  • https://davideguida.com Davide Guida

    very interesting article, and good addition to your Pluralsight course, thank you.
    I see you’re instantiating the command handler in the controller. What’s your view about using DI instead or a library like MediatR ?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thanks, glad you liked it. I actually do use DI to instantiate handlers, manual instantiation in the controller is just to illustrate the point.

  • http://www.kamilgrzybek.com Kamil Grzybek

    Vladimir, great article but I think a little bit controversial.

    I always think that Commands are part of application service layer similar to Command Handlers. This is the approach described in DDD Red Book written by Vaughn Vernon.

    “Commands represent what the clients can do with the application” – true, but not what can be done with our domain. For example, you can have ten commands and all ten handlers can invoke the same aggregate method. So your public aggregate’s methods are “push model” you described, not the commands.

    What is your opinion? I have described my approach to CQRS recently on my blog http://www.kamilgrzybek.com/design/simple-cqrs-implementation-with-raw-sql-and-ddd/ you can check it if you want to.

    By the way – your blog is awesome and very valuable – I regret that so few people writes about these kind of topics.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Kamil, from your blog post, I see that you are using commands the same way I do (map between the incoming DTO (`Request` in your case) and the command), so it’s more of a terminology/categorization disagreement.

      “Commands represent what the clients can do with the application” – true, but not what can be done with our domain. For example, you can have ten commands and all ten handlers can invoke the same aggregate method.

      Ten command handlers invoking the same method on the domain model doesn’t look like a good design decision. Could you give some examples?

      So your public aggregate’s methods are “push model” you described, not the commands.

      Aggregate’s methods follow the push model, yes, and the commands are a higher level representation of the calls on those method.

      • http://www.kamilgrzybek.com Kamil Grzybek

        Ok, maybe number of ten was bad example, but I wonder if Command to Aggregate Method relation is always one to one.

        Example – I can have two commands AddOrderCommand and AddSimplifiedOrderCommand and both handlers will execute the same Aggregate Method AddOrder(Order order) on Customer Aggregate Root.
        First command is executed when Customer creates order from web application, second when Customer creates order from Mobile application (different endpoint or even service). We assume that mobile app is simplified and Customer cannot enter all order data from mobile phone.
        Of course we can split AddOrder method to two methods (AddOrder, AddSimplifedOrder) but my question is if it is good approach? Two methods will be required if we would have different logic for these two cases but if the logic is the same?

        I am still wondering about this. What is your opinion?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          That’s a good example. I think I wouldn’t introduce another method in the domain model. Would make both command handlers call the same one.

          But that still doesn’t invalidate my point from the article that commands represent what the clients can do with the app. From the client’s perspective, these operations are two different use cases, so introducing two commands makes sense here even though they will work with the same method from the domain model.

          • http://www.kamilgrzybek.com Kamil Grzybek

            commands represent what the clients can do with the app

            I agree! But your main point from the article is:

            Commands are part of the core domain model.

            I don’t agree with that. As you described “can do with the app” so for me they are “closer” to application than domain model so they should be categorized in ApplicationService Layer.

          • http://enterprisecraftsmanship.com/ Vladimir Khorikov

            I would rather base the categorization on the fact that commands operate at the same abstraction level as domain events. If we agree that domain events are part of the core domain model, then commands should belong there too.

          • http://www.kamilgrzybek.com Kamil Grzybek

            I totally agree that domain events are part of Domain Model. I still don’t agree that commands should belong there too 🙂 Scott Millet and Vaughn Vernon put them in Application Layer – check theirs codebases – http://www.wrox.com/WileyCDA/WroxTitle/Patterns-Principles-and-Practices-of-Domain-Driven-Design.productCd-1118714709,descCd-DOWNLOAD.html (Chapter 25) and https://github.com/VaughnVernon/IDDD_Samples_NET/tree/master/iddd_identityaccess/Application

          • http://enterprisecraftsmanship.com/ Vladimir Khorikov

            Appeal to authority is sometimes a useful shortcut but not an absolute argument.

            I could be wrong here (of course), but currently don’t think I am. BTW, regarding your earlier argument that 2 commands can result in invocation of the same method. It’s actually the same for domain events. A single method can result in producing 2 domain events. Still, that doesn’t prevent domain events from residing in the core domain layer.

          • Luís Barbosa

            @kamil_grzybek:disqus think in commands as business intentions, something you want a system to do and events as immutable facts for the business. From this point of view, it already seems clearer that commands should be in the domain?

  • Anderson GM

    Hi Vladimir,

    Thanks for sharing your ideas. I’m always reading your blog and never get disappointed =)

    Because I watched your Pluralsight course I promptly answered “No” with some confidence to your question. Guess what? You answered “Yes”.

    I will try summarize my doubt with a question. Are you going to create commands and calling your pure services or handlers direct – or indirect with some infrastructure – to coordinate the execution of your code (despite from the exposed interface, in thin case, the controller)?

    I’m asking that because commands should be used by the outside world to communicate with your app (although you can protect it with DTOs for compatibility reasons as you mentioned).

    *Maybe I’m only reproducing with some imprecision what I saw – or at least what I think I saw – in your course.

    Thanks