Responsibilities of the command bus

Posted on by 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:

  1. 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 a name() method.
  2. 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 a CommandHandlerResolver to resolve the correct instance of CommandHandler.

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.

If you're interested to learn more about these subjects and start using commands and events in your (Symfony) application, check out my Hexagonal Architecture training website.
PHP hexagonal architecture command bus SimpleBus