BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Does Dependency Injection pay off?

Does Dependency Injection pay off?

This item in japanese

There has been an interesting discussion in the blogosphere about the benefits or lack of benefits from using dependency injection (DI).

The discussion started with Jacob Proffitt writing a blogpost where he explains that in his opinion, dependency injection doesn’t scale well. According to Proffitt, the only reason DI is popular is because of mocking.

The real reason that DI has become so popular lately, however, has nothing to do with orthogonality, encapsulation, or other “purely” architectural concerns. The real reason that so many developers are using DI is to facilitate Unit Testing using mock objects. Talk around it all you want to, but this is the factor that actually convinces bright developers to prefer DI over simpler implementations.

Proffitt goes as far as claiming that DI is only good for unit testing:

I do wish that people would admit that DI doesn’t have compelling applicability outside of Unit Testing, however.

However, Proffitt does use unit testing, but without DI. He is using a the TypeMock framework, which is able to intercept calls to dependencies even if they are created inside the code under test. This means that Proffitt doesn’t have to decouple his objects to be able to create mocks for his unit tests.

Ayende, the creator of RhinoMocks, responds in his blog:

While the ability to easily mock the code is a nice property, it is almost a side benefit to the main benefits, which is getting low coupling between our objects. I get to modify my data access code without having to touch the salary calculation engine, that is the major benefit I get.

Nate Kohari also answered to Proffitt’s initial post. After showing a DI code example, Kohari elaborates on what DI really is:

If you’re a GoF fan, this is actually the Strategy pattern. Dependency injection (in my perspective) is basically the Strategy pattern used en masse.

Kohari is the creator of the NInject DI framework, and he pushes the usefulness of DI frameworks:

Once you start writing code that relies on a DI framework, the cost required to wire objects together falls to next to zero. As a consequence, hitting the goal of Single Responsibility becomes exponentially simpler.

In a later post, Kohari responds to Proffitt’s original claim that DI does not scale, by restating the importance of using a framework:

In real-world scenarios, dependency injection by hand simply does not scale.

Proffitt does not agree:

How can you say that dependency injection (I’m not taking on the whole inversion of control pattern, but I might. Jury’s still out on that one.) creates loosely coupled units that can be reused easily when the whole point of DI is to require the caller to provide the callee’s needs? That’s an increase in coupling by any reasonable assessment. Dumping the coupling workload onto a framework doesn’t change the fact that it’s still a requirement to supply external stuff to use an object.

Kohari explains that in most cases, in his configuration he only needs to set up how to create and inject a certain type of object once and that it is not done by the caller but by the framework.

Kohari also talks about changeability of the code:

… simply put, dependency injection makes your code easier to change. That’s why it’s so popular in Agile crowds, whose whole software development practice is geared around quick alterations in path.

Eli Lopian, CTO of the company that created TypeMock, enters the debate with a few argument that defines the core of the debate:

When you use DI as a ’Silver Bullet’ you are losing more then half the abilities of your programming language. You can not use static methods or the ‘new‘ keyword or sealed types. Oh, you have to make all your methods virtual too.

He also argues that using DI just to enable change violates the YAGNI principle.

Lopian continues:

One of the first issues that was discussed when TDD was starting was: “should we change our code to make it testable?” Should we change the visibility of our code? Should we change the design of our code? This lead to a collision between testable code and OO encapsulation. Developers started to expose private parts of the code to enable testing. It started with private fields and methods and now it is the complete design.

This is the classic part of the discussion. Some people argue that changing the code to make it more testable is a good thing, others argue that breaking encapsulation for that reason is a bad thing.

Kohari’s take on encapsulation and dependencies is:

Here’s the secret that makes dependency injection worthwhile: when it comes to dependencies, encapsulation is bad.

If changes made for unit testing purposes leads to looser coupling (which itself is questioned by Proffitt) - is this a good thing or not?

Both loose coupling and encapsulation are valued OO properties, but how shall we handle the balance? Which is the right path?

Rate this Article

Adoption
Style

BT