Dependency Injection: A Challenge to Conventional Thinking

Cover image

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.

Dependency injection's rise in popularity can be traced to influential members of the software development community, such Uncle Bob, who advocated it. It is important to remember, however, that it evolved from a strict object-oriented programming context and it may not be the best choice for dynamic languages such as Python and JavaScript.

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.

In conclusion, while dependency injection is a valuable pattern in some contexts, it is important to challenge conventional thinking and carefully consider if it is the best option for your project. There might be better options for dynamic languages like Python and JavaScript that offer dependency injection's advantages without its disadvantages. It is important to weigh the pros and cons before adopting this pattern, and to not blindly follow the norm without considering its potential drawbacks.