cult3

What is Dependancy Injection?

Apr 01, 2013

Table of contents:

  1. An example of Dependency Injection
  2. Conclusion

When you start to build complex web applications, it’s important to structure your components so that they remain independent and your architecture remains flexible and maintainable going forward. However, once you add even the slightest bit of complexity, it can become difficult to maintain this form.

In Object Oriented Programming, it is inevitable that one object will need to use an instance of another. This is likely going to be happening in places all over your project. Say for example you are using a MySQL database. When you are making calls to the database, you will be using an instance of the database object. But what happens if you need to switch databases to use PostgreSQL instead? Dependency Injection is a design pattern that allows you to “decouple” these two components so they remain independent.

A second big advantage to Dependency Injection is when it comes to testing. Recently I introduced Test Driven Development and then we explored PHPUnit. Dependency Injection is another important part of writing good, well tested software.

Back to our database example. When you are testing your code, you probably don’t want to have to actually connect to a Database. Connecting to a database during testing can slow the process down and it requires you to maintain test data when really all you need to test are the methods that interact with the database. By using Dependency Injection, you can replace the database object with a static resource that acts the way you would expect the database to act.

So as you can see, Dependency Injection allows to keep your components independent. Dependency Injection sounds like such a complicated idea, but really it’s very simple. Essentially it just breaks down to passing an object it’s dependencies, rather than letting it create them itself.

An example of Dependency Injection

To show you how Dependency Injection works in real life, here is an example in code. As usual, these examples are in PHP, but hopefully it should be easy enough to translate into whatever language you are using. Don’t take this code too literally, it’s just an example of passing a dependency, rather than something you would actually want to use.

What not to do

Imagine we have the following database class:

class Database
{
    public function __construct($dsn, $user, $password)
    {
        // Make a connection to the database
    }
}

And we have a User class that creates a new user:

class User
{
    private $name;
    private $age;
    private $website;
    private $db;

    public function __construct($name, $age, $website)
    {
        $this->name = $name;
        $this->age = $age;
        $this->website = $website;
        // Instantiate database
        $this->db = new Database(
            "
mysql:host=localhost;dbname=database",
            "username",
            "password"
        );
    }
}

This code is bad for 3 main reasons.

  1. Multiple concerns A class should only ever have one concern. In our User class, we have to deal with the database when really it has nothing to do with the user.
  2. Making changes is difficult Imagine if you had to change the database type or the username or password in every place where you are using this database connection. As you can probably tell, having your classes too closely coupled like this will make it a nightmare to maintain the codebase in the future.
  3. Unit testing is difficult Unit testing is also much more difficult because now we have to deal with the database. As I mentioned above, during testing, you only want to be testing one specific thing. With the Database class being created in the User class, it means we can’t switch it out for testing purposes.

The correct way to use Dependency Injection

Hopefully that example above shows the pain of not using Dependency Injection.

To refactor this example to use Dependency Injection, we simply have to pass the database object to the User class constructor:

class User {
private $name;
private $age;
private $website;
private $db

public function __construct(
    $name,
    $age,
    $website,
    Database $database
) {
    $this->name = $name;
    $this->age = $age;
    $this->website = $website;
    $this->db = $database;
    }
}

Now that we are passing an instance of the database to the User class on construction we have solved the three problems that we had before.

  1. Single concern The User class is now only concerned with the User as it no longer needs to care about the database.
  2. No more repetition Now that we have cut out all the duplicate code it is now much easier to make a change to the database parameters because we only have to do it once. The User class never needs to care about changes made to the database.
  3. Easier to test Now that the User class is just given an instance of the database it makes this much easier to test. Now we can just pass an object that provides the same api as the database, but without having to actually make a connection or return real results.

Conclusion

Whilst Dependency Injection can seem like a difficult term to get your head around, it is really very simple. Dependency Injection is basically just providing an object with the things it needs, rather than allowing it to create them itself. So if an object requires access to the database, instead of allowing the object to create an instance of the database class, we can provide an instance instead.

Dependency Injection is really very important when it comes to testing. When you provide an object with it’s dependencies, it makes it very easy to mock them. If you allow an object to create it’s own dependencies, you now need to deal with them during your tests as the object now has multiple concerns.

To find out more about Dependency Injection, have a read of this article by Fabien Pontencier and this article by Martin Fowler.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.