I read the article on InfoQ about the various blog posts that have been going back forth concerning the pros and cons of Dependency Injection (DI).
A very interesting read for certain. I think there are excellent points made on both sides. Ultimately, there are pluses and minuses to all software architecture decisions. I believe that if someone doesn’t think that tradeoffs exist in their architecture, they likely do not understand software architecture very well.
Jacob Profit argues that DI has grown in popularity largely because it helps with Test Driven Development (TDD). Certainly, DI helps dramatically in this area and it likely is a good reason for the popularity surge. However, I don’t really agree with his assessment of how the caller becomes responsible for configuration of dependencies when implementing DI. Well, let me restate that to: It can be that way but it certainly doesn’t have to be and I highly recommend against it.
First, using a framework makes things much easier. The choice of framework makes a difference. DI frameworks come in 2 basic flavors: file based configuration and code based configuration. A few support both configuration methods but most fall into one category or the other. In the file based configuration camp, Spring.net is my favorite but there are other excellent choices like Windsor and StructureMap. ObjectBuilder from the MS Patterns and Practices group is an example of a code based configuration DI framework.
In my opinion, a code based configuration DI framework can lead you down the path the Jacob Profit mentioned – making configuration of dependencies the responsibility of the caller.
Just like Oren, I like DI because it makes it easier to create a loosely coupled software architecture. When I use Spring.net, I get the added bonus of the ability to abstract away the location of my components when I use the proxy factories. With Spring.net proxy factories, a dependency could be a local, in process, object instance or a proxy to a remoting object, web service, or enterprise service. The product will soon support WCF as well. This helps me develop and test in an all local configuration and move to a more distributed model after I am sure the core logic works locally in process.
Eli Lopian entered the discussion on the negative side of DI but made some statements that I think are a little misleading:
When you use DI as a ’Silver Bullet’ you are losing more then half the abilities of your programming language. You can not use static methods or the ‘new‘ keyword or sealed types. Oh, you have to make all your methods virtual too. This is going to be even harder once Extension Methods (and Linq) become main stream.
I will concede the static keyword argument. It is difficult to handle static methods in DI frameworks.
The new keyword seems to me to be by design rather than a negative side effect. DI frameworks create and configure dependencies for an object. Therefore, the need to call new is removed.
It is possible Eli was referring to the need for later dependency creation rather than creating all dependencies at startup. I can see this being a requirement. In fact, I have had the requirement myself and I solved it by having the object request the dependency from the Spring.net context rather than having the dependency injected. I realize this is not ideal, but no worse than coupling to a concrete implementation or factory in my opinion.
Eli also says that you cannot use sealed types and all methods must be made virtual. This is where Eli and I start to part ways.
I have used both sealed types in my Spring.net configuration and have used objects without virtual methods. In fact, most of my objects do not have virtual methods. Whether or not to make a class sealed and make methods virtual is a design decision that has nothing to do with the use of a DI container. I make sure to retain the flexibility of the caller by enforcing the use of the interface/implementation paradigm in my designs. This way I can divorce my decisions about inheritability from the flexibility I want in the caller’s code. I agree that you probably want to avoid sealed classes and make methods virtual, if the caller is declaring concrete class variables instead of interfaces. However, interfaces are the way to go in my opinion. In fact, using interfaces for variable declaration types is a good idea in many cases even if a DI container is not used at all.
I might be missing the point but the last sentence in the quote from Eli Lopian does not make since to me at all. Using extension methods is perfectly ok with DI containers. I have even attached a very simple sample project to this post demonstrating both calling extension methods from an object returned from the Spring.net context, and calling extension methods on a property injected within the container. I fail to see why LINQ would be a big issue either. The types of objects I would be performing LINQ queries on would likely be value objects that I use for my problem domain. These would not be something I would normally configure in a DI container anyway.
By the way, I am already working on a post describing Extension Methods in general and I should be posting that either tomorrow or Monday.