What result does a Command request return in CQRS design?
Asked Answered
P

2

9

I've been looking at CQRS but I find it restricting when it comes to showing the result of commands in lets say a Web Application.

It seems to me that using CQRS, one is forced to refresh the whole view or parts of it to see the changes (using a second request) because the original command request will only store an event which is to be processed in future.

In a Web Application, is it possible that a Command request could carry the result of the event it creates back to the browser?

Purl answered 31/12, 2010 at 12:26 Comment(0)
C
6

The answer to the headline of this question is quite simple: nothing, void or from a webbrower/rest point of view 200 OK with an empty body.

Commands applied to the system (if the change is successfully committed) does not yield a result. And in the case that you wish to leave the business logic on the server side, yes you do need to refresh the data by executing yet another request (query) to the server.

However most often you can get rid of the 2nd roundtrip to the server. Take a table where you modify a row and press a save button. Do you really need to update the table? Or in the case a user submits a comment on a blog post just append the comment to the other comments in the dom without the round trip.

If you find yourself wanting the modified state returned from the server you need to think hard about what you are trying to achieve. Most scenarios can be changed so that a simple 200 OK is more than enough.

Update: Regarding your question about queuing incoming commands. It's not recommended that incoming commands are queued since this can return false positives (a command was successfully received and queued but when the command tries to modify the state of the system it fails). There is one exception to the rule and that is if you are having a system with an append only model as state. Then is safe to queue the mutation of the system state till later if the command is valid.

Udi Dahans article called Clarified CQRS is always a good read on this topic http://www.udidahan.com/2009/12/09/clarified-cqrs/

Clouse answered 1/1, 2011 at 11:34 Comment(4)
Interesting answer Tim, Thanks. I see the wisdom in using CQRS for implementing commands that don't need immediate result. The problem of updating the DOM thinking the Command will eventually materialize is that it makes it hard to tell the user that the command wasn't successful. Maybe by then the user has already left the page thinking that his input is in effect. I can't see how CQRS can be used to solve this problem if all commands are to return void.Purl
The commands must always modify the state of your system when submitted. Deferring this type of work might cause invalid changes to the state of the system giving the user a false positive as you point out. Queuing incoming commands is not the way to go unless you are working with an append only model as the state of your system! Now that the state is changed by the submitted command it's safe to change the UI in the web browser. Other things like denormalized views of your data, aggregation of data, etc. that make up for your queries might be differed till later.Clouse
"Most scenarios can be changed so that a simple 200 OK is more than enough." I'd say the opposite is true. Most operations need the id of the newly-created item to perform further operations on them.Postdiluvian
This is a bad answer. A command should be able to be rejected, and to be rejected it's a very good idea to do so asap. Example: Withdraw cash rejected immediately due to no funds or requester being banned, no cash withdrawn. Otherwise we're not talking about commands but about events miswritten in imperative. Rejecting a command is not the same as ignoring an event.Cash
C
-1

Async commands are a strange thing to do in CQRS considering that commands can be accepter or rejected. I wrote about it, mentioning the debate between Udi Dahan's vision and Greg Young's vision on my blog: https://www.sunnyatticsoftware.com/blog/asynchronous-commands-are-dangerous

Answering your question, if you strive to design the domain objects (aggregates?) in a transactional way, where every command initiates a transaction that ends in zero, one or more events (independently on whether there are some process managers later on, picking one event and initiating another transaction), then I see no reason to have an empty command result. It's extremely useful for the external actor that initates the use case, to receive a command result indicating things like whether the command was accepted or not, which events did it produce, or which specific state has now the domain (e.g: aggregate version).

When you design a system in CQRS with asynchronous commands, it's a fallacy to expect that the command will succeed and that there will be a quick state change that you'll be notified about.

Sometimes the domain needs to communicate with external services (domain services?) in an asynchronous way depending on those services api. That does not mean that the domain cannot produce meaningful domain events informing of what's going on and which changes have occured in the domain in a synchronous way. For example, the following flow makes a lot of sense:

  1. Actor sends a sync command PurchaseBasket
  2. Domain uses an external service to MakePayment and knows that the payment is being processed
  3. Domain produces the events BasketPurchaseAttempted and/or PaymentRequested or similar
  4. Still, synchronously, the command returns the result 200 Ok with a payload indicating some information about what has happened. Even if the payment hasn't completed because the payment platform is asynchronous, at least the actor has a meaningful knowledge about the result of the transaction it initiated.

