There’s a lot of discussion going on between Oren and Jacob (here, here and here) about the relative benefits, costs and overall usefulness of Dependency Injection. Both have done a decent job arguing their beliefs and they certainly triggered some thoughts in my head. In the not so distant past I did a post that showed the steps that I would take when refactoring from junk code into a full IoC implementation that has some Dependency Injection, SRP and interface based design.
I noticed some interesting things when I sat back and analyzed the results. The first thing that jumped out at me was that the coupling of my code, according to nDepend, only made a significant leap when I began coding to interfaces. Prior to the experiment I had expected Dependency Injection would have the largest impact. Looking at the code, it makes sense that interface based development has a larger impact on coupling. When you change from coding to concretions to coding to interfaces you are telling your consuming code that it doesn’t care what the implementation of that object is, but instead just what it’s contract with you is. Immediately I can create another class that implements the same interface as is currently being used, change one line of code (for that one instance of use only) and, voila, I have new functionality. Although the class using that implementation has to know how to create the implementation, it still is decoupled through the rest of it’s use.
On the other hand Dependency Injection only provides the class with what it needs to use. As far as coupling is concerned, all you have done is remove the “newing-up” of the object and passed it in instead. This is an important part of decreasing the coupling, but the overall impact on the code is limited. Instead of having one “new Customer()” statement every time you need a Customer object, it will be created in on central location. Comparing the impact provided by the centralization of object initialization with the impact provided by coding to an interface and I believe that coding to an interface is far more reaching.
Probably the biggest thing that I’ve thought about since my experience with refactoring to IoC, is that Dependency Injection, SRP and coding to interfaces all are inextricably linked. Without interfaced based code, it becomes very difficult to see any decoupling benefit from Dependency Injection. Without adherence to SRP it is very difficult to practice good Dependency Injection. That has led me to formulate the thought that Dependency Injection actually acts as a pattern and practice aggregator.
If you want to implement Dependency Injection well, you are going to have to also begin practicing SRP and interfaced based development. Dependency Injection, by itself, isn’t a silver bullet for creating loosely coupled applications. Neither are coding to an interface or SRP. Dependency Injection will, however, force you to take a long look at why your code exists as it does. It will be a catalyst for you to move to begin implementing better OO practices as you work towards making Dependency Injection work smoother and more powerfully for you.