How would one apply command query separation (CQS), when result data is needed from a command?
Asked Answered
M

9

69

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.

Memorize answered 10/9, 2010 at 20:21 Comment(2)
I believe you should also be using event driven architecture, when using CQRS.Coadjutor
The easy way would be to let the command publish an event that others could subscribe to. The handler for that event would also receive the data about the result.Aixenprovence
A
46

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.

Aixenprovence answered 15/7, 2011 at 8:3 Comment(2)
What if command failed?, you subscribe to both ReceiptGenerated and ReceiptGenerattionFailed events, what if ReceiptGenerattionFailed will never be published because of some error?Confuse
@AlexBurtsev – not generating a ReceiptGenerationFailed event because of an error seems like a huge bug. Wouldn't exception handling reasonably prevent this?Browder
V
20

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?

Viand answered 9/9, 2015 at 8:43 Comment(4)
I welcome the distinction between CQS and CQRS and the original question's focus on CQS.Pich
" I'll accept the exception to the CQS rule. " I don't agree. In CQS Commands are handled via CommandHandlers, which are orchestrated by processors. In processors you can mix command and query handlers to achieve the result you need: first process the command, if no errors, process the query that retrieves the new object state. Yes, that means 2 data store interactions, but and advantageous one, as your query model could be completely different from your command model. This will bring clarity and effectiveness to your code.Follansbee
@Follansbee It seems you mix up CQS and CQRS here. CQS has nothing to do with CommandHandlers. It's just a principle that a query for data should not have unexpected side effects. It is idempotent. There are a few common exceptions to this rule: Popping an item from a stack, calling an Increment() function that increases and returns the value atomically or modify an object in combination with a fluent API. In those cases the state has changed and the function returns something other than void. But the intention of the method is clear enough to not cause problems.Viand
@RemcoteWierik "It's just a principle that a query for data should not have unexpected side effects" Yes, I agree... In theory. The application of that theoretical pattern to a concrete use case sees commands being handled by CommandHandlers. Of course it's not mandatory, but it's widely used (in my experience)Follansbee
F
4

Oh that's interesting. Probably I have something to say, too.

During recent time I've been using non-orthodox CQS (maybe not CQS at all for somebody, but I don't really care) approach which helps to avoid messy Repository (because who uses the specification pattern, huh?) implementations and Service layer classes which grow up absolutely enormously over time, especially in huge projects. The problem is it happens even if everything else is fine and developers are pretty skilled, because (surprise) if you have a big class it doesn't always mean it violates SRP in the first place. And the common approach I see in such projects very often is "Oh, we've got huge classes, let's divide them", and that division is mostly synthetic rather than evolving naturally. So, what do people do to cope with this? They make several classes out of one. But what happens with DI in a huge project when you suddenly have several times more classes than before? Not really nice picture since DI is probably already pretty loaded with injections. So there come workarounds as facade pattern etc. (when applicable), and the implications are that we: don't prevent the problem; deal with consequences only and spend much time for it; often use "synthetic" approach to refactoring; get less evil instead of more evil, but still that's evil.

What do we do instead? We apply KISS and YAGNI to CQS as a first step.

  1. Use Commands/CommandHandlers and Queries/QueryHandlers.
  2. Use generic return object for both queries and commands which contains result and error (ouch!).
  3. Avoid standard service and repository implementations by default - only if it's strictly necessary.

What problems are solved with this approach?

  1. Early prevention of code mess, much easier to work with and scale (future proof).
  2. Believe it or not, for medium size project we had neither service classes nor repositories at all. The bigger the project, the more beneficial such approach is (if we assume that CQRS and ES aren't needed and compare only to standard service + data layers). And we're extremely happy with it since it's more than enough for most medium-sized projects in terms of costs and efficiency.

So what would I suggest you to do?

  1. Use right tool for the right job. Use the approach which solves your problems and avoid doing everything by the book if it comes with unnecessary complexity for your case "just because that's why". How often do you see fully RESTful Level 3 APIs, by the way?..
  2. Don't use anything if you don't need it and especially if you don't understand it since if you really don't, it will do more harm than good. CQRS is good for some cases and is still pretty easy to understand, but comes at a price of development and support; ES is rather difficult to understand and even more difficult to build and support.
Fidelis answered 10/10, 2020 at 15:17 Comment(0)
C
3

The question being; How do you apply CQS when you need the result of a command?

The answer is: You don't. If you want to run a command and get back a result, you aren't using CQS.

However, black and white dogmatic purity could be the death of the universe. There are always edge cases and grey areas. The problem is that you begin to create patterns that are a form of CQS, but no longer pure CQS.

A Monad is a possibility. Instead of your Command returning void, you could return Monad. a "void" Monad might 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; }
}

Now you can have a "Command" method like so:

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 grey area is that it is easily abused. Putting return information such as the new OrderID in the Monad would allow consumers to say, "Forget waiting for the Event, we've got the ID right here!!!" Also, not all Commands would require a Monad. You really should check the structure of your application to ensure you have truly reached an edge case.

With a Monad, now your command consumption might 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?

In a codebase far far away . . .

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

In a GUI far far away . . .

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

Now you have all of the functionality and properness you want with just a bit of grey area for the Monad, but BEING SURE that you aren't accidentally exposing a bad pattern through the Monad, so you limit what you can do with it.

Cara answered 16/5, 2017 at 19:19 Comment(0)
L
3

Take some more time to think about WHY you want Command Query Separation.

"It lets you use queries at will without any worry of changing system state."

So it is OKAY to return a value from a command to let the caller know it succeeded because it would be wasteful to create a separate query for the sole purpose of finding out if a previous command worked properly. Something like this is okay in my books:

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

A disadvantage of your example is that it is not obvious what is returned by your method.

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

It is not clear what 'result' is exactly.

Using CQS (Command Query Separation) allows you to make things more obvious, similar to below:

if(_storeService.PurchaseItem(buyer, item)){

    String receipt = _storeService.getLastPurchaseReceipt(buyer);
}

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

Ludlow answered 14/8, 2018 at 22:14 Comment(0)
L
2

I like the event driven architecture suggestions other people have given, but I just want to throw in another point of view. Maybe you need to look at why you're actually returning data from your command. Do you actually need the result out of it, or could you get away with throwing an exception if it fails?

I'm not saying this as a universal solution, but switching to a stronger "exception on failure" instead of "send back a response" model helped me a lot in making the separation actually work in my own code. Of course, then you end up having to write a lot more exception handlers, so it's a trade off... But it's at least another angle to consider.

Lambda answered 21/9, 2010 at 23:8 Comment(1)
Super-late, but still an interesting discussion after eight years: I'm always tempted to throw an exception on failure too, but that can violate a different rule that one should only throw exceptions in truly exceptional cases. If it's totally possible that a command could fail, throwing an exception would be bad. It's a tough dilemma. However, I still find throwing an exception cleaner and more readable than setting up events and event handlers just to see if a command succeeded. Every event you add makes the class more complex.Durham
M
1

I'm really late to this, but there are a few more options that haven't been mentioned (though, not sure if they are really that great):

One option I haven't seen before is creating another interface for the command handler to implement. Maybe ICommandResult<TCommand, TResult> that the command handler implements. Then when the normal command runs, it sets the result on the command result and the caller then pulls out the result via the ICommandResult interface. With IoC, you can make it so it returns the same instance as the Command Handler so you can pull the result back out. Though, this might break SRP.

Another option is to have some sort of shared Store that lets you map results of commands in a way that a Query could then retrieve. For example, say your command had a bunch of information and then had an OperationId Guid or something like that. When the command finishes and gets the result, it pushes the answer either to the database with that OperationId Guid as the key or some sort of shared/static dictionary in another class. When the caller gets back control, it calls a Query to pull back based the result based on the given Guid.

The easiest answer is to just push the result on the Command itself, but that might be confusing to some people. The other option I see mentioned is events, which you can technically do, but if you are in a web environment, that makes it much more difficult to handle.

Edit

After working with this more, I ended up creating a "CommandQuery". It is a hybrid between command and query, obviously. :) If there are cases where you need this functionality, then you can use it. However, there needs to be really good reason to do so. It will NOT be repeatable and it cannot be cached, so there are differences compared to the other two.

Maisey answered 18/7, 2017 at 18:52 Comment(0)
H
1

Well, this is a pretty old question but I post this just for the record. Whenever you use an event, you can instead use a delegate. Use events if you have many interested parties, 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 where the operation failed

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

This decrease the cyclomatic complexity on the client code

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

Hope this helps any lost soul out there...

Hamster answered 14/8, 2018 at 22:0 Comment(0)
G
0

CQS is mainly used when implementing Domain Driven Design, and therefore you should (as Oded also states) use an Event Driven Architecture to process the results. Your string result = order.Result; would therefore always be in an event handler, and not directly afterwards in code.

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

Galactic answered 13/9, 2010 at 15:25 Comment(1)
Cool article, but I think they may be confusing CQS with CQRS. CQS is more about function signatures, where-as CQRS focues on what this article describes. From what I've read CQRS ties into Event Driven Architecture and DDD, like you say, but CQS is a general low level programming techinque.Memorize

© 2022 - 2024 — McMap. All rights reserved.