Compare this design with an asynchronous one

  1. Actor sends an async command PurchaseBasket
  2. The system returns a 202 Accepted with a transaction Id indicating "thanks for your interest, we'll call you, this is the ticket number")
  3. In a separate process, the domain initiates a process manager or similar with the payment platform, and when the process completes (if it completes, assuming the command is accepted and there are no business rules that forbid the purchase basket), then the system can start the notifying process to the actor.

Think about how to test both scenarios. Think about how to design UX to accommodate this. What would you show in the second scenario in the UI? Would you assume the command was accepted? Would you display the transaction Id with a thank you message and "please wait"? Would you take a big faith leap and keep the user waiting with a loading screen waiting for the async process to finish and be notified with a web socket or polling strategy for XXX seconds?

Async commands in CQRS are a dangerous thing and make us lazy domain designers.

UPDATE: the accepted answer suggest not to return anything and I fully disagree. Checkout Eventuous library and you'll see that returning a result is extremely helpful.

Also, if an async command can't be rejected it's... because it's not really a command but a fact.

UPDATE: I am surprised my answer got negative votes. Especially because Greg Young, the creator of CQRS term, says literally in his book about CQRS

One important aspect of Commands is that they are always in the imperative tense; that is they are telling the Application Server to do something. The linguistics with Commands are important. A situation could for with a disconnected client where something has already happened such as a sale and could want to send up a “SaleOccurred” Command object. When analyzing this, is the domain allowed to say no that this thing did not happen? Placing Commands in the imperative tense linguistically shows that the Application Server is allowed to reject the Command, if it were not allowed to, it would be an Event for more information on this see “Events”.

While I understand certain authors are biased towards the solutions they sell, I'd go to the main source of info in CQRS, regardless of how many hundred of implementations are there returning void when they can return something to inform requester asap. It's just an implementation detail, but it'll help model better the solution to think that way.

Greg Young, again, the guy who coined the CQRS term, also says

CQRS and Event Sourcing describe something inside a single system or component.

The communication between different components/bounded contexts (which ideally should be event driven and asynchronous, although that's not a requirement either) is outside the scope of CQRS.

PS: ignoring an event is not the same as rejecting a command. Rejection implies a direct answer to the command sender. Something "difficult" if you return nothing to the sender (not even a correlation ID?)

Source: https://gregfyoung.wordpress.com/tag/cqrs/

https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf

enter image description here

Cash answered 12/11, 2020 at 8:59 Comment(7)
"Dangerous" is an ironically dangerous leap to make. In fact, there are plenty of examples out there of the exact scenario you pose as "dangerous", yet we use daily. For example, Amazon's order management and payment system. One does not need to blindly accept the command - acceptance does not imply success, it simply means that it's well-formed. There is plenty of room for both sync and async processing in CQRS.Lianneliao
Then it's not a command, but an event. Do you see the difference? If it can't be rejected it's a fact. No matter if you write it in imperative.Cash
I didn't say it couldn't be rejected, did I? An async command can most certainly be rejected on ingress - quite simple. Some fairly basic stuff here and beyond that, you've clearly glossed over the fact that there are NUMEROUS real-world implementations contrary to your approach.Lianneliao
If the main argument is "there are many implementations like that" there is nothing to discuss anymore. If by "reject" you mean ignore and do nothing, sure, but that's an event. It's a fact that cannot be changed but you choose to ignore (not to react upon).Cash
Good luck notifying the requester about whether a command was accepted or rejected in an asynchronous way, especially if we accept as valid the answer that "commands don't return anything". And later we wonder why there is such a mess in distributed architectures. Well, at least you didn't refer to Confluent "authority" and their infamous "command event" description that has done so much damage.Cash
Yeah, I don't know what to tell you - clearly you don't have adequate experience in the matter, nor have you implemented such systems. Way too much to address in comments, but you are fundamentally incorrect in your assumptions and assertions. Again, lots of real world examples out there that you probably use daily (e.g. Amazon, airline ticketing, etc.) that take these approaches and magically work just fine, in spite of your attestation to the contrary. May be worth investigating how they function.Lianneliao
Maybe the person who coined CQRS term has something to say about it and about mixing CQRS between bounded context (like you're suggesting when talking about ordering system and payment system), considering CQRS is not a top level architecture. You're mixing architectural styles with CQRS, and this question is about CQRS. gregfyoung.wordpress.com/tag/cqrsCash

© 2022 - 2024 — McMap. All rights reserved.