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.
My main concern with setNext() is the mutability of the buses, which smells like temporal coupling (even if the trait deals with that for you). IMO either the next bus is a dependency of the bus, or the next bus is part of the handling request.
If the next bus is a dependency of the whole object (from instantiation) then it should always be in the constructor and can't be part of any interface. This is where I think decoration should be preferred over CoR. The request to handle is then just "handle this command".
Alternatively, what may make more sense for a command bus is making the next bus be part of the handling request. I'm not sure how the last command bus would work; perhaps $nextCommandBus should be optional.
class CommandBus {
public function handle(Command $command, CommandBus $nextCommandBus);
}
This means you're saying "handle this command and pass it to this handler".
Having a setNext() method is in between these 2. The next handler is almost a dependency and almost part of the handling request. This doesn't feel quite right to me. Either you've got an "optional dependency" (which is an oxymoron) or you have to call 2 methods to make it do 1 thing.
Thanks for mentioning this. Yes, this is (I think) the only concern I have with my own code ;)
I wanted to make the constructor ownership of the author of the command bus. But I didn't think of passing the next bus as the second argument of the handle method until I saw it done like this somewhere else. However, you can't pass in the *actual* next command bus, because you don't know what will be the next command bus after that. So it'd better be a simple callable with one argument, the Command object itself.
In version 2.0 this issue is solved: the "next" callable is provided as the second argument of the handle() method of command/event bus middleware.
See also: http://simplebus.github.io/... ("Implementing your own command bus middleware")
Same here: thanks for asking awesome questions - I'll address them in a new post.
In the beginning of the article, when declaring the CommandBus interface, Matthias mentions "We should introduce a type for the $command parameter, but for now this suffices."
In the example in the article I think it's difficult to specify the type of the $command parameter without changing the interface. One way to solve this is to put the $command parameter into the constructor of the Handler instead of the handle() method. Then all handlers could share the same CommandBus interface, having a parameterless handle() method, which is very beneficial for executing clients. But in that case a new handler object has to be created for each command object, which is not optimal.
Does anyone know a better idea how to tackle this problem?
I don't see the issue with the bus having an interface containing $command->handle(Command $command) . The issue would be the handler interface having such an interface, as it is within the handle method of the handler, not the bus, that we actually want to access the specific methods the concrete command value object provides.
Conall, you're completely right - my lapsus. I wanted to mention a potential issue when the actual handlers implemented a common interface (having a single handle() method), not the buses.
Simplest solutions are to either make handlers callable (either as anonymous functions or objects with __invoke()) or do what Tactician (https://github.com/rosstuck... does and give the CommandBus an inflector to resolve method names (eg MethodNameInflector).
In my opinion, it's a bit odd to IMPLEMENT a CommandBus Interface AND receive an CommandBus in the constructor. That means, translated: "Handler Class XYZ is an CommandBus and needs a CommandBus to work".
Why not EXTEND an BaseCommandBusHandler and work in the ChildCommandBusHandler with parent::?
like
public function handle($command) {
try {
// start transaction
parent::handle($command);
// commit transaction
} catch (Exception $exception) {
// rollback transaction
}
}
And because extending any class is typically a bad idea.
Because you are now hardcoding the chain of command buses (in depends of your inheritance hierarchy), which is far less flexible.
It also mixes all responsibilities in the same class.
"Handler Class XYZ is an CommandBus and needs a CommandBus to work" is perfectly fine. this is how composition works, and it is far more powerful than inheritance
This explains it very well, thanks.
The SimpleBus Symfony integration actually offers a way to decorate command buses using service tags and they allow you to define a priority, which means you can easily move them around in the hierarchy of specialized command buses.