And so of course, I managed to leave out one important consideration.
You are on the UI and you, e.g., click a button that creates a command. What happens now?
I didn’t really talk about either the command bus or the command handler, because to a certain extent they are implementation details. You could actually have, e.g. NServiceBus and use a bus, or you could connect through regular method calls, or you could do a host of different things. When it comes to the command handler, you could have some generic handler class or, better I think, have a one-to-one pair between a command and a handler (quick note below).
More important is the question, what do you do if the command fails? With CQRS, even more important to answer is the question, what do you do if the command succeeds?
Command Notification
One set of validation failures can be handled at the client before a command is sent, and the ways of accomplishing this are as varied as they are when CQRS isn’t involved (in fact, CQRS doesn’t change a thing here). Field length validations, regex validations, required field validations, etc. are all things that can be handled by javascript, view model annotations, or a host of other solutions. I won’t go into any more detail here, other than that you would notify the UI when this occurred.
Another set of notification failures are ones that happen due to technical problems with the command bus and/or command handler. These are almost all implementation specific, and so I don’t really have a lot to say here that would be useful (again, you would notify the UI per usual here).
The next set of notification failures are due to a command passing all local validation and then being passed through the bus/handler and into the domain, and then failing due to whatever reason (could be technical problems, could be failing domain-side validation, doesn’t matter). How do you handle this?
It depends a little bit on whether you handle your commands in an async manner or not. Normally, I wouldn’t use async methods here, and instead either make your command passing methods return true or false, or throw a specific exception on why the command failed to be processed inside the domain (this is in my mind preferable, so that you know what to due in various situations).
digression: in case there is any confusion, when I talk about a command failing to be processed in the domain, this shouldn’t be thought of as an ‘exceptional’ in the sense of being rare. I know there is a lot of ‘religious’ debate around exceptions, and in other contexts, I would argue that throwing an exception for a scenario that isn’t rare is arguably bad design. In this situation, if a command fails to be processed inside the domain, I want to know why. Did it fail because of some specific validation rule within the domain? If so, which one? If not, was it a technical problem? Methods that return true/false don’t give you this level of detail. I suppose that one could return a ISpecificCommandSentToDomainMethodResponse message back to the UI. This might actually be a better option. But I digress.
The really interesting case is when you send a command that succeeds, in the scenario where you are using Eventual Consistency.
Keep in mind that you can have a separate Event Store and a separate Query Store, and have all communications between them take place with full transactional support. Though my guess is most implementations of CQRS in the wild will have some amount of Eventual Consistency built in, it isn’t, strictly speaking, required.
But what if you are using Eventual Consistency? This raises interesting scenarios. I’m the customer updating my Address through the UI and click the update button. If I’m using Eventual Consistency, the UI screen will return after the command is sent and doesn’t fail (since we don’t know how long it will take till the query store gets updated, we don’t want to block once the command makes it through the domain). What do we show the user?
There are a couple of options, and a lot of it depends on context and what the end user expects. An obvious option for commands that might reasonably be expected to take more than a few milliseconds is to simply tell the user that the request has been submitted, and to check back later. Though I don’t have any personal experience in the area, I’ve heard anecdotal reports from many people who use online banking and expect this sort of behavior.
In other cases, you can, well,….’lie’ to your user. The end user sent the information that they wanted to update, so it is available on the client (cached or in session or whatever), so you can redraw your UI to include this info. By the time the end user gets into a scenario where they actually have to re-query the Query Store, the info will be there by then.
Mark and Udi have suggested techniques such as these, and while I admire the cleverness of them, I don’t like them. If an end user expects some end result and is shown a ‘fake’ and then, for whatever reason, that end result doesn’t end up in the query store….that seems bad to me. I suppose, like everything, it depends on context. If one is using an internal system and it happens once in a blue moon, and there is a well understood set of actions an end user can take, maybe that’s all right.
But, in general, I lean toward the ‘you sent a command, check back later’ model. It’s honest, and publicly understood.
Command Handlers
Why would it be better to have a specific command handler per command, especially if command handlers are implementation specific anyway?
Potential scalability. If I have a separate piece of code, say, CommandXHandler, to handle all instances of CommandX, then, there is a potential there that I can take that piece of code (CommandXHandler) and scale it separately if needed. For instance, suppose I use MSMQ and so my command bus is MSMQ and different handlers are different queues. Suppose it turns out that a certain type of CommandX is more prevalent than others. If needed, I could then dedicate separate hardware to handle these commands apart from the rest.