How would one apply command query separation (CQS), when result data is needed from a command?
This question is old but has not received a satisfying answer yet, so I'll elaborate a bit on my comment from almost a year ago.
Using an event driven architecture makes a lot of sense, not only for achieving clear command/query separation, but also because it opens new architectural choices and usually fits with an asynchronous programming model (useful if you need to scale your architecture). More often than not, you will find the solution may lie in modelling your domain differently.
So let's take your purchase example. StoreService.ProcessPurchase
would be a suitable command for processing a purchase. This would generate a PurchaseReceipt
. This is a better way instead of returning the receipt in Order.Result
. To keep things very simple, you can return the receipt from the command and violate CQRS here. If you want a cleaner separation, the command would raise a ReceiptGenerated
event that you can subscribe to.
If you think about your domain, this may actually be a better model. When you're checking out at a cashier, you follow this process. Before your receipt is generated, a credit card check might be due. This is likely to take longer. In a synchronous scenario, you would wait at the cashier, unable to do anything else.
I see a lot of confusion above between CQS & CQRS (as Mark Rogers noticed at one answer as well).
CQRS is an architectural approach in DDD where, in case of a query, you do not build up full blown object graphs from aggregate roots with all their entities and value types, but just lightweight view objects to show in a list.
CQS is a good programming principle on code level in any part of your application. Not just the domain area. The principle exists way longer than DDD (and CQRS). It says not to mess up commands that change any state of the application with queries that just return data and can be invoked any time without changing any state. In my old days with Delphi, the lanquage showed a difference between functions and procedures. It was considered a bad practice to code 'functionprocedures' as we called them back than as well.
To answer the question asked: One could think of a way to work around executing a command and getting back a result. For instance by providing a command object (command pattern) which has a void execute method and a readonly command result property.
But what is the main reason to adhere to CQS? Keep code readable and reusable without the need to look at implementation details. Your code should be trustworthy not to cause unexpected side effects. So if the command wants to return a result, and the function name or return object clearly indicates that it is a command with a command result, I'll accept the exception to the CQS rule. No need to make things more complex. I agree with Martin Fowler (mentioned above) here.
By the way: wouldn't strictly following this rule break the whole fluent api principle?
These links may help
- Meanwhile... on the command side of my architecture
- Returning data from command handlers
- Meanwhile... on the query side of my architecture
- and also this...