Attempting to understand Dependency Injection

Watching Rob Conery and Jeremy Miller work through Dependency Injection for the MVC Storefront project really helped me to piece together a few ideas that had been rattling around in my generally deserted cranium. Dependency injection (DI) is sometimes dismissed as "just" a tool for unit testing and mocking dependencies. But I think DI, and DI containers, offer a bit more to software design than simply providing a way to use mocks for interaction testing. So as usual I’m polluting the blogosphere with my ramblings in an effort to solidify my understanding. Let’s work through an example and see what we can find.

Here is how we could write a class to send invoice reminder emails without any thought given to design or testability:

public class InvoiceReminderService {
  public void SendReminders() {
    var emailService = new EmailService();
    var invoiceRepository = new InvoiceRepository();  
    var invoicesDueForReminderEmail = invoiceRepository.GetInvoicesDueForReminders();
    foreach (var invoice in invoicesDueForReminderEmail) {
      var reminderMessage = createReminder(invoice);
      emailService.Send(reminderMessage);
    }
  }
  //...
}

Here we have dependencies on InvoiceRepository, for getting invoices due for reminder emails, and EmailService, for sending out the emails over SMTP. These dependencies could be instantiated at many different places all over our code base. Without worrying about design principles or testability, let’s simply pull out these dependencies and rely on constructor injection to instantiate them.

public class InvoiceReminderService {
  private EmailService emailService;
  private InvoiceRepository invoiceRepository;

  public InvoiceReminderService(InvoiceRepository invoiceRepository, EmailService emailService) {
    this.invoiceRepository = invoiceRepository;
    this.emailService = emailService;
  }

  public void SendReminders() {
    var invoicesDueForReminderEmail = invoiceRepository.GetInvoicesDueForReminders();
    foreach (var invoice in invoicesDueForReminderEmail) {
      var reminderMessage = createReminder(invoice);
      emailService.Send(reminderMessage);
    }
  }
  //...
}

Here we’ve just created a constructor that takes the required dependencies and adds them to private fields. SendReminders() has been updated so that it is no longer responsible for instantiating the dependencies. I can then instantiate an InvoiceReminderService by creating the dependencies and passing them to the constructor, or I can use a DI container (I’m using a pre-release build of StructureMap 2.5 for this post) to automatically create my dependencies for me:

var invoiceReminderService = ObjectFactory.GetInstance<InvoiceReminderService>();

By default our DI container looks at the greediest constructor (the one with the most parameters) to see what dependencies it needs to create. Because InvoiceRepository and EmailService are both concrete classes (i.e. not interfaces or abstract), we don’t need to give StructureMap any additional information, it can simply instantiate the required objects and pass them through to the InvoiceReminderService constructor.

So what has this accomplished? Well, SendReminders() is now a lot clearer without the dependencies in the way. And we also have an easy way to tell exactly what the dependencies of the class are (the constructor). We are also skirting dangerously close to having a testable class that could easily be modified to follow the Dependency Inversion Principle (DIP) (by extracting interfaces from our dependencies and relying on those instead of on concrete classes) and the Open/Closed Principle (OCP) (by allowing us to change the behaviour of our class by providing different implementations for the dependencies).

But the main, obvious thing this has accomplished is that our class is no longer responsible for instantiating its dependencies. I guess you could almost link this back to the Single Responsibility Principle (SRP) – we are limiting this class’ responsibilities and given it one less reason to change. Why is this good? Well, let’s imagine our EmailService class is used by a number of classes throughout our application. We want to change our EmailService so that it no longer sends emails directly via SMTP. Now it simply queues up the email in a database, and another process is responsible for firing off emails from the queue. To create an EmailService without a DI container I now need to do this to every class that builds an EmailService:

emailService = new EmailService(new EmailRepository());

Or we can just let my DI container handle it for me, and keep our original ObjectFactory call unchanged. This reduces the friction experienced whenever we need to factor out a new class to provide new functionality or to avoid an SRP violation.

//No change need here, even though the EmailService constructor has changed...
var invoiceReminderService = ObjectFactory.GetInstance<InvoiceReminderService>();

(Yes, this is slightly circular logic as I am assuming we using DI for the new EmailRepository class too, but the logic is equally valid if we want to change the constructor to include a connection string or some other parameter. The point is that we can vary the instantiation without affect dependent classes.)

