How can I apply Command Query Separation (CQS) when result data from a command is required?

The wikipedia definition of query request separation indicates that

More formally, methods should only return a value if they are referentially transparent and, therefore, have no side effects.

If I issue a command, how can I determine or report whether this command was successful, because by this definition a function cannot return data?

For example:

string result = _storeService.PurchaseItem(buyer, item); 

There is both a command and a request in this call, but part of the request is the result of the command. I think I could reorganize this using the command template, for example:

 PurchaseOrder order = CreateNewOrder(buyer, item); _storeService.PerformPurchase(order); string result = order.Result; 

But it seems that this increases the size and complexity of the code, which is not very positive about the refactor.

Can someone give me a better way to achieve split command request when you need the result of an operation?

Did I miss something?

Thank!

Notes: Martin Fowler talks about the limitations of cqs CommandQuerySeparation :

Meyer likes to use the command request separation absolutely, but there are exceptions. A stack attempt is a good example of a modifier that changes state. Meyer correctly says that you can avoid this method, but it is a useful idiom. Therefore, I prefer to follow this principle when I can, but I am ready to tear it to pop.

In his opinion, it is almost always worth refactoring to separate commands / queries, with the exception of a few minor simple exceptions.

+61
c # command-query-separation
Sep 10 '10 at 20:21
source share
9 answers

This question is old, but has not yet received a satisfactory answer, so I will talk a little about my comments almost a year ago.

Using an event-driven architecture makes a lot of sense, not only to achieve a clear separation of commands / requests, but also because it opens up new architectural options and usually matches the asynchronous programming model (useful if you need to scale your architecture). that the solution may lie in modeling your domain in different ways.

So, take an example of a purchase. StoreService.ProcessPurchase would be the right team to process your purchase. This will create a PurchaseReceipt . This is the best way instead of returning a receipt to Order.Result . To keep things simple, you can return a receipt from the team and break CQRS here. If you want a cleaner separation, the command will raise a ReceiptGenerated event, which you can subscribe to.

If you are thinking about your domain, this might be the best model. When you check the cashier, you follow this process. Before your receipt is generated, a credit card check may be required. It will probably take longer. In a synchronous scenario, you will be waiting at the cashier, unable to do anything else.

+42
Jul 15 2018-11-11T00:
source share
+17
Jul 15 '13 at 7:32
source share

I see a lot of confusion between CQS and CQRS (as Mark Rogers noted in one answer as well).

CQRS is an architectural approach in DDD, in which, in the case of a query, you do not construct full-size graphs of objects from aggregate roots with all their entities and value types, but simply facilitate the presentation of objects in a list.

CQS is a good principle of programming at the code level in any part of your application. Not only a domain zone. The principle exists much longer than DDD (and CQRS). He says not to confuse commands that change any state of the application with requests that simply return data and can be called at any time without changing any state. In my old days with Delphi, the language showed the difference between functions and procedures. It was considered bad practice to code "functional procedures" as we recalled them.

To answer the question: you can come up with a way to bypass the execution of the command and get the result. For example, by providing a command object (command template) that has a void execute method and a readonly command result property.

But what is the main reason to stick with CQS? Keep code readable and reusable without having to look at implementation details. Your code must be reliable so as not to cause unexpected side effects. Therefore, if the command wants to return the result, and the function name or the returned object clearly indicates that it is a command with the result of the command, I will accept an exception to the CQS rule. No need to make things more complicated. I agree with Martin Fowler (mentioned above) here.

By the way, will the whole principle of API fluency not strictly follow this rule?

+13
Sep 09 '15 at 8:43
source share

Take a little more time to think WHY you want to split team requests.

"This allows you to use queries as you wish without worrying about changing the state of the system."

So everything is in order to return the value from the command, so that the caller knows that it is successful

because it would be wasteful to create a separate query for the sole purpose

Find out if the previous team worked correctly. Something like that is okay

my books:

 boolean succeeded = _storeService.PurchaseItem(buyer, item); 

The drawback of your example is that it’s not obvious what your

method.

 string result = _storeService.PurchaseItem(buyer, item); 

It is not clear what a “result” is.

Using CQS (Command Query Seperation) makes things more obvious.

similar to below:

 if(_storeService.PurchaseItem(buyer, item)){ String receipt = _storeService.getLastPurchaseReciept(buyer); } 

Yes, this is more code, but it’s more clear what is happening.

+3
Aug 14 '18 at 22:14
source share

I like the event driven architecture ideas that other people have given, but I just want to give a different perspective. You may need to look at why you are actually returning data from your team. Do you really need a result from this, or could you avoid throwing an exception if it fails?

I'm not talking about this as a universal solution, but switching to a stronger “exception on failure” instead of the “send back answer” model has helped me a lot in that the separation really works in my own code. Of course, then you have to write a lot more exception handlers, so this is a compromise ... But this is at least one more angle to consider.

