Monday, 10 October 2011

The Benefits Of Dependency Injection

Dependency Injection is the way to go, so say the Guys at Spring, and who am I to argue with them, after all it sounds like a sensible idea. But, how many developers have ever stopped to figure out why? If I ever interview you for a job one of the things I ask is “explain the benefits of dependency injection”. I should also explain that in my interviews, there’s often no right answer and that it’s your opinion that I’m interested in. Still, in asking the question you get a lot of blank faces. Those who know what dependency injection is will often define it, telling me that using Dependency Injection means that you design some interfaces and write some implementation classes. They then add that Spring instantiates their classes and connects them together via their interfaces and an ApplicationContext. In response to this I usually ask why would you want to use interfaces and usually get the reply that you can replace one class implementation with another in your application. I then ask how many implementations do you usually have for any given interface, to which the answer is normally... one... to which I ask “what about testing?”. The penny seems to drop a little at this point and the prospective candidate then talks about stubs or mocks, though sometimes confusing the two (see Martin Fowler’s Article on Mocks aren’t Stubs for more information on this) and sometimes not knowing what they’re called. They realize that injecting mocks and stubs into your classes when testing means that you’re using alternative implementations of your interfaces and this is something you do everyday. The candidate then quickly mentally revises their estimation of the number of interface implementations up to two. We then talk about testing, arriving at the conclusion that tests are good and concluding that using dependency injection means that your code is more testable and therefore of better quality.

Having written all this, I did a little research to see what other writers think and they proffer additional dependency injection benefits, such as reduction of boiler plate code (wikipedia) and improved production maintenance (StackOverflow) and More Reusable Code (from Jenkov’s Tutorials), but for me it all really comes down to testing.

Good tests = fewer bugs = good code = easy life...

Finally, just in case I sound rather smug about all this, when I first though if this as an interview question, I did have a rather blank face for a few moments before I came up with an answer.

8 comments:

Anonymous said...

DI copes the wiring of static dependencies. And preferrably it does this via Constructor Injection.

This brings in two issues: First devs regullary mix dynamic dependencies (i.e. sth. like a Tx) with static dependencies (Statless Service A depending on a stateless Service B).And the other thing is: Is it really so beneficially to get some services injected vs. retrieving those frome some service provider?

I don't think you write less boilercode with DI. I'd rather say, unless you fragment you solution into hundreds of individual & stateless services, you even write more boilercode and esp. much more complexity compared to a simple ServiceFactory which simply readss: ServiceProvider.get(ServiceInterface.class).doServiceA().

The last pro-DI resort would: "It helps desigining better software". Frankly meanwhile I do think: None at all!

Good software means loose coupling via interfaces. Isolatable units which can be unit tested. Clear, simple and eady design and architecture contracts. I've seen to much really grave design error provoced by the developers idea that DI will "magically" know and do the right thing and rather places where I'd the impression DI helped to achieve a better software design.

Santiago Lezica said...

I'm with Anonymous here, I never saw real benefits to DI.

The idea of communicating objects through public interfaces and exchanging backing implementations is older than DI, and perfectly plausible without it.

The amount of code you write is roughly the same, or more for DI frameworks that need heavy configuration, only now the actual logic that drives instantiation is hidden from sight. I'd much rather have a plain-old factory for the classes that I actually plan on interchanging, and put that logic where it belongs -- right were the next programmer to read my code will need it to know what's happening.

Yeah, DI feels automatic and magical, but magical also means mysterious, and I don't like my code being mysterious.

Anonymous said...

There are no benefits to DI.

There are no design advantages to using DI.

The belief that "it is ok to partially construct objects" and spring will sort it out later on is complete bullshit.

This allows programmers (especially the weaker ones) to write code without first thinking, which ultimately ends up in project disaster.

Don't use DI.

You will find that without DI you will be writing less tests, and therefore, concentrating on getting your job done rather than noncing on about agile practices.

Anonymous said...

I come from PHP and Zend Framework where they use DI to good effect, being able to plug and play aspects of a framework is nice (config files: PHP array, Yaml, Xml, Ini) etc is nice... DI seems to depend on what level you are in the software stack, if you are the glue level then it has it's place

Bill Wixon said...

Santiago,

You do not need a DI framework to do DI. Your use of factories is still DI. DI is just injecting dependencies into a class rather than the class instantiating its own dependencies.

"The idea of communicating objects through public interfaces and exchanging backing implementations is older than DI, and perfectly plausible without it."

That is DI. Just because you don't use an IoC container like Spring doesn't mean you are not doing DI.

Anonymous said...

I used Spring for about 3 years. DI and Spring _can_ be useful for testing, I agree.

Spring as an implementation is far from optimal. I think this is more an artifact of DI/AOP/etc not being natively supported by Java.

I've spent countless hours trying to figure out the xml incantations to get things to work as expected.

Nathan Dolan said...

Wow, a lot of hate for DI here!

I've worked on several projects that wrote their own object configuration factory based on XML and/or annotations (and one I wrote myself). This was in pre-Spring/CDI days, and they served their purpose well. It isn't that hard... at its heart Core Spring doesn't do anything particularly clever; IMHO the real value of Spring is in its vast ecosystem. That to one side, I do think it's pretty hard to argue CoreSpring/DI/IoC doesn't bring any benefits over using new Impl(), even if you don't think they out-weigh the trade-offs (the indirection, arguably greater complexity and the everything-is-a-singleton trap). DI/Spring makes it really easy to wire your app in different ways to support different configurations, which amoungst other things, does have obvious benefits for testability as Roger pointed out. Accepted that's more important to some than others.

As an aside: if peeps have worked on sucky projects that use Spring, don't blame Spring or the DI pattern, blame the architect or the developers. Bad workmen, tools and all that.

What I really want to say though is: don't assume DI/IoC is the end game for achieving proper modularity and all the benefits that brings. You're still coupling interfaces with their implementations, you're just doing it within an XML file or annotations rather than via new Impl(). For that you need a broker, and in this space OSGi is still pretty much the only game in town. Services-First Migration to OSGi was a good passionate talk on this at JavaONE. There were several others.

Roger Hughes said...

A link to this simple, seemingly uncontentious blog was posted on Reddit a few days ago. This generated about 6000 page hits and over 200 comments. It just goes to show that there are as many opinions as programmers; however, the the consensus, with which I agree, seems to be in favour of DI, although I'm promising myself that I'll get around to checking out OSGi - one day.