Returning From Command Buses
The most common question I get about my command bus library is: “can commands really return nothing?” The second most common question is “Why do you let commands return something, don’t you know that’s Wrong(tm)?”
It’s easy to get hung up on form, not function. That’s a shame because command buses aren’t important. In the grand scheme of things, they’re completely, utterly, totally unimportant. It’s all about where the messages are going, not how they get there.
Still, let’s take a look at some myths about command buses.
“Command Buses are a part of CQRS and they always go together.”
CQRS is about the separation of a (write) model that solves a problem and a (read) model that informs you about problems. This is a useful lens for viewing some domains.
While I wasn’t there when the term was coined (and haven’t asked), it’s pretty logical to assume the “Command” in “Command Bus” had the same etymology. It was a piece of plumbing used to address the write model, which is the important part of our app.
But that’s a one way relationship. Write model doesn’t care how you send it information. A “old school” service layer like this:
is just as CQRS-y as a command bus like this:
$this->serviceLayer->handle(new OpenAccount($email, $password));
It has the same guarantees, the same ability to encapsulate. It’s just a minor difference in implementation. And no, it doesn’t return anything.
Conversely, if we’re using either version in a non-CQRS app, it doesn’t matter if we return something or not. The non-returning is a property of CQRS, not the Command Bus.
“You can only use a Command Bus if you’re doing CQRS.”
Nowadays I would argue the term “Command” in Command Bus has less to do with the CQRS write model and more to do with the classic Gang of Four definition of “Command”, i.e. breaking down operations into discrete units and passing them around. Command Bus has found a broader audience as a modern take on implementing a service layer. And that’s okay.
The advantages for a command bus hold true whether you’re using CQRS or not:
- It’s easy to decorate the uniform interface
- It’s different enough to form a clear barrier between UI and domain model
- The command class is a nice way to capture ubiquitous language
- The command DTOs can pair well with form libraries and serializers.
We use a command bus because it’s a useful implementation idiom, not because it’s a fixed part of CQRS. It’s not key architecture, it’s just a handy little twist.
“I should be using CQRS and Command Buses because that’s good practice”
No, they’re useful practices for some types of problems. CQRS is rarely a primary goal anyways. Most of the folks I see using it are actually oriented at doing Event Sourcing, which is another orthogonal concept altogether.
“I shouldn’t be returning anything because CQRS is CQS which says don’t return anything”
CQS (like CQRS) can be a useful lens for some problems but not all situations or practices. It is a good guideline for warning you against side-effect prone code. That said, CQS is aimed at method level whereas CQRS is targeting higher-level architecture. I’d argue they’re spiritually similar but CQRS isn’t direct a superset of CQS.
“We don’t return things because commands are asynchronous”
At a technical level, this seems legit. We could be sending the command into a background queue so we don’t know when it’s actually going to be executed. Therefore, we can’t count on a return value for any command.
Truncated by Planet PHP, read more at the original (another 6243 bytes)