+2
Sep 21 '10 at 23:08
source share

Question: How to apply CQS when you need the result of a command?

Answer: You do not. If you want to run the command and return the result, you are not using CQS.

However, black and white dogmatic purity could be the death of the universe. There are always edge cases and gray areas. The problem is that you are starting to create templates that are a form of CQS, but not more pure CQS.

Monad is an opportunity. Instead of your team returning the void, you could return the Monad. The "Void" Monad may look like this:

 public class Monad { private Monad() { Success = true; } private Monad(Exception ex) { IsExceptionState = true; Exception = ex; } public static Monad Success() => new Monad(); public static Monad Failure(Exception ex) => new Monad(ex); public bool Success { get; private set; } public bool IsExceptionState { get; private set; } public Exception Exception { get; private set; } } 

You may now have this “Command” method:

 public Monad CreateNewOrder(CustomerEntity buyer, ProductEntity item, Guid transactionGuid) { if (buyer == null || string.IsNullOrWhiteSpace(buyer.FirstName)) return Monad.Failure(new ValidationException("First Name Required")); try { var orderWithNewID = ... Do Heavy Lifting Here ...; _eventHandler.Raise("orderCreated", orderWithNewID, transactionGuid); } catch (Exception ex) { _eventHandler.RaiseException("orderFailure", ex, transactionGuid); // <-- should never fail BTW return Monad.Failure(ex); } return Monad.Success(); } 

The problem with the gray area is that it is easily abused. Entering return information, such as the new OrderID in Monad, will allow consumers to say: "Forget waiting for the event, we have an identifier here!" In addition, not all teams require a Monad. You really have to check the structure of your application to make sure that you have really reached the edge.

In Monad, your command consumption may now look like this:

 //some function child in the Call Stack of "CallBackendToCreateOrder"... var order = CreateNewOrder(buyer, item, transactionGuid); if (!order.Success || order.IsExceptionState) ... Do Something? 

The code space is far.,.

 _eventHandler.on("orderCreated", transactionGuid, out order) _storeService.PerformPurchase(order); 

The GUI is far away.,.

 var transactionID = Guid.NewGuid(); OnCompletedPurchase(transactionID, x => {...}); OnException(transactionID, x => {...}); CallBackendToCreateOrder(orderDetails, transactionID); 

Now you have all the functionality and convenience you want, with only a few gray areas for Monad, but MAKE SURE that you do not accidentally expose a bad template through Monad, so you limit what you can do with it.

+2
May 16 '17 at 19:19
source share

Well, this is a pretty old question, but I am posting it for recording only. Whenever you use an event, you can use a delegate instead. Use events if you have many stakeholders, otherwise use a delegate in a callback style:

 void CreateNewOrder(Customer buyer, Product item, Action<Order> onOrderCreated) 

You can also have a block for the case when the operation failed

 void CreateNewOrder(Customer buyer, Product item, Action<Order> onOrderCreated, Action<string> onOrderCreationFailed) 

This reduces the cyclomatic complexity of client code.

 CreateNewOrder(buyer: new Person(), item: new Product(), onOrderCreated: order=> {...}, onOrderCreationFailed: error => {...}); 

Hope this helps any lost soul there ...

+2
Aug 14 '18 at 10:00
source share

I am very late for this, but there are a few more options that have not been mentioned (although I’m not sure that they are really so wonderful):

One of the options that I have not seen before creates a different interface for implementing the command handler. May be ICommandResult<TCommand, TResult> , which implements a command handler. Then, when a regular command is run, it sets the result according to the result of the command, and the caller displays the result through the ICommandResult interface. With IoC, you can make it return the same instance as the command handler so that you can return the result. Although it can break the SRP.

Another option is to have a kind of storage that allows you to display the results of commands so that the request can receive the request. For example, let's say your team had a ton of information and then had an OperationId Guid or something like that. When the command ends and receives the result, it pushes the response either to the database using this OperationId Guid, or as a key or some kind of general / static dictionary in another class. When the caller receives control back, he calls a return request based on the result based on this Guide.

The simplest answer is simply to click the result on the Team itself, but this may confuse some people. Another option that I mentioned is events that you can technically perform, but if you are in a web environment, this makes management difficult.

Edit

After working with this more, I ended up creating "CommandQuery." Obviously, this is a hybrid between the team and the request. :) If there are times when you need this functionality, you can use it. However, this requires really good reason. It will NOT play and cannot be cached, so there are differences compared to others.

+1
Jul 18 '17 at 18:52
source share

CQS is mainly used in the implementation of Domain Driven Design, so you should (like Oded also specify) use Event Driven Architecture to process the results. So your string result = order.Result; will always be in the event handler, and not immediately after that in the code.

Check out this great article that shows a combination of CQS, DDD, and EDA.

0
Sep 13 '10 at 15:25
source share



All Articles