Now I’m not suggesting for a moment that you want to globally replace new with a DI container, but for me the realisation that DI containers were all about abstracting the responsibility of dependency creation, rather than simply providing a testing seam, was a bit of an A-HA! moment. Of course, I am a bit slower than your average developer, so sometimes the things like this take me a while :-)

From abstracting dependency creation to SOLID designs

Now there are still a number of SOLID design principles the code above is violating. This doesn’t mean we need to instantly refactor to be compliant (you’re never going to be, they are general guidelines that can be somewhat contradictory when taken to the n’th degree), but it is something we can look at.

First up is the DIP. We are depending on concrete types rather than abstractions. This also limits our options of altering the behaviour of the class via its dependencies to subclassing those dependencies, which is a minor strike against the OCP. This is easily fixed by extracting interfaces from the dependencies:

public class InvoiceReminderService {
  private IEmailService emailService;
  private IInvoiceRepository invoiceRepository;

  public InvoiceReminderService(IInvoiceRepository invoiceRepository, IEmailService emailService) {
    this.invoiceRepository = invoiceRepository;
    this.emailService = emailService;
  }
  //...
}

StructureMap will auto-wireup these dependencies, but if we are using our EmailService implementation that depends on an extracted IEmailRepository interface, then we’ll need to tell StructureMap’s configuration about it, either at compile time in code or using a configuration file:

public static class Bootstrapper {
  public static void ConfigureIoC() {            
    StructureMapConfiguration.AddRegistry(new DiSampleRegistry());
  }  
}
public class DiSampleRegistry : Registry {
  protected override void configure() {
    ForRequestedType<IEmailRepository>()
      .TheDefaultIsConcreteType<EmailRepository>();                
  }
}

We are now looking at a more traditional DI design. Our InvoiceReminderService is now completely independent of the specific implementations of its dependencies. All the code in the class is cohesive – working at one responsibility with minimal background noise. This project doesn’t even need a reference to the DLL containing the dependency implementations. This means we are fine changing implementations (although not interface contracts!) and we know our InvoiceReminderService is safe. If you were given this class to reuse, or simply to maintain, you wouldn’t have to go pulling in a whole bunch of concrete dependencies. As a result and as a nice bonus, we have some good seams for running automated tests. We can easily stub or mock these dependencies and isolate the behaviour under test.

Aside: DI containers are an obvious way to get plugin and provider-style implementations, by loading specific implementations of an interface at runtime. I’m focusing on more general design effects here – if you’re looking for a plugin/component/provider model you’ll obviously be designing more explicitly for loose coupling and will choose your approach based on that.

Not all beer and Skittles?

That’s the DI theory, as far as I can tell. But as always there is no silver bullet. It is now tougher for us to navigate from the InvoiceReminderService to the current implementations of its dependencies (as we’ve abstracted them away). We are also looking at a potential interface explosion. Why extract an interface for virtually every class you write? That’s two units of code for every responsibility. And we now have a DI container to learn and troubleshoot when debugging. If we’re happy with tight coupling between this class and its dependencies, then why go to these lengths? If you want to run unit tests why not just use TypeMock to break into tightly coupled dependencies? Or at the very least provide default implementations in the class’ default constructor (a.k.a. the poor man’s dependency injection, see Nikola’s post for an interesting variation on this approach):

public class InvoiceReminderService {
  private IEmailService emailService;
  private IInvoiceRepository invoiceRepository;

  public InvoiceReminderService() {
    this.invoiceRepository = new InvoiceRepository();
    this.emailService = new EmailService();
  }

  public InvoiceReminderService(IInvoiceRepository invoiceRepository, IEmailService emailService) {
    this.invoiceRepository = invoiceRepository;
    this.emailService = emailService;
  }  
  //...
}

And how much of all this is just working around limitations of statically typed languages? To me these are all quite reasonable questions (some of these raised by Kevin Berridge in some nice posts here and here, as well as a couple of posts from Jacob Proffitt starting here).

As always the key seems to lie in achieving a balance. The benefits of a loosely coupled design always need to be traded off with any additional complexity of that design. After watching the MVC Storefont DI screencast and having a play around with StructureMap I can see a lot of very obvious benefits to DI containers, but at the same time it’s not something to dive into without having an vague idea of the theory and problems it aims to solve (which is why I’ve spent so much time reading about DI containers, but generally sticking to poor man’s DI until I had a pressing reason to move to a container). After all, we don’t go around blindly applying the GOF patterns to every situation under the sun… right? :-)

Some interesting DI reads

As opposed to this post, here are a few interesting takes on DI.

Comments