Responsibilities of the command bus
Matthias Noback
In the previous post we looked at commands and how you can use them to separate technical aspects of the input, from the actual behavior of your application. Commands are simple objects, handed over to the command bus, which performs the change that is needed.
As we learned, the command bus eventually calls the command handler which corresponds to the given command object. For
example when a SignUp
command is provided, the SignUpHandler
will be asked to handle the command. So the command bus
contains some kind of a lookup mechanism to match commands with their handlers. Some command bus libraries use a naming
convention here (e.g. handler name = command name + “Handler”), some use a kind of service locator, etc.
Responsibilities of the command bus
The command bus doesn’t merely hand over commands to their handlers. Usually it does all kinds of things. For instance a command bus may validate command data, wrap the command handler in a database transaction, provide queueing options for a command, etc.
How does it do all these things without becoming one big inarticulate unmaintainable class?
There are several options. Usually the Decorator pattern is used to wrap command buses and add behavior. This is particularly easy since command buses generally only have one public method:
interface CommandBus
{
public function handle($command);
}
We should introduce a type for the $command
parameter, but for now this suffices.
If you want to decorate an existing command bus (i.e. you want to add behavior to it), you can do this easily, like this:
class CommandBusWithAddedBehavior implements CommandBus
{
public function __construct(CommandBus $originalCommandBus)
{
$this->originalCommandBus = $originalCommandBus;
}
public function handle($command)
{
// do anything you want
$this->originalCommandBus->handle($command);
// do even more
}
}
The major advantage of this approach is that none of the specialized command bus implementations needs to know about any of the other command buses. It only takes care of its own business and then hands the command over to the next command bus. Each of the command buses can now easily adhere to the Single responsibility principle. The command bus object is also open for extension, and closed for modification.
An example: database transactions
If you want one command bus to wrap the next one in a database transaction, you could do it like this:
class TransactionalCommandBus implements CommandBus
{
public function __construct(CommandBus $innerCommandBus)
{
$this->innerCommandBus = $innerCommandBus;
}
public function handle($command)
{
try {
// start transaction
$this->innerCommandBus->handle($command);
// commit transaction
} catch (Exception $exception) {
// rollback transaction
}
}
}
What we thought was one command bus actually consists of many command buses, but hidden from sight. The command bus is
the one that is not wrapped by another command bus. Of course it’s still an instance of the CommandBus
interface, so
you just need to call its handle()
method and all the magic unfolds itself in the background.
Another example: protecting the original order of commands
Let’s say you let the command bus handle a command. The command bus finds the proper handler for the given command and wraps its execution in a database transaction. Now the handler creates a new command and lets the command bus handle that one:
class Handler
{
public function __construct(CommandBus $commandBus)
{
$this->commandBus = $commandBus;
}
public function handle($command)
{
...
$newCommand = ...;
// we are still handling $command, but now we start handling $newCommand
$this->commandBus->handle($newCommand);
}
}
The first command wasn’t fully handled yet. In fact, the database transaction hasn’t even been closed yet, so now both commands are being handled within the same transaction. Which is totally undesirable since the second command may fail, and take the first command down in its fall.
What we need is a command bus which recognizes the fact that it’s already handling a command. If it is, and someone asks it to handle a new command, it just puts the new command on some internal stack:
class ProtectOrderOfCommands implements CommandBus
{
private $queue = array();
private $isHandling = false;
public function handle(Command $command)
{
$this->queue[] = $command;
if (!$this->isHandling) {
$this->isHandling = true;
while ($command = array_shift($this->queue)) {
$this->innerCommandBus->handle($command);
}
$this->isHandling = false;
}
}
}
About SimpleBus/CommandBus
Everything we have discussed so far (commands, command buses, protecting the order of commands, wrapping command
handling in transactions, etc.) has been covered already for you by the SimpleBus
packages. The central package is simple-bus/command-bus. It contains the interfaces Command
,
CommandBus
and CommandHandler
. It comes with default implementations for:
- A command bus that delegates command handling to specialized command handlers (as discussed above)
- A command bus that finishes a command before it handles the next (idem)
It also offers extension points for implementing a command handler resolver which either:
- Immediately returns the right handler for a given command
- Loads the handler using some kind of a service locator
This package makes (almost) no assumptions about how you are going to use the command bus in your projects. The only assumptions are:
- A command should have at least a name to be able to refer to it. This name doesn’t need to be exactly the same as the
class name, since a class name is another level of abstraction than a command name. Hence, the
Command
interface contains only aname()
method. - A command bus never handles a command itself, so it always delegates to a command handler. This delegation process
always requires some sort of resolving, to find the right handler for the given command. Hence, we have a
DelegatesToCommandHandlers
command bus which uses aCommandHandlerResolver
to resolve the correct instance ofCommandHandler
.
Chain of responsibility
Instead of decorating command buses as described in the examples in this post, the command buses in
SimpleBus/CommandBus
follow the Chain of responsibility pattern. The “inner” or “next” command bus is being
injected from the outside:
$commandBus1 = ...;
$commandBus2 = ...;
$commandBus1->setNext($commandBus2);
...
Instead of being forced to accept the next command bus as a constructor argument, this allows you to have your own
constructors. The downside is that the next command bus may or may not be injected (since your command bus may be the
last one). SimpleBus/CommandBus
comes with a trait that relieves you from the duty to verify this manually all the
time:
class YourCommandBus implements CommandBus
{
use RemembersNext;
public function handle(Command $command)
{
// ...
// delegate to the next command bus, if applicable
$this->next($command);
// ...
}
}
SimpleBus
comes with other useful tools for event handling, Symfony integration, Doctrine integration, etc. so if you
want to start using it in your projects, don’t forget to take a look at the project
homepage.
Conclusion
We discussed the command bus which actually consists of several command buses, wrapped using object composition. Each of
them has separate responsibilities. Because none of them knows about the other, it’s easy to extend the command bus and
add your own functionality to it. The SimpleBus/Command
package provides the code that you need in every project. The
other SimpleBus packages offer extended functionality for the command bus.
In the next post we’ll take a look at events and the event bus.