Implementing a use case (III) — Command Bus

Enhancing your use cases with extra powers easily

Maikel González Baile
5 min readJul 26, 2018

This post is part of Implementing a Use Case, a series of posts where I share my learnings on designing, architecting and implementing use cases. I suggest reading the previous posts where I already explained some concepts you might find here.

You can either take a look at the code of the application example or the different tags which show the state of the application at the moment of the post.

In the previous post, I introduced the Command Pattern as a good technique to represent your use cases in your code. In this new post, I am going to show you a pattern to easily enrich your use cases with extra functionality. See the code of the post here.

So far, we have seen that use cases orchestrate the dependencies which are passed to the class owning the behavior.

As you can see, the last step of the use case is to persist the new state of the Pull Request. However, what if there is an exception afterward so that an error is shown to the user? Should the Pull Request still be saved in the database? Should we rollback the database transaction to undo the action instead?

By definition, a use case must be transactional, meaning that in case of error all changes performed within the use case and saved in the database must be reverted. In databases with ACID capabilities we can manage a transaction by doing something like:

try {
$database->beginTransaction();
// DO SOME LOGIC
$database->commit();
} catch (\Throwable $exception) {
$database->rollback();
}

In the example above, a transaction is started at the beginning, then some code is executed (i.e. the use case) and then the transaction is either committed or reverted if everything went well or not respectively. In order to avoid adding the transaction management code to all our use cases, we can make use of the Command Bus pattern.

Command Bus

The Command Bus pattern is based on the chain-of-responsibility pattern.

In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.

You can see the Command Bus as a pipeline consisting of chained classes so that when you send a Command through the bus all piped classes get executed sequentially receiving the Command.

Classes in the chain are called Middlewares and implement the next interface:

All of them receive the Command and the next Middleware to be executed. This way, each Middleware can perform some work either before or after passing the command to the next Middleware. For instance, imagine that we want to log all Commands executed by our app:

Easy, you just inject the Logger so when the Middleware is executed the Command is first logged, then the execution continues through the next Middleware.

As I explained at the beginning of the post, use cases must be transactional, so let’s add another Middleware to handle this logic:

The Middleware, in this case, is first starting a transaction, then the execution flow is passed to the next Middleware so that if everything succeeds the transaction is committed. Otherwise, since the execution of the next Middlewares is wrapped by a try/catch block, exceptions are caught and the transaction is reverted.

Finally, we need to execute our use case, right? We need a Middleware that, based on the Command received, it can instantiate the associated CommandHandler to handle the Command.

In this case, since by convention we correlate Commands and CommandHandlers by adding the Handler suffix to the name of the Command, we can easily retrieve the corresponding CommandHandler from the Container. Then, we just need to execute the CommandHandler by passing the Command to its handle method. You have to take into account that we are using the Fully Qualified Class Name of the CommandHandler class as the alias to retrieve it from the Container, meaning that if you are using another kind of aliases to identify your services you will need some sort of mapping logic to associate each Command with the service alias of the corresponding CommandHandler, something like:

Now that we have our Middlewares ready, the class in charge of routing the Command through all of them sequentially is the Command Bus.

To do a concrete implementation and see an example of how the Bus routes the Command throughout all the middlewares let’s start with the test:

The test instantiates three spy middlewares (to learn more about Spies and other different test doubles take a look at this Uncle Bob’s post) which will allow us to check whether the middlewares are called or not by the bus. Then, a CommandBus is instantiated with the three middlewares injected and it gets executed. Finally, the test asserts that each middleware was called.

If you see the body of the fake command bus, the class responsible for chaining the Middlewares is the MiddlewarePipelineFactory, let’s implement it to pass our test.

Here the trick is that each middleware is wrapped with a closure so that each middleware knows which is the next middleware to be executed. As result, we have a function that just needs to receive a Command to sequentially call all the piped middlewares.

Now, we are ready to enrich our use cases with new functionality without modifying the use cases code at all.

You can make use of the recently created command bus from your controllers. When an Http request is received by any of your controllers you just need to instantiate the corresponding command and route it through your bus.

Linking learnings with some theoretical concepts

The Command Bus technique favors some of the SOLID principles which makes our code cleaner designed:

SRP (Single Responsibility Principle)

Robert C. Martin expresses the principle as

A class should have only one reason to change.

Each Middleware has a specific responsibility. Two different reasons, changing the way we log commands or how the transaction is managed, will not make you modify the same class.

OCP (Open Closed Principle)

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

You have seen how we are now able to extend the functionality of our use cases without modifying any code of them.

DIP (Dependency Inversion Principle)

High level modules should not depend upon low-level modules. Both should depend upon abstractions.

Abstractions should never depend upon details. Details should depend upon abstractions.

Taking a look at the code of the Resource, although it is using a Command Bus, the resource just knows that he can pass a Command to the bus. You are totally free to have different Command Bus implementations and inject whichever you prefer so that as long as the behavior remains the same everything will continue working. This is the benefit of depending on abstractions (interfaces) instead of concrete classes.

Extra points

As part of the implementation of the Command Bus and its usage, I have also added some parts you might find interesting such as:

  • A Basic Container that can teach you the basics of how a Dependency Injection service works to instantiate and return a service given an alias.
  • An Http resource (with its test) you can see as an example of a cleanly designed controller without dependencies on any framework

--

--