"If the only tool you have is a hammer, you tend to see every problem as a nail."
Abraham Maslov

Monday, August 5, 2013

Dependency Injection in C++

One of the most fundamental rules of good programming is the single responsibility principle, a term coined by Robert C. Martin. In object oriented programming a similar concept is often referred to as encapsulation. Unfortunately, programmers usually get these two rules wrong. Separating responsibilities is not only about wrapping code into separate classes and methods, but also about decoupling dependencies. Consider the following code:

There is one big problem with this implementation: class Foo is strongly tied to the concrete instance of the class Logger, which has the following implications:
1) If you ever need to write a new logger and make your application use it, you will have to browse through all the classes depending on the logger and refactor them.
2) There is no way to write good unit tests for class Foo, since it requires the environment setup expected by Logger (like syslog, database, log directory on the filesystem, etc.).

A solution to this problem is to turn Logger into an abstract interface and inject its concrete implementation (hence term "dependency injection") into class Foo through a constructor. Because C++ implements multiple inheritance instead of interfaces, let's just use an abstract class ILogger:

With this implementation it is now possible to create different loggers inheriting from ILogger and use them with class Foo without any modification of the Foo itself (it follows so called open/closed principle, which means that you can modify object's behaviour without changing its source code). It is also possible to write unit tests to cover doSomething(), using a fake logger having an empty log() method, or even doing some assertions inside. The classes are loosely coupled, which means that you can use them like independent building blocks, and make changes to the application architecture much more easily.

However, if you have a lot of classes, it is tedious to instantiate all of them with proper dependencies, like this:

A common pattern that solves this problem is called a dependency injection container. It's a mechanism that helps you managing application through registering and resolving dependencies. More advanced containers (like Google Guice for Java or Symfony Framework Container for PHP) provide additional services, like support for injecting dependencies through setters or defining dependencies in separate configuration files (XML or YAML for example). However, these features rely heavily on reflection and cannot be easily used in C++, so let's just create a simple dependency resolver:

The resolver implements two methods: Register() and Resolve(), which store and retrieve data from a map holding associations between type name and a pointer to a concrete object of that type. You can now use it to simplify dependency management of the initial Foo class:

The resolver can also be used as a service locator, which means that a class uses a resolver instance to retrieve the dependencies itself, instead of relying on injection through a constructor or setter:

Using a resolver or a full-blown dependency container to inject class dependencies is generally considered better practice than using service locators within classes, because it forces you to initialize dependencies before injecting them (with service locator you may forget to register all dependencies required by a class before trying to make an object).
The resolver is publicly available for download on Github. It's super simple (around 30 lines of code, not including unit tests and comments) and uses a simplified BSD license, which means that you can use and distribute it with any project (free or commercial) without any restrictions, provided that you keep the original copyright notice.