Dependency Injection and Inversion of Control are great design principles that most capable programmers discovered on their own before they were given names. Having a worthless container instantiate everything via reflection and moving what ought to be compile-time errors into the runtime to enforce that is an unnecessary waste.
Instantiation and teardown aren’t hard, or at any rate they shouldn’t have to be. If you roll this stuff by hand, it can often indicate weak areas of the design -- unnecessarily tedious boilerplate that can be cleaned up.
To me, DI frameworks are usually an example of the tail wagging the dog. You make your code more complex, slower and harder to debug just for the sake of making it more testable. But if you avoid leaning too hard on the framework, it’s usually possible to keep the design clean and get good test coverage. In fact you can often get better test coverage, by using real components rather than being tempted into relying on mocks.
...and some of those Most Capable Programmers helped by letting other reuse what they wrote, in form of IoC/DI frameworks!
Or are you suggesting that every programmer worth their salt should write their own IoC to suit their needs?
See, that's kind of like saying, "the Most Capable Programmers helped by writing a program, are you suggesting that every programmer should write their own program to suit their needs?" I mean, yes... absolutely. I don't think anybody should write a program that parses an XML file, reads class names out of specific attributes, reflectively instantiates them, then reflectively matches up their methods with other class names and then reflectively associates them, not do I think that anybody should write a program that scans annotations to match class types to attributes and instantiate them behind the scenes either. I don't think Rod Johnson should have done that, and I don't think anybody should use it. It's pure overhead with no benefit. I do think that programmers should decouple implementation from interface and program to interfaces and then write a dozen lines of Java code that do, in a type-safe, efficient way what the eight or ten megabytes of Spring "framework" does a bad job of doing "for you" slowly and poorly.
Actually that's what I typically do in Java. There's far too much magic in Spring. Initialization code to read a parameter file and inject values into objects only takes a couple hundred lines. Plus there's huge value in controlling boot and exit sequences directly.
I do the same with object-relational mapping--write a thin layer of classes to wrap INSERT, SELECT, UPDATE, DELETE. Not hard to write, easy to test, and you can always slip into SQL if you run into problems.
Use-case specific code should always be considered as an alternative to general frameworks.
I also don't get the Spring hate and what that has to do with creating "one big function and a few global variables."