2

At what point does dependency injection make sense?

When I first learned about Guice I was really excited. I have a Concurrency module, which is basically just a singleton controlling concurrency. I was looking for a better solution than using a singleton when I remembered DI. I'd never used it before and there's some slight complexities but I thought an example of what I'd be able to do is:

public class SomeClass{

    @Inject
    private ConcurrencyProcessor concProc;

    public void doStuff(){
       concProc.enqueue(whatever);
    }
}

and then to init it I would do something like

void randomMethod(){
    SomeClass sc = new SomeClass();
    sc.doStuff();
}

Thereby allowing me to have the ConcurrencyProcessor object created once, and to ensure that the entire program is running the same object while also reducing code. For creating it I figured it would run something like

The issue I'm having is DI as a programming paradigm seems like a good idea and is something I've already been doing. The way I'd right SomeClass right now if I wasn't using a singleton is:

public class SomeClass{

    public SomeClass(ConcurrencyProcessor concProc){
        this.concProc = concProc;
    }

    private final ConcurrencyProcessor concProc;

}

Which seems like a good idea. It's still decoupling the dependency which is fantastic. My problem with DI frameworks (really just Guice, it's all I've seen) is that it seems like it adds a lot of boiler plate through the bindings and such, and doesn't provide this lower level convenience. I understand if you have a very large program with plenty of inner dependencies it may make sense. But for anything that isn't a large scale operation is something like Guice overkill?

I see how it's worth it in certain systems. This may be a better way to re-phrase the question. How do you know when using DI frameworks is worth it? In a scenario where I'm running multiple different types of payment and such I agree it makes complete sense to use DI frameworks as you can easily plug in different aspects of the program at different points. But for example with my singleton I wanted to change, or in any scenario where there aren't a huge amount of dependencies that can change, is it worth using a DI framework vs. just standard DI design practices?

  • 1
    It looks like you're missing an example following the paragraph that ends "For creating it I figured it would run something like". – Mike Partridge Jun 17 at 13:15
  • 1
    Sorry for nitpicking, but title is misleading. You should ask about DI framework being overkill, not DI. DI wouldn't be overkill even for small project, where instead of framework you can build object graph manually on the entry point of application – Fabio Jun 22 at 20:20
8

Of course. If you have a really small project with 12 classes, then a DI framework is almost certainly overkill.

As a rule of thumb, the point where it becomes truly useful is when you find yourself repeatedly writing code that wires up object graphs with multiple dependencies and have to think about where to put that code.

2

You know it is worth it when the problems you are encountering because you do not have it outweigh the trouble it takes to apply it.

Every decoupling effort, when done afterwards, will be work and a bit of extra plumbing. But it will likely make things easier in the long run. It is up to you to decide if it is worth it, on a case-by-case basis.

Dependency injection as such is often not the ideal solution, it is a practical fix to a problem that, in most cases, could have been avoided. If an object would implement appropriate events, it would not have to know about the injected type at all. Events mean more plumbing still though.

1

Dependency injection itself is not overkill, nor is it complicated. It's just handing a class its dependencies through one or more interfaces as constructor parameters. This allows you to swap out the implementation of the dependency, and all you need is the new keyword.

public class Bird : Animal
{
    ICanFly flight;

    public Bird(ICanFly flight)
    {
         this.flight = flight;
    }

    public void Takeoff()
    {
        flight.Fly()
    }
}

public Bird bird = new Bird(new Wings()); // Wings has an implementation of ICanFly.

bird.Takeoff();

It's the DI frameworks and IoC containers that sometimes seem like they're overblown, not inversion of control per se.

Take my favorite container DryIoC as an example. This container has a huge list of features and employs some very sophisticated code techniques to make it as fast as possible.

Do you need all that? Maybe not. But the purpose of IoC containers is to provide a feature set, stability and speed that pretty much guarantees that you'll never need anything else, including the new keyword.

Here's what I can do with dependency injection using DryIoC and Prism. I can create a View and ViewModel, wire it up in the bootstrapper using this:

catalog.Register<MyModule>();

In my module, I wire up the ViewModel like this:

container.RegisterTypeForNavigation(typeof(MyViewModel));

And in my ViewModel, I inherit from an INavigationAware interface, and provide a simple implementation that loads up the data I need and hooks it up to the View.

So for just a little bit of work, I get an application containing a loosely-coupled collection of modules, and a navigation system that works with URI's. It will even cache the views so that it remembers where I left off if I navigate to a different module.

Is it worth it? I think it is.

  • I see how it's worth it in certain systems. This may be a better way to re-phrase the question. How do you know when using DI frameworks is worth it? In a scenario where I'm running multiple different types of payment and such I agree it makes complete sense to use DI frameworks as you can easily plug in different aspects of the program at different points. But for example with my singleton I wanted to change, or in any scenario where there aren't a huge amount of dependencies that can change, is it worth using a DI framework vs. just standard DI design practices? – Matthew Kerian Jun 16 at 0:15
  • 3
    Keep in mind that while proper use of a DI framework may decouple your code from itself, it also couples your code to that framework and adds a layer of complexity straneous to the language that the person that will manage your code down the line may not be aware of the inner workings. One needs to balance the needs, the pros and the cons before embracing any given framework for a project. – T. Sar Jun 17 at 13:17
  • @T.Sar: Prism uses an interface to abstract away the DI framework. I believe it's called IInjectable or something like that. – Robert Harvey Jun 17 at 15:22
1

I usually ask myself the following:

  • Will this code live for more than a week or two?
  • Will I ever come back to maintain this code after a week of not looking at it?
  • Will this turn into production code (even if I swear up and down that it's only proof of concept code)?

If the answer to any of these is yes (or even maybe-yes), I'll go through the effort of putting in DI. A vast majority of the projects I work on have DI so for me, the cost of having to think about it when it isn't there is a factor I consider. It's a lot easier for me (mentally) when I can just assume it's there. Plus anything that has a chance of going into production or could live for a long time will benefit from having the work to put in DI now while it's easy rather than later when it becomes a huge effort.

0

I think you're mixing things up a bit. The principle is "Dependency Inversion", not "Dependency Injection" and they're different things.

Dependency Inversion to me is a cognitive tool & concern while Dependency Injection is an optimization for Software designed with Dependency Inversion in mind.

Applying Dependency Inversion helps you design your models better, the way I see it, after creation the object must be ready to play and do what it is for. In Java code it's pretty common to see APIs with boilerplate like, initialize object, call 3 methods on it to set it up and only then it's ready to play. This means the object doesn't guarantee it's integrity, you have to make sure you're handling it the right way or it breaks, so to me that's brittle. Having a proper constructor which is responsible for this solves the problem. It also allows you to decompose your object before OR after it. E.g.: you can start coding "freestyle" mode having a lot of responsibilities, if you want to extract stuff to other objects for testing, parameterizing or purely organizational purposes, it's easy, the constructor tells, clearly, the objects needs that. And your refactoring is straightforward(e.g.: type checks).

Now, none of these benefits need an injection framework. You already have all that just by properly defining constructor(or factory whatever) & API on your SW. I've done it just using constructors and instantiating all dependencies by calling new.

In conclusion, how I handle it: most of the time I can't find justification not to only care about Dependency Inversion at the beginning, if this starts becoming strenuous or adding too much object creation boilerplate, then I'll think about Injection. Most importantly: doing that allows you to move on with the functionality you're trying to implement first and there's not that much harm in Injection later.

P.s.: IMO it's also helpful to think of @Inject variables as if they were constructor params, even though in some cases they can't be, that's just a side effect of the container(e.g.: Spring, EJB), it's a cognitive penalty if you forget that, though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.