Inversion of Control (IoC) is a very good idea.
But as the clever Joel Spolsky noted, sometimes you need to be a super-natural hero to use it:
I try not to be judgemental (HAHA!), but I think that people who use IoC containers are (A) very smart and (B) lacking in empathy for people who aren’t as smart as they are. Everything makes perfect sense to them, so they have trouble understanding that many ordinary programmers will find the concepts confusing. It’s the curse of knowledge. The people who understand IoC containers have trouble believing that there are people who don’t understand it.
I have trouble using Spring in at least two projects. On the third, it was a disaster, because a single software-architect-guy keeps passing around the Spring context factory as method parameter, getting beans from it!
On .NET I ended up using the Enterprise Library by Microsoft for Logging and some small orchestration, which still did not pay its bill.
An IoC like Spring could be a good idea if you need to integrate a well written legacy system. Spring could glue together simple POJOs and let you the freedom to reorganize the architecture. But your legacy is often a mess if it is old and had a lot of casual patcher. It is not legacy code fault: “it is its destiny, young Luke” (like in StarWars)
As Joel Spolsky point out on the same thread:
The most valuable benefit of using an IoC container is that you can have a configuration switch [..]. For example, suppose you have two versions of your database access classes… one version which logged aggressively and did a lot of validation, which you used during development, and another version without logging or validation that was screamingly fast for production.
On the other hand, this is a fairly trivial problem easily handled in a simpler way without the complexity of IoC containers.
And here your IoC will fail.
From my point of view, if your target is a “clean architecture”, IoC container is not the solution, is your enemy.
So what?… We could start over from a random architecture, and find a way to make it better.
A very easy way to check your architecture is trying to write unit tests on it. For instance if class “Card Deck” has a “shuffle()” method, you must be able to create a Card Deck of predefined size (i.e. 5 cards 1,2,3,4,5), call shuffle and verify in an easy way the result(i.d. 1,4,2,5,3)
You must be able to do it without instantiating the entire project classes, and the test must be very clean to read.
If you cannot do it, you must add layers between classes, restructure them, until you get an easy way to do it.
Then reiterate this step for all the core classes of your project.
Last but not least: a good architecture could be “lazy” on not-so-core classes (it is a matter of economy: very well designed things cost too much in real world).
In all this picture IoC is a useful tool, not a framework. It like saying your bytecode is an architecture. The bytecode is a technology to achieve something! You will never ever use it directly in your day-by-day work!
What I save from IoC is the Hollywood Principle, which is the real added value of an IoC container. And you know the funny part? Hollywood principle could be used even without OOP!
But every time I have managed to teach it, I found it a bit difficult to understand.
Then I found this great explanation on Stack Overflow and I remanaged it:
When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.
What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.
On the programming side, please forget for a bit objects, methods and so on. Come back to an easy functional-language like C, to an operating system basic feature: interrupts!
What is an hardware interrupt? It calls you when an event occur. If it is well done, the interrupt will call you in a regular, controlled way, managing errors or other external troubles. It will encapsulate the complex need “Call me when something occur”.
Call me when a very beautiful girl (or an handsome bold man if you are a girl) is walking out the street in front on my house… and please avoid to call me if it is raining, or if it is too late.
Functional programming revival is mostly due to the possibility to define lambda functions and/or closure to express this needs and develop them in a robust and typed way.
WordPress plugin architecture is done mostly by callbacks and filters, and it works so great you have more than 14.000 plugin out of there. So it scales pretty well, isn’t it?