Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CQRS DDD: How to validate products existence before adding them to order?

CQRS states: command should not query read side.

Ok. Let's take following example:

The user needs to create orders with order lines, each order line contains product_id, price, quantity.

It sends requests to the server with order information and the list of order lines.

The server (command handler) should not trust the client and needs to validate if provided products (product_ids) exist (otherwise, there will be a lot of garbage).

Since command handler is not allowed to query read side, it should somehow validate this information on the write side.

What we have on the write side: Repositories. In terms of DDD, repositories operate only with Aggregate Roots, the repository can only GET BY ID, and SAVE.

In this case, the only option is to load all product aggregates, one by one (repository has only GET BY ID method).

Note: Event sourcing is used as a persistence, so it would be problematic and not efficient to load multiple aggregates at once to avoid multiple requests to the repository).

What is the best solution for this case?

P.S.: One solution is to redesign UI (more like task based UI), e.g.: User first creates order (with general info), then adds products one by one (each addition separate http request), but still I need to support bulk operations (api for third party applications as an example).

like image 843
Teimuraz Avatar asked Jul 10 '17 08:07

Teimuraz


1 Answers

The short answer: pass a domain service (see Evans, chapter 5) to the aggregate along with the other command arguments.

CQRS states: command should not query read side.

That's not an absolute -- there are trade offs involved when you include a query in your command handler; that doesn't mean that you cannot do it.

In domain-driven-design, we have the concept of a domain service, which is a stateless mechanism by which the aggregate can learn information from data outside of its own consistency boundary.

So you can define a service that validates whether or not a product exists, and pass that service to the aggregate as an argument when you add the item. The work of computing whether the product exists would be abstracted behind the service interface.

But what you need to keep in mind is this: products, presumably, are defined outside of the order aggregate. That means that they can be changing concurrently with your check to verify the product_id. From the point of view of correctness, there's no real difference between checking the validity of the product_id in the aggregate, or in the application's command handler, or in the client code. In all three places, the product state that you are validating against can be stale.

Udi Dahan shared an interest observation years ago

A microsecond difference in timing shouldn’t make a difference to core business behaviors.

If the client has validated the data one hundred milliseconds ago when composing the command, and the data was valid them, what should the behavior of the aggregate be?

Think about a command to add a product that is composed concurrently with an order of that same product - should the correctness of the system, from a business perspective, depend on the order that those two commands happen to arrive?

Another thing to keep in mind is that, by introducing this check into your aggregate, you are coupling the ability to change the aggregate to the availability of the domain service. What is supposed to happen if the domain service can't reach the data it needs (because the read model is down, or whatever). Does it block? throw an exception? make a guess? Does this choice ripple back into the design of the aggregate, and so on.

like image 74
VoiceOfUnreason Avatar answered Sep 25 '22 18:09

VoiceOfUnreason