That was the question that I got asked about a month ago. My response was "something in the middle". I like Dependency Injection. It facilitates testing, it facilitates change, and it facilitates clean design.
I have been thinking about container assisted dependency injection lately and have been playing around with PicoContainer. I've been trying to justify the use of PicoContainer to facilitate dependency injection versus just injecting dependencies manually. My primary aim was to facilitate testing and good design, so the manual passing of dependencies was sufficient, but there was this nagging voice in my head telling me that the design would be more open to change if the rigidity of the dependency injections was placed in just one spot. However, I couldn't quite articulate that idea and had just left it hanging for a little while.
Enter Mr Oberg.
Rickard Oberg is a very smart guy that I first found out about when he did an interview on TheServerSide.com back in 2001 when he was a core architect and developer on the JBoss (then version 2.0) J2EE server. Rickard has made some great posts on his blog over the past year that have helped me better understand Aspect Oriented Programming (I'm watching the development of Spring.Net with some interest) and the value it can bring to software development.
Rickard just made a great post on "Dependency injection and open vs. closed designs" that has helped bring clarity to my thoughts on dependency injection and design. Go read his post for the full story, but I had a number of 'oh yeah' moments while I read this part:
So, is an "open design preferable to a "closed" design? Well, I like to compare this to house building. Using a "closed" design is like building a house where the rooms have no doors. Whenever you decide that there needs to be a door between two rooms you punch out the wall and insert a door. It's not something you would do easily. On the other hand, using an entirely "open" design is like building a house where the rooms have no walls, only doors. This makes for great flexibility, but don't be surprised if the roof comes crashing down. The conclusion of this analogy is that you'd probably want both: the rigidity of walls combined with the flexibility of doors. In Pico terms, the foundation of the house is provided by the Container, while the rigidity is provided by a ContainerComposer. The composer is the place where all decisions are made, and essentially it has to know about all the things that Foo knew in the "closed" design version: whether Bar is a class or interface, how to instantiate Bar, and what parameters to provide to it. If you let it do this for all components in the system, then all of our assumptions have been put into one place, and if any assumption would be wrong, that is the only place which would be affected by it.
Dependency injection = 'open'. Specific injection decisions = 'closed'. Pico + ContainerComposer = isolate the 'closed' parts in one 'easy to maintain' place. Biggest value of a Dependency Injection container = maintainability.