How would one apply command query separation (CQS), when result data is needed from a command?
In wikipedia's definition of command query separation, it is stated that
More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.
If I am issuing a command, how should I determine or report whether that command was successful, since by this definition the function cannot return data?
For example:
string result = _storeService.PurchaseItem(buyer, item);
This call has both a command and query in it, but the query portion is result of the command. I guess I could refactor this using the command pattern, like so:
PurchaseOrder order = CreateNewOrder(buyer, item);
_storeService.PerformPurchase(order);
string result = order.Result;
But this seems like it's increasing the size and complexity of the code, which is not a very positive direction to refactor towards.
Can someone give me a better way to achieve command-query separation when you need the result of an operation?
Am I missing something here?
Thanks!
Notes: Martin Fowler has this to say about the limits of cqs CommandQuerySeparation:
Meyer likes to use command-query separation absolutely, but there are exceptions. Popping a stack is a good example of a modifier that modifies state. Meyer correctly says that you can avoid having this method, but it is a useful idiom. So I prefer to follow this principle when I can, but I'm prepared to break it to get my pop.
From his view, it's almost always worth it to refactor towards command/query separation, except for a few minor simple exceptions.
Solution 1:
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.
Solution 2:
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?