views:

93

answers:

4

I consider myself an experienced programmer and understand the basic concept of dependency injection. On the other hand, most of my experience is in writing relatively low-level, one-man number crunching code. I have no experience whatsoever working on large enterprise projects.

Given this background, I can't for the life of me wrap my head around why anyone would need a framework to do dependency injection. Can someone give me a brief overview of how such a framework works, without getting into lots of specifics, and explain how it makes life easier than just rolling your own?

Edit: I've gotten some great answers here. Am I correct in saying that a DI framework basically gives you a convenient way to create globally accessible factories that create/return instances of dependencies whenever an object requests them? If so, I've been doing stuff like this in very ad-hoc ways in my code all along, but never thought to use any kind of formal/heavyweight framework for it.

+3  A: 

Wikipedia has a good writeup on benefits and implementations.

http://en.wikipedia.org/wiki/Inversion_of_control

I find IoC containers like Spring to be helpful because of all the other "stuff" they do, like transaction management, and the code they provide, like code templates, testing base classes, etc, which are eminently useful. Also, in the Java world I think IoC is a reaction to a JEE standard that many developers found too clunky. IoC, as it has been implemented by Spring, lets you design POJO service components, for the most part, which I guess is easier than the hoops that JEE made people jump through.

I lot of it, or at least some of it, is mental masturbation, to a degree, meaning the IoC advantages provided by the containers aren't fully utilized in most projects that use them.
"We should use DI because we'll be able to easily swap implementations of our DAOs in the future, yippeeeeee" -- it rarely happens in my experience. People use them because they have become a standard, and buzzword IMHO. Im not saying thats a bad things; just that the IoC part of the standard software isn't really the reason they are used.

hvgotcodes
+2  A: 

I really like @hvgotcodes answer, but thought id add a few points, as im a big fan of DI/IoC.

We use DI, for the following advantages:

  1. Testability. We write unit-tests against a Repository (for example), via interfaces. Now, for integration testing, we use DI to inject a "real" Repository for our tests. But what about unit-testing? We don't want to test the "real" Repository/database. So we use DI to "inject" a mock repository. A lot of this has to do with the magic of interfaces (of course you could 'hard-code' your tests to use the fake repository when needed).

  2. Central point of injection. - AKA Registry. Each project/module has a Registry where we flick on/off components. For example, in our test project, when "something" requests an IRepository, we inject a MockRepository. In our service layer project, when "something" requests an IRepository, we inject a EntityFrameworkRepository.

  3. Excellent Scope Management. This depends on the DI container (we use StructureMap for .NET). But you can setup your objects to have Singleton, HTTP-Context, ThreadLocal lifetimes in a single-line when you setup your Registry. This again is nice because you handle the objects in a central place. Your components have no idea of their lifetime, they can focus on their job at hand and nothing else.

  4. One-line toggling of components. This is made possible by the registry (point #2). But at the moment we are using Entity Framework for persistence. The only thing that "knows" about this is the Registry. So if one day something better comes out, all we need to do is create another implementation of IRepository, and flick over one line in the Registry. This is very possible in long-life applications. We used L2SQL for v1 of our website, now we are using EF for v2. If we used DI with v1, the time to cutover would almost be halved. But everything is tied to the persistence layer, so we're basically rewriting the website from scratch.

The benefits of DI/IoC are really seen when you combine a lot of different principles such as Repository, POCO's, DDD, Interfaces, N-Tier.

I wouldn't be using it for a small application that is unlikely to evolve.

That's my two cents.

RPM1984
Items 1 and 4 are a function of dependency injection, not of containers, which is what the OP is asking about.
Mauricio Scheffer
@Mauricio Scheffer - a related topic, don't you think? I see the question about Dependency Injection, not just "why are DI containers good".
RPM1984
A: 

If you start down the DI route, you'll pretty soon have constrictors that take 20 parameters for the various dependencies that object needs. Getting those 20 parameters will require getting 20 other parameters to construct them. And, then, at the end (beginning?) of it all, you'll realize that you just coupled yourself to a concrete implementation of your carefully considered interface (by calling the constructor). And then, 6 months later, you'll add a new dependency, which requires you to backtrack through all existing calls and change them as well.

A DI framework basically takes care of that plumbing for you. By standing between you and the constructor, it can interrogate config (maybe XML, maybe code) that tells it what to do when it needs a concrete object.

The basics are pretty easy with any language that has some sort of introspection (register a concrete type to satisfy an interface, when you need an instance of an interface then instantiate the type. Walk the graph created by the constructor and repeat.) where it gets complicated is when you also want to control object lifetimes (this Logger class should only be instantiated once, and then reused. This DataAccessFacade should be instantiated once per thread, etc.) or dynamically choose how to satisfy a dependency. A DI framework will normally provide both object creation facilities (figure out the dependencies required for the constructor) as well as a Service Locator facility so that not everything has to be passed in the constructor or as a parameter to methods. That allows you to register types with arbitrarily complex constructors, get an instance of it, and not have to worry about when or how to share an instance, when its constructed, when its destroyed, or be coupled to the actual type.

Desiging libraries using DI also allows users to swap out dependencies when needed - which gives a great deal of flexibility when combined with interfaces or inheritance without otherwise cluttering your code with constructor or method arguments for every dependency.

Mark Brackett
@mark, have you ever actually seen an implementation swapped out?
hvgotcodes
@hvgotcodes - Sure. The obvious ones are for testing, or maybe logging. Hardware facades, data access, 2-tier to 3-tier components, etc. I don't mean to imply that you can insulate yourself from or design for all future eventualities - but you can certainly ease the pain.
Mark Brackett
+2  A: 

DI is all about decoupling dependencies between classes.

With DI you're classes no longer have references to implementing classes. The factory pattern comes close to DI, but it’s different because a factory class is it selves a unwanted dependency (that for example will hurt unit testing).

DI is also not necessarily a global or application wide affair; it’s possible to configure different dependency schema’s for the same application and the same classes. There can even be runtime dependencies. DI can even determine the lifecycle or scope in which objects need to live (request scope, session scope, etc.).

It also not heavy weight or intrusive either if you look at lightweight DI implementations like Google’s Guice. It’s not for nothing they call it the new “new”.

Kdeveloper
I'm accepting this because it does answer my question. However I searched and read a little about Guice and I'm still skeptical about whether configuring it is really any easier or less brittle than just writing a few factory functions/classes and/or having a few configuration flags stored in the appropriate way for what you're trying to accomplish.
dsimcha
I see it as an improvement of those patterns, as it also solves the depency on the factory classes. It's also less coding, with a simple annotation you create whole factories. Thus less bugs.
Kdeveloper
@Kdeveloper: The more I think about it, the more I think a DI framework could be convenient. It's something I would use if it were in the standard lib, and would make life marginally easier, but not something I'd mess with 3rd party dependencies for. My primary language is D, I'm a developer for its standard library, and D's metaprogramming facilities are pretty good, so I'm halfway thinking of writing a very simple, lightweight (as in, one module) DI framework for inclusion in the D standard lib.
dsimcha
Then you might want to take a look at JSR299 and JSR300 as these describe the DI standardization in Java (DI is now part of the Java EE 6 API).
Kdeveloper