26

I have recently worked on a Python project where we did dependency injection heavily (because we must in order for the app to be testable), but we didn't use any framework. At times it was a little tedious to wire up all the dependencies manually, but overall it worked great.

When an object had to be created in multiple places, we simply had a function (sometimes a class method of that object) to create a production instance. This function was called whenever we needed that object.

In the tests, we did the same thing: if multiple times we needed to create a 'test-version' of an object (i.e., a real instance backed by mock objects), we had a function to create this 'test-version' of a class, to be used in tests.

As I said, generally this worked fine.

I am now entering a new Java project, and we are deciding whether to use a DI framework, or do DI manually (like in the previous project).

Please explain how working with a DI framework will be different, and in what manners it is better or worse than manual 'vanilla' dependency injection.

Edit: I would also like to add to the question: have you witnessed any 'professional level' project that does DI manually, without a framework?

2
  • Beside my answer. Both ways are compatible. You can leave soft dependency injection to the framework and keep your factories for critical components. Components related to the model or business.
    – Laiv
    Commented May 14, 2016 at 21:46
  • 4
    I guess you already checked, just in the case you don't Why do we need frameworks for DI?
    – Laiv
    Commented May 15, 2016 at 7:05

9 Answers 9

23

The key of DI containers is the abstraction. DI containers abstract this concern for you. As you may guess, it has a noticeable impact on the code, often translated into a fewer number of constructors, setters, factories and builders. In consequence, they make your code more loosely coupled (due to the underlying IoC), cleaner and simpler.

Backgrounds

Years ago, DI required us to write config files (declarative programming). It was fantastic to see the number of LOC diminishing substantially, but while the LOCSs decreased, the number of config files slightly increased. For medium or small projects it was not a problem at all, but for larger projects having the DI scattered between code and several files became a pain in the ... Nonetheless, the main problem was the paradigm itself. It was quite inflexible because the descriptors left little space for customizations.

The paradigm shifted progressively towards to convention over configuration, which trades config files for annotations or attributes. It keeps our code cleaner and simpler while providing us with the flexibility that XML could not. Some DI contianers are programable so the DI graph can change in runtime.

Now, without setters, constructors and XML the application is more than clean. Is also magic.

On the down side...

Convention over configuration makes the abstraction so heavy that you barely know how it works. Sometimes seems magic and here comes one more drawback. Once is working, many developers don't care about how it works.

This is a handicap for those who learnt DI with DI containers. They don't fully understand the relevance of the design patterns, the good practices and the principles that were abstracted by the container. I have asked developers if they were familiarised with DI and its advantages and they answered: -Yes, I have used Spring IoC-. (What the hell does it mean?!?)

One can agree or not with each of these "drawbacks". In my humble opinion, it's a must to know what's going on in your project. Otherwise, we don't have a full understanding of it. Also is to know what DI is for and to have a notion of how to implement it is a plus to consider.

On the plus side...

One word productivity. Frameworks let us focus on what really matters. The application's business.

Despite the commented shortcomings, for many of us (which job is conditioned by deadlines and costs), these tools are an invaluable resource. In my opinion, this should be the main argument in favour of implementing a DI containers.

Testing

Whether we implement pure DI or containers, testing is not going to be a problem. Quite the opposite. The same containers often provide us with the mocks for unit testing out of the box. Along the years I have used my tests as thermometers. They tell me if I have relied heavily on the containers facilities. I say this because the containers I'm used can initialize private attributes without setters or constructors.

Sounds tempting right? Be careful! Don't fall into the trap!

Suggestions

If you decide to implement containers, I strongly suggest sticking with the good practices. Keep implementing constructors, setters and interfaces. Enforce the framework/container to use them. It will make easier possible migrations to another framework or to remove the actual one. It can reduce significantly the dependency on the container what ease the testing too.

Regarding this practices:

When to use DI containers

My answer is going to be biased by own experience which is mainly in favour of DI containers (as I commented, I'm heavily focused on productivity, so I have never had the need of pure DI. Quite the opposite).

I think you will find interesting Mark Seeman's article about this subject, which also answers the question how to implement pure DI?.

Finally, if we were speaking of Java, I would consider first taking a look to the JSR330 - Dependency Injection.

Summarising

Benefits:

  • Cost-cutting and time-saving. Productivity.
  • A smaller number of components.
  • The code becomes simpler and cleaner.

Drawbacks:

  • DI is delegated to 3rd party libs. We should be aware of their trade-offs, strengths and weakness.
  • Learning curve.
  • They quickly make you forget some good habits.
  • Increase of the project's dependencies (more libs)
  • Containers based on reflection require more resources (memory). This is important if we are constrained by the resources.

Differences with pure DI:

  • Less code and more configuration files or annotations.
17
  • 1
    "These frameworks don't private to you to do unit test or integrity test, so don't you worry about testing. " What exactly does this mean? The wording makes me think it's a typo but I'm having trouble decoding it. Commented May 15, 2016 at 16:47
  • It means that the hard time debugging or the usage of the frameworks for testing are not enough drawbacks to discard to use these frameworks. Because even if you dislike them they still have benefits that really worth a try. The big drawbacks are not frameworks by theyself. Is how you use them. Some good practices like interfaces and setters are still required even if your framework doesn't. Finally there are good libs for testing which integrates easly with these sort of Frameworks (DI)
    – Laiv
    Commented May 15, 2016 at 17:01
  • If that's what you mean consider: "These frameworks don't prevent you from performing unit tests or integrity tests, so don't you worry about how they impact testing" Commented May 15, 2016 at 17:06
  • 1
    Note that Dagger2 does DI slightly different. The glue code is generated at compile time as normal, readable Java sources so it is much simpler to follow how things are glued together instead of having to deal with runtime magic. Commented Jul 17, 2017 at 3:01
  • 1
    Yep. The problem with spring is its weight. Too heavy, IMO. Plus the abuse of reflection. It has a significant impact on the resources
    – Laiv
    Commented Jul 17, 2017 at 10:27
10

In my experience, a dependency injection framework leads to a number of issues. Some of the issues will depend on the framework and tooling. There might be practices that mitigate the issues. But these are the issues that I've hit.

Non-global objects

In some cases, you want to inject a global object: an object which will have only one instance in your running application. This might be a MarkdownToHtmlRendererer, a DatabaseConnectionPool, the address for your api server, etc. For these cases, dependency injection frameworks work very simply, you just add the needed dependency to your constructor and you've got it.

But what about objects that aren't global? What if you need the user for the current request? What if you need the currently active database transaction? What if you need the HTML element corresponding to the div which contains a form in which is a text box which has just fired an event?

The solution I've seen employed by DI frameworks is hierarchical injectors. But this makes the injection model more complicated. It becomes harder to figure out just what will get injected from what layer of the hierarchy. It becomes difficult to tell whether a given object will exist per-application, per-user, per-request, etc. You can no longer just add your dependencies and have it work.

Libraries

Often you will want to have a library of reusable code. This will also include the instructions for how to construct objects from that code. If you use a dependency injection framework, this will typically include binding rules. If you want to use the library, you add their binding rules to yours.

However, various problems can result. You may end up with the same class bound to different implementations. The library may expect certain bindings to exist. The library may override some default bindings causing your code to do strange thing. Your code may override some default binding causing the library code to do strange things.

Hidden Complexity

When you manually write factories, you have a sense of how the dependencies of the application fit together. When you use a dependency injection framework, you don't see this. Instead, objects tend to grow more and more dependencies until sooner or later everything depends on pretty much everything.

IDE Support

Your IDE will probably not understanding the dependency injection framework. With manual factories, you can find all the callers of a constructor to figure out all the places that the object might get constructed. But it won't find the calls generated by the DI framework.

Conclusion

What do we get from a dependency injection framework? We get to avoid some simple-minded boilerplate needed to instantiate objects. I'm all for eliminating simple-minded boilerplate. However, maintaining simple minded boilerplate is easy. If we are going to replace that boilerplate, we should insist on replacing it with something easier. Because of the various issues I've discussed above, I don't think frameworks (at least as they stand) fit the bill.

5
  • This is a very good answer, but I can't imagine using an IoC container for a class library. That feels like poor design to me. I would expect a library to have me explicitly give it whatever dependencies it requires.
    – RubberDuck
    Commented May 16, 2016 at 22:41
  • @RubberDuck, in my case, I worked for a large company with a large number of java projects all standardized on the same dependency injection framework. At that point it becomes tempting for some teams to export a library that expects to be put together by the DI framework, rather then providing a sensible external interface. Commented May 16, 2016 at 23:38
  • That's unfortunate @WinstonEwert. Thanks for filling in the context for me.
    – RubberDuck
    Commented May 17, 2016 at 0:09
  • It would be great to IDE part, with the runtime binding of injections framework as opposed to design time type binding of manual injections. Compiler prevents forgotten injections when they are manual.
    – Basilevs
    Commented Nov 12, 2016 at 21:18
  • IntelliJ understands CDI (Java EE standard DI) Commented Jul 17, 2017 at 3:02
3

Does Java + dependency injection = framework required?

No.

What does a DI framework buy me?

Object construction happening in a language that isn't Java.


If factory methods are good enough for your needs you can do DI in java completely framework free in 100% authentic pojo java. If your needs go beyond that you have other options.

The Gang of Four design patterns accomplish many great things but have always had weaknesses when it came to the creational patterns. Java itself has some weaknesses here. DI frameworks really help with this creational weakness more than they do with the actual injections. You already know how to do that without them. How much good they will do you depends on how much help you need with object construction.

There are many creational patterns that came out after the Gang of Four. The Josh Bloch builder is a wonderful hack around java's lack of named parameters. Beyond that are iDSL builders that offer a lot of flexibility. But each of these represent significant work and boilerplate.

Frameworks can save you from some of this tedium. They are not without drawbacks. If you are not careful you can find yourself dependent on the framework. Try switching frameworks after using one and see for yourself. Even if you somehow keep the xml or annotations generic you can end up supporting what are essentially two languages that you have to mention side by side when you advertize programming jobs.

Before you become too enamored with the power of DI frameworks take some time and investigate other frameworks that give you capabilities that you may otherwise might think you need a DI framework for. Many have branched out beyond simple DI. Consider: Lombok, AspectJ, and slf4J. Each overlaps with some DI frameworks but each works fine on their own.

If testing is really the driving force behind this please look into: jUnit (any xUnit really) and Mockito (any mock really) before you start thinking a DI framework should take over your life.

You can do what you like, but for serious work I prefer a well populated tool box to a Swiss army knife. Wish it was easier to draw these lines but some have worked hard to blur them. Nothing wrong with that but it can make these choices challenging.

11
  • PowerMock has solved some of these cases. Atleast it let you mock up statics
    – Laiv
    Commented May 15, 2016 at 7:08
  • Meh. If you're doing DI properly, it should be relatively simple to swap out one IoC Container framework for another. Keep those annotations out of your code and you'll be fine. Basically, use the IoC container to do DI instead of using the container as a service locator.
    – RubberDuck
    Commented May 15, 2016 at 13:31
  • @RubberDuck correct. Short of testing and maintaining your code base constantly under multiple DI frameworks do you know a simple reliable way to check that "you're doing DI properly"? Even if I use nothing but pojo's in java, if significant effort has gone into making the XML it's still not a simple swap when the XML is dependant on the IoC container. Commented May 15, 2016 at 14:22
  • @CandiedOrange I'm using "simple" as a relative term. In the grand scheme of things, replacing one composition root with another is not an overly difficult task. A few days work tops. As for ensuring you're doing DI properly, that's what Code Reviews are for.
    – RubberDuck
    Commented May 15, 2016 at 16:25
  • 2
    @RubberDuck most "composition roots" I've seen are about 5 lines of code in main. So no. not an overly difficult task. It's the proprietary stuff that escapes those lines that I'm warning against. You call it "doing DI properly". I'm asking if you what you'd use to prove a problem in a code review. Or would you just say "Meh"? Commented May 15, 2016 at 16:37
2

Creating classes and assigning them dependencies is part of the modeling process, the fun parts. It's the reason why most of programmers enjoy programming.

Deciding, which implementation will be used and how classes are constructed is a thing which will have to be implemented somehow and is part of application configuration.

Manually writing factories is a tedious work. DI frameworks make it easier by automatically resolving dependencies which may be resolved and requiring configuration for those which may not.

Using modern IDEs allows you to navigate through methods and their usages. Having manually written factories is quite good, because you can simply highlight a class' constructor, show its usages, and it will show you all the places where and how the specific class is being constructed.

But even with DI framework, you can have a central place, such as object graph construction configuration (OGCC from now on), and if a class depends on ambiguous dependencies, you can simply look into OGCC and see how a specific class is being constructed right there.

You could object, that you personally think being able to see the usages of a specific constructor is a great plus. I would say what comes out better to you is not only subjective, but comes mostly from personal experience.

If you had always worked on projects which relied on DI frameworks, you would really know only that and when you wanted to see a configuration of a class, you would always look into OGCC and wouldn't even try to see how the constructors are used, because you would know the dependencies are all wired up automatically anyway.

Naturally, DI frameworks cannot be used for everything and every now and then you will have to write a factory method or two. A very common case is constructing a dependency during iteration over a collection, where each iteration supplies a different flag which should produce a different implementation of an otherwise common interface.

In the end it will most likely all come down to what your preferences are and what you are willing to sacrifice (either time writing factories or transparency).


Personal experience (warning: subjective)

Speaking as a PHP developer, although I like the idea behind DI frameworks, I have only ever used them once. That was when a team I was working with was supposed to deploy an application very quickly and we couldn't lose time writing factories. So we simply picked up a DI framework, configured it, and it worked, somehow.

For most projects I like to have the factories manually written because I don't like the black magic happening within DI frameworks. I was the one responsible for modeling a class and its dependencies. I was the one deciding why the design looks the way it does. So I'll be the one who properly constructs the class (even if the class takes hard dependencies, such as concrete classes instead of interfaces).

2

Yes, when working in Java, I would recommend a DI framework. There are a few reasons for this:

  • Java has several extremely good DI packages that offer automated dependency injection and also usually come packaged with additional capabilities that are harder to write manually than simple DI (eg scoped dependencies that allow automatic connection between scopes by generating code to look up what scope should be in use an d finding the correct version of the dependency for that scope - so for instance application scoped objects can refer to request scoped ones).

  • java annotations are extremely useful and provide an excellent way of configuring dependencies

  • java object construction is overly verbose compared to what you're used to in python; using a framework here saves more work than it would in a dynamic language.

  • java DI frameworks can do useful things like automatically generating proxies and decorators which are more work in Java than a dynamic language.

2

Personally I don't use DI-containers and don't like them. I have couple of more reasons for that.

Usually it's a static dependency. So it's just a service locator with all its drawbacks. Then, due to the nature of static dependencies, they are hidden. You don't need to deal with them, they are somehow already there, and it's dangerous, because you cease to control them.

It breaks OOP principles, such as cohesion and David West's Lego-brick object metaphor.

So building the whole object as close as possible to the program's entry point is the way to go.

1

If your project is small enought and you do not have much experience with the DI-Framework i would recommond to not using the framework and do di manually.

Reason: I once worked in a project that used two libraries that had direct dependencies to different di frameworks. they both had frameworkspecific code like di-give-me-an-instance-of-XYZ. As far as i know you can only have one active di-framework implementation at a time.

with code like this you can do more harm than benefit.

If you have more experience you would probably abstract away the di-framwork by an interface (factory or servicelocator) so this problem will not exist any more and the di framework will do more benefit that harm.

1
  • Note that your point is not generally the case. E.g., Guice and Spring can co-exist in a project quite nicely.
    – winne2
    Commented Jan 17, 2022 at 14:51
1

As you already have noticed: Depending on the language you use, there are different points of views, diffenrent takes on how to deal with similar problems.

Regarding to dependency injection, it comes down to this: dependency injection is, as the term says, nothing more than putting the dependencies one object needs into that object - contrasting the other way: letting the object itself instatiate instances of objects it depends on. You decouple object creation and object consumption for the win of more flexibility.

If your design is well layed out, you usually have few classes with many dependencies, therefore the wiring up of dependencies - either by hand or by a framework - should be relatively easy and the amount of boilerplate to write the tests should be easy managable.

That said, there is no need for a DI-framework.

But why do you want to use a framework nevertheless?

I) Avoid boilerplate code

If your project gets a size, where you feel the pain of writing factories (and instatiations) again and again, you should use a DI-framework

II) Declacrative approach to programming

When Java was once programming with XML it is now: sprinkling fairydust with annotations and the magic happens.

But seriously: I see a clear upside to this. You clearly communicate intent with saying what is needed instead of where to find it and how to build it.


tl;dr

DI frameworks don't make your codebase magically better but it helps making good looking code looking really crisp. Use it, when you feel you need it. At a certain point in your project, it'll save you time and prevent nausea.

6
  • 1
    You are right! I tend to worry too much about how things works under the hood. I have had awful experiences working with frameworks that I barely understood. I'm not advocating in favour of testing the frameworks, just understand what they do and how they do It (if possible). But it depends on your own interestings. I think that understanding how they works, you are in a better position to decide if they are suitable for you. For example, the same way you would compare different ORMs.
    – Laiv
    Commented Jul 16, 2017 at 11:02
  • 1
    I think it is always right to know how stuff works under the hood. But it shouldn't scrare you not knowing. I think the selling point for Spring e.g. is, that it just works. And yes, you are absolutely right, that in order to make an informed decision on whether to use a framework, you have to have some degree of knowledge. But I see too often a pattern of distrust for people who haven't the same scars as oneself, although not in your case, where there is the belief, only the one who has experienced manual hunting is allowed going to the supermarket. Commented Jul 16, 2017 at 12:07
  • Fortunately, on these days we don't even need Spring or DI frameworks for Java. We already got the JSR330 which is sadly ignored (at least I didn't see a project implementing it). So, the people still has time win their scars :-)
    – Laiv
    Commented Jul 16, 2017 at 12:27
  • I have edited my answer and I took into consideration your comments. I have removed the "drawbacks" related with debugging. I came to the conclusion that you were right on that. Take a look and consider updating your answer too, because right now you would be quoting parts I have removed from my answer.
    – Laiv
    Commented Jul 17, 2017 at 8:24
  • 1
    The answer changed so little!!! Nothing that should worry you :-). The message and the arguments remain the same. I just wanted your answer to continue to be as it's. I guess It just took you to remove one of the quotes.
    – Laiv
    Commented Jul 17, 2017 at 9:29
0

Yes. You should probably read Mark Seemann's book titled "Dependency Injection". He outlines some good practices. Based on some of what you've said, you might benefit from. You should aim to have one composition root or one composition root per unit of work (e.g., web request). I like his way of thinking that any object you create is considered a dependency (as is any parameter to a method/constructor) so you should really be careful of where and how you create objects. A framework will help you keep these concepts clear. If you read Mark's book you'll find more than just the answer to your question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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