About the author

Steven Harmansteven harman :: makes sweet software with computers!

For recent posts and more about me, scroll to the bottom.

Subscribe

  • Subscribe to my feed. via RSS
  • Subscribe via email via email

News

Badges

  • Subtext Project
  • Support Subtext

Prefer Dependency Injection to Service Location

There is currently a thread running over in the StructureMap Users mailing list asking if we really need constructor injection when using an Inversion of Control container. Before any one rips off on a rant let me say that I worked with Jon in my former life and I’m fairly certain he’s merely conducting a thought experiment, trying to sure up his own beliefs. A worthwhile exercise, if you ask me.

At any rate, I have a few points I wanted to throw out there; most of them basic and mere reiterations of the words of others… but I’m gong to do it anyhow!

The question at hand

I would encourage you to go read the full thread (it’s a quick read… 4 minutes, tops!), but knowing many of you are lazy like me, I’ll reprint Jon’s original question here.

Again, please go read the full thread so you have the full context.

Whenever I tell people about StructureMap (or using DI in general), I
mention that two of the benefits are that (a) StructureMap will create
objects and all their dependencies for you and (b) it enables you to
fake out the dependencies in a test.

Why do we need constructor injection to do this?  I can call
ObjectFactory.GetInstance() anytime I want and it will work.  And I
could leave SM configured for my tests and call ObjectFactory.Inject()
to stub things out.

So theoretically, I wouldn't even need constructor injection, right?

Let’s get the jargon down

To be clear, Jon proposing using Service Location rather than Dependency Injection.

While Service location is better than poor-man's DI, using it as suggested above is still introducing a high degree of coupling as all of these classes now have an opaque and highly concrete dependency on the container. This is effectively creating a new form of Global. Eww!

The key to using Service Location within new code is to keep it tucked away in the deepest, darkest corners of your infrastructure. For example, if you’re building something on the asp.net mvc stack, you might use Service Location within a custom IControllerFactory to create each of your controllers.

If you’re dealing with legacy code, full of concrete dependencies, you might use Service Location as technique for teasing things apart with a goal of decreased hard coupling. In the end this may result in wholesale replacement of some modules.

When it comes to Dependency Injection and dependencies in general, I agree with Scott Bellware's point of view; make your dependencies explicit & transparent by requiring them in the constructor. My gut reaction is also to avoid translucent (setter-injected) dependencies as they make it harder to tell what dependencies an object will need to do its job – the shape of the object isn’t as clear as with explicit constructor dependencies.

Feeling the friction

I tend to be lazy and prefer to feel friction of poor design early so I can change direction quickly. For example, when a constructor gets too large it's a signal to stop and consider Single Responsibility Principle, Separation of Concerns, etc. In a similar vein, I don’t usually advocate use of an auto-mocking container. Or at least not for folks who’ve not yet acquired a strong nose for design and simplicity; the friction helps keep you on the rails.

Later in the tread Jon mentions some friction he’s been feeling when setting up the context of his tests (or specs). Namely he’s having to set up and inject a lot of concrete objects for interaction within his unit tests.  To me this is an indication that those tests may actually be integration tests. After all, they are flexing the integration of a several modules in concert, right?

I say, call them what they are, fire up the fully configured container, and move on.

I prefer to make the implicit explicit, to be able easily see the shape of an object, and in getting forced feedback when my design starts to slip off the rails.

What others are saying.

# re: Prefer Dependency Injection to Service Location
Gravatar Jon Kruger
Sep 25, 2009
Good post. You're right about service location creating tight coupling with the container. From an academic perspective, I agree with you, and if you create that tight coupling, no one could use your code without a DI container and you would have to have the DI container wired up in the unit tests.

But on most of my projects, I'm always going to have a DI container, and I'm probably always going to have the same DI container (although I could put Common Service Locator in to protect against that). So that makes the tight coupling with the container less bad. The other thing is that I have to have the container wired up in the unit tests now, which I think might provide some benefits (I'm doing this now to a limited extent and it's really made that portion of the code easier to use and test).

I asked on twitter and some people said that they have their container wired up in their tests. I've never tried it before on an entire project. It would probably be cool in some ways, but I wonder if there would be other kinds of pain (for example, now everything by default is wired up to use the real concrete classes instead of stubs).

I guess the tight coupling seems less bad if I'm tightly coupled to something that I can inject stubs into. If I do the usual tight coupling sins (newing up objects), I can't stub it, so I can't test. I feel like I could do service location and still have it be totally testable.

I don't know, it's just an idea. In my head, it seems like it would work and that it would be cool. But then again, I haven't tried it so there might be pain out there that I'm not thinking about.

If I find time (there's a lot of stuff in the queue), maybe I'll make a sample project of what I'm thinking. I think some of the benefits might make it worth it, but we'll see.
# re: Prefer Dependency Injection to Service Location
Gravatar José F. Romaniello
Sep 25, 2009
I prefer dependency injection over service location. And I prefer in some case to inject an IServiceLocator via constructor instead of using the static SerrviceLocator.DonnoWhat.Current.

Look this factory:
http://digg.com/u1D7xY
# re: Prefer Dependency Injection to Service Location
Gravatar José F. Romaniello
Sep 25, 2009
Another point "If the constructor get too long" sometimes you can simply put a factory.
If your Service depends on three DAO, when you need to add another dao, you will need to change all the tests.
Instead that put a IDaoFactory.
# re: Prefer Dependency Injection to Service Location
Gravatar Caleb Jenkins
Sep 28, 2009
Great write up Steve. I've been a fan of constructor injections for a long time now. Much cleaner and explicit about exactly what your dependencies are and what you are trying to accomplish.

Even when I am using a service locator, I always prefer to (1) wrap the IoC/DI container in my application's own wrapper (ie. IFactory) to reduce my coupling to the DI, and (2) push it way down in a concrete class.

It's tempting to start putting IFactory in every constructor and then moving on, but like you said, that makes it much harder to read the class and discern it's actual dependencies and function... and makes testing a huge pain.
Comments have been closed on this topic.