What is Dependency Injection?

This is the first in a series posts which will explain, in plain language, some important architectural concepts in professional software development. The goal of the series is to help educate both programmers who haven’t used these patterns before, and non-programmers, such as managers or those on the client end of a software development contract. I chose dependency injection for the topic of the first post because it is central to creating software that is well-factored and testable, and because it ties in closely with many other software architecture concepts.

Dependency injection is simple. Like anything, it can get a bit complex if you try to make it very generic and automate it, but at the core the concept is only this: instead of “newing up” the thing you need inside a function, let that thing be given to you. An example will help to clarify this.

Let’s say that we want to send an email every day to employees whose anniversary is the following day. Such a function might look like this:

  1. function Keep_Out_Of_Trouble_With_Spouse
  2.      // Get the list of employees we want to contact
  3.      employeeDatabase = new EmployeeDatabaseConnection()
  4.      employees = employeeDatabase.getEmployees
  5.  
  6.      // Send them each an email to remind them about their anniversary
  7.      emailService = new EmailService();
  8.  
  9.      for each employee in employees
  10.             if employee.Anniversary == Tomorrow
  11.                     emailService.sendAnniversaryReminderTo(employee)
  12.      end
  13. end

This function is fairly well-factored – the finding of employees by anniversary date is taken care of by the EmployeeDatabaseConnection class, and the construction and sending of the anniversary reminder email is delegated to the EmailService. So far, so good – we can change the logic of either of those components without having to change our function. But what happens when we want to test this function? As it stands, we will end up sending a lot of (possibly incorrect – we’re just testing after all!) emails to employees during testing.

The way to eliminate that side effect during testing is dependency injection. If we inject the email service, we get:

  1. function Keep_Out_Of_Trouble_With_Spouse(IEmailService emailService)
  2.      // Get the list of employees we want to contact
  3.      employeeDatabase = new EmployeeDatabaseConnection()
  4.      employees = employeeDatabase.getEmployees
  5.  
  6.      // Send them each an email to remind them about their anniversary
  7.      for each employee in employees
  8.           if employee.Anniversary == Tomorrow
  9.                emailService.sendAnniversaryReminderTo(employee)
  10.      end
  11. end

Note how instead of creating the email service within our function, we’re receiving it as a parameter to our function. Also note that the type of the parameter is IEmailService. This means that instead of saying “we have to have an EmailService!” we’re saying “We just need something that can handle the functions we’re going to call”. The way to define that is an Interface. For testing, we could have a class called ConsolEmailService which looks like this:

  1. public class ConsoleEmailService extends IEmailService
  2.      function sendAnniversaryReminderTo(employee)
  3.           Console.WriteLine("Sending anniversary reminder to: " + employee.Name
  4.      end
  5. end

Ahh, that’s better! Now we can test to our heart’s content without worrying about flooding our beloved employees’ inboxes. But we still have a problem – any time we test, we don’t know how many employees in the database might have an anniversary coming up. It could be a hundred, or it could be none. Not a very good situation to be in when you want to test for a consistent result. Like the EmailService, the EmployeeDatbaseConnection can be injected as well. Let’s see what that would look like:

  1. function Keep_Out_Of_Trouble_With_Spouse(IEmailService emailService, IEmployeeRepository employeeRepository)
  2.      // Get the list of employees we want to contact
  3.      employees = employeeRepository.getEmployees
  4.  
  5.      // Send them each an email to remind them about their anniversary
  6.      for each employee in employeesWithAnUpcomingAnniversary
  7.           if employee.Anniversary == Tomorrow
  8.                 emailService.sendAnniversaryReminderTo(employee)
  9.      end
  10. end

I’ve used the name “IEmployeeRepository” here to touch on the fact that using the repository pattern is generally a good way to access your data – the repository can take care of retrieving raw data and filtering or transforming it for use by other parts of the application. But other than that, it’s the same story – now we don’t need a database connection per se, but just something that can handle a call to getEmployeesWithAnniversaryOn(). That might look something like this:

  1. public class MockEmployeeRepository extends IEmployeeRepository
  2.      function getEmployees
  3.           bob = new Employee { Name = "Bob", Anniversary = Today – 1 }
  4.           jim = new Employee { Name = "Jim", Anniversary = Today }
  5.           pat = new Employee { Name = "Pat", Anniversary = Today + 1 }
  6.           sue = new Employee { Name = "Sue", Anniversary = Today + 2 }
  7.  
  8.           return new Employee[] { bob, jim, pat, sue }
  9.      end
  10. end

Now we know that whenever we use the MockEmployeeRepository, we can expect to get back one employee whose anniversary is tomorrow, and three that aren’t. Much better for testing!

Posted Sunday, October 13th, 2013 under Software Architecture.

Leave a Reply