Dependency Injection: A Challenge to Conventional Thinking
Dependency injection is a common pattern in software development, especially in object-oriented programming languages such as Java and C#. This pattern arose in response to these languages' limitations in expressing dynamic and flexible relationships between objects, and it is considered a way to achieve modularity, testability, and loose coupling. However, it is critical to question conventional wisdom and reconsider whether this pattern is beneficial to you and your project, as it has numerous drawbacks that are frequently overlooked.
While dependency injection has numerous advantages, it also has many drawbacks. One of the main issues is that it increases the cognitive load when reading code, as you have to assemble what the code will look like when it is running. This makes it harder to reason about and understand, and can also break your IDE, auto-complete, and go-to definition functionality. Besides that, it violates the black box principle because outside code is now responsible for a black box's "dependencies," making it less reusable.
Traditional dependency importing, on the other hand, does not have any of the drawbacks of dependency injection and greatly simplifies and clarifies the code. Additionally, even without relying on dependency injection, you may still enjoy all the advantages of it, including testability, modularity, and separation of concerns. For example, you can use build-time dependency replacement, rewrite import paths, or aliased dependencies to make tests even easier than dependency injection, while avoiding its drawbacks.