Decoupling Your Application From Your Dependency Injection Framework
Dependency Injection has become a much more accepted and accessible approach in recent years, driven by many factors including increased popularity in SOA, TDD, and many other factors. With this has come increased usage of Dependency Injection frameworks, highlighted by its recent inclusion in Java EE 6. Bob Martin advises, with examples, applying a decoupling approach between your application code and your Dependency Injection framework of choice.
In his Dependency Injection Inversion article, [Uncle Bob] Martin presents a message that boils down to this simple statement, in his words:
... I don’t want [Dependency Injection] framework code smeared all through my application. I want to keep frameworks nicely decoupled and at arms-length from the main body of my code.
To illustrate this point, Martin sets up an example revolving around the creation of BillingService class having the following dependencies defined by its constructor:
public class BillingService {
...
BillingService(CreditCardProcessor processor, TransactionLog transactionLog) {
this.processor = processor;
this.transactionLog = transactionLog;
}
...
}
He first introduces an snippet that uses Guice (Google's Dependency Injection framework) to create an instance of the BillingService class:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
billingService.processCharge(2034, "Bob");
}
After going through some of the details behind what's really happening here (with Guice), Martin picks on the fact that you're now in the position of having to explicitly ask Guice for an injector to create instances of the BillingService. So, code that needs a BillingService no longer has a hard dependency on BillingService's dependencies (A Good Thing), but it now has a hard dependency on Guice.
Have you just traded one evil for another? Martin says yes:
Dependency Injection is just a special case of Dependency Inversion. I think Dependency Inversion is so important that I want to invert the dependencies on Guice! I don’t want lots of concrete Guice dependencies scattered through my code.
Later, he shows how a hand-rolled Factory-like object might be used to control and reduce the application's dependency on the D.I framework:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService.factory = new BillingServiceFactory(injector);
}
...
// Deep in the bowels of my system.
BillingService billingService = BillingService.factory.make();
billingService.processCharge(2034, "Bob");
Going into more detail about why this approach may be useful, Martin says this:
I like this because now all the Guice is in one well understood place. I don’t have Guice all over my application. Rather, I’ve got factories that contain the Guice. Guicey factories that keep the Guice from being smeared all through my application. What’s more, if I wanted to replace Guice with some other DI framework, I know exactly what classes would need to change, and how to change them. So I’ve kept Guice uncoupled from my application.
An interesting point made in clarification is that, in all examples provided, the BillingService itself adheres to the Dependency Injection principle; knowledge about what implementations of the BillingService's dependencies (CreditCardProcessor and TransactionLog) are used is externalized from the BillingService. To illustrate this, he concludes the article showing a JUnit test of the BillingService that uses simple hand-rolled "test doubles" of the TransactionLog and CreditCardProcessor, noting the test will run fine no matter what mechanism the application chooses to inject the dependencies at runtime.
(As a sidenote related to Martin's test doubles and explicit choice to "hand-roll" them, Gary Bernhardt has posted a very interesting article highlighting how this decision may be prudent in Java or other statically-typed languages, but not necessarily in dynamic languages such as Python.)
So, do you use Dependency Injection? Do you use a D.I. framework? If so, or also if not, how does all this resonate with you?
Abstraction is good, abstraction is bad
by
Jim Leonardo
However, let's be cautious. If the abstraction is there only for the sake of abstraction, it can drive you nuts if you are having to work on code originally written by someone else. Some frameworks suffer from this in that you have 5 or 6 levels of interface inheritance before you get to a concrete class and very little documentation in between to tell you how to create any of those concrete instances. Sure we all understand the idea of coding to interfaces, but sooner or later something needs to actually create an object instance. When that gets buried in all of the abstractions, the fun in life can disappear very quickly. It gets a bit like being told all the directions on the freeway, but never getting told where the on ramp is.
I wonder how often he does *coding* for the last couple of years
by
monser corp
Re: I wonder how often he does *coding* for the last couple of years
by
Davy Herben
I haven't looked at Guice, so I can't say if what Bob Martin is showing as an example is the right way to do things there. I would indeed feel reluctant to sprinkle DI framework code all over my code (I find annotations to do the same thing just as bad, btw). Just wondering if this is really needed in the first place. In spring, you could give every class access to the ApplicationContext and let them get the beans they want, but that's not what you want to be doing either...
Re: I wonder how often he does *coding* for the last couple of years
by
Edward Moraru
I've worked with Guice and I had the Guice dependency in a couple of files not by using factories but a context that was accessible in the web layer.
The project used Stripes, Hibernate and Guice. Wonderfully minimalistic.
I don't like the factory per service, maybe it's more flexible that way.
It's a matter of style and taste, I think. To each it's own, then ;)
Educational Content
Intro to CLP with core.logic
Ryan Senior Jun 18, 2013
Spock: A Highly Logical Way To Test
Howard Lewis Ship Jun 18, 2013
Java Garbage Collection Distilled
Martin Thompson Jun 17, 2013
C++11 The Future is Here
Bjarne Stroustrup Jun 16, 2013
The Big Data Revolution
Claudia Perlich Jun 16, 2013




Hello stranger!
You need to Register an InfoQ account or Login to post comments. But there's so much more behind being registered.Get the most out of the InfoQ experience.
Tell us what you think