I announced recently that I’ll be posting some smaller bits to this list that aren’t a good fit for the blogging format. So here’s the first of such bits. It’s an interesting question I received from a viewer of my CQRS in Practice Pluralsight course (reply to this email if you need a trial code that gives a 30 days unlimited access to Pluralsight, I still have some).
The question is about CQRS commands and primitive types (shared with permission, edited lightly for clarity):
Hi Vladimir,
My colleague and I discussed commands in CQRS and we both agreed that they should only contain primitive types, but we disagree on collections of primitives. In my opinion having a collection of primitives does not violate the principle of having only primitive types but in his opinion, this is wrong. He argues that we should create as many commands as the number of items in the collection. Which is the right approach?
There are two questions in this message. Well, one is a question and the other one is a presupposition:
-
Can commands contain collections of primitive types? — the question itself.
-
Should commands only contain primitive types? — the hidden presupposition.
As for the collections of primitive types, commands absolutely can have them. Remember, commands in CQRS represent what the external client can do with your application. One command is one action.
For example, if an action involves creation of an order with multiple lines, the corresponding command will contain a collection of those lines. Don’t create commands for each of the order lines, that’s an anti-pattern. Commands shouldn’t beget other commands, they can only be spawned by the external client.
Now, to the presupposition of commands consisting of primitive types only. That’s actually a false premise. Commands don’t cross the application boundary and so you don’t have to keep them backward compatible. Moreover, commands are part of the domain model and, as such, they evolve along with that domain model. Hence, there’s nothing wrong with commands referencing other domain classes.
I recommend that you look at it in terms of the onion architecture:
On the picture from left to right:
-
A controller receives a
ChangedEmailDto
from the external client. Because that’s a DTO, meaning that its sole purpose is to transfer data from one application to another, it consists of primitive types only. -
The controller transforms the DTO into a command by converting some of the primitives into Value Objects (
string email
intoEmail email
in the above example, whereEmail
is a Value Object) and passes that command to a command handler (the application services layer). -
The command handler executes the command by coordinating the work between domain classes (including the already dehydrated
Email
Value Object). -
The domain model generates domain events. Domain events may also contain value objects — for the same reasons commands do, since both commands and domain events reside at the same level of abstraction in the onion architecture.
-
The app services layer converts the domain events into messages on the message bus. Those messages are plain DTOs too because their sole purpose is to communicate the email change to other systems.
Notice the symmetry. Once a piece of information enters the application, it gets converted from a shapeless blob of data into a command, which has a clear domain meaning. That command expresses itself using domain terms — Value Objects. On the other hand, a domain event is something that has happened in your application, which may also be expressed using Value Objects. When the domain event leaves the application, it gets converted back into a plain DTO.
--Vlad
https://enterprisecraftsmanship.com
Enjoy this message? Here are more things you might like:
Workshops — I offer a 2-day workshop for organizations on Domain-Driven Design and Unit Testing. Reply to this email to discuss.
Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »
My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »