I think Inversion of Control (and Dependency Injection, basically the only decent way to do IoC in OO languages) is a great idea. We do it all over our Izooble codebase, for example: it enables testability and encourages us to keep independent things separated. I believe that Dependency Injection is one of the few good design patterns that still make sense in modern OO languages. I suspect that it, too, will at some point be superseded by a programming language designer’s great idea, but right now I can’t imagine what that would be.
What I do think is wildly overrated, is IoC containers. I don’t see their added value over explicitly injecting a dependency into a class’s constructor. It’s the singleton antipattern in disguise, and with an IoC container it’s very difficult to see what is going on, because, magic. It’s even worse when the IoC container is configurable with something other than code (e.g. Spring.NET’s horrible, horrible, horrible XML abomination), because that actively encourages messing around with live servers* instead of fixing your damn deployment pipeline.
If you avoid IoC containers, you’ll typically end up with a
Main method that instantiates a whole bunch of objects and passes them to other objects again. That
Main method is an excellent summary for your entire application’s architecture. You can see how all the important components are tied together at a single glance.
Now, when your application grows, when you do this, two things tend to happen:
- Some class constructors, those high in the composition hierarchy, may need a very large amount of injected constructor parameters, just to pass them through to a class way down the tree. Well that’s cumbersome.
Mainmethod becomes a ginormous 100-line list of
Somehow, people take this as a sign that they need an IoC container, so they can hide the monolithic, highly coupled contraption they inevitably grew their application into.
The real solution, of course, is to fix the architecture. Split the application into multiple independent components that only have few dependencies on each other. In fact, you can use a nearby whiteboard to trivially turn your
Main method into a tree diagram so you can see how to best cut your application into pieces. Maybe you’ll need to reverse some dependency arrows here and there (events to the rescue – or Observer if it’s 2002 and all you have is Java). You’ll end up with a bunch of independent parts, with the old content of
Main spread across constructors of Facade-style entry point classes in these parts. Congratulations, you just forced yourself to fix your architecture by stubbornly avoiding IoC containers.
I really don’t understand why some programmers insist on hiding their bad designs from their own view. It’s like they don’t want to know that things are becoming a mess. IoC containers are to architecture what .NET regions are to classes.
* Or robots, or machines, or whatever your software runs on.