Dependency injection frameworks add confusion
Manual DI vs. Frameworks
- Many agree with the article’s stance: start with manual DI (explicit construction at the top level) and only adopt a framework if real pain appears.
- Critics say reflection/magic-based frameworks obscure wiring: object graphs become implicit, control flow is hidden, and you lose a “single place” to see how the system is assembled.
- Some report real bugs caused by test DI configuration diverging from production, or by complex lifecycle rules (e.g., Spring/ASP.NET Core quirks like
@Lazyand config injection). - Others argue DI frameworks are just automating object construction; you can get most benefits with straightforward code that wires dependencies in
mainor equivalent.
Language Ecosystems and Culture
- In Go, DI containers are rare; people hand-wire dependencies or use global-ish configuration, and many see this as simpler and sufficient.
- In Java and .NET, DI frameworks (Spring, Guice, Dagger, ASP.NET Core, Autofac, etc.) are mainstream. Some call Spring a “cancer”; others note it’s both extremely popular and a major improvement over pre-Spring Java.
- Dynamic or monkey‑patch‑friendly languages (Python, JS/TS) often solve testability via module mocking rather than DI containers, reducing perceived need for frameworks.
Testability, Design, and Trade-offs
- Pro-DI voices emphasize:
- Easier unit testing via injected clocks, DB handles, etc.
- Separation of “glue code” from business logic.
- Managing lifecycles (singletons, per-request objects), cross-cutting concerns, and reducing tight coupling/statics.
- Coding to interfaces and enabling multiple implementations.
- Skeptics counter:
- Manual DI or simple factory/static
create()methods often suffice. - If wiring becomes painful, it may indicate an overgrown dependency graph that should be simplified, not hidden behind a container.
- For small services and microservices, DI frameworks can be net harmful noise.
- Manual DI or simple factory/static
Tooling, Navigation, and “Magic”
- A major complaint: DI frameworks break straightforward navigation and “grepability” (which implementation of
Foois this? where is it constructed?). - Supporters respond that modern IDEs (IntelliJ, Rider, VS, Android Studio) model DI graphs, show which implementation is injected, and even visualize bean graphs.
- Critics argue relying on advanced IDE features is risky (e.g., debugging production at 3 a.m.) and that code should remain understandable with minimal tooling.
Terminology and Conceptual Confusion
- Several note confusion between dependency injection, dependency inversion, and IoC.
- Many see “dependency injection” as an intimidating or misleading label for “pass your dependencies as parameters,” suggesting alternatives like “dependency parameters.”
- Some characterize DI frameworks as glorified global variables or service locators; others insist the value lies in explicit, testable wiring rather than runtime magic.