3

I'm new to dependency injection and though I've really liked it so far, I'm not sure where bindings should go. I'm using Guice in Java, so some of what I say might be specific to just Guice. As I see it, there's two options:

Accompanying the class(s) its needed for. Then, just write install(OtherClassModule.class) in whatever other modules want to be able to use said class. As I see it, the advantage of this is that classes that want to use it (or manage classes that want to use it) don't need to know any of the implementation detail. The issue I see is that what if two classes want to use two different versions of the same class? There's a lot of customization possible because of DI and this seems to restrict it a lot.

Implemented in the module of the class(s) its needed for. It's the flip of what I said above. Now you have customization, but not encapsulation.

Is there a third option? Am I misunderstanding something obvious? What's the best practice?

2
  • If you're not new to programming then dependency injection is not a new concept for you. What you are referring to (or what Guice does) is Inversion of Control (IoC)
    – Bart
    Aug 4, 2014 at 12:38
  • Are you writing a library ?. Or does your module belong to an application ? If it's not application see BenjaminHodgson answer.
    – Walfrat
    Dec 22, 2016 at 10:44

3 Answers 3

4

Mark Seemann has written extensively about this topic. Here's a summary of his points.

  • For maximum reuse, structure your code as one or more libraries and/or frameworks which do not require or even mention a particular IoC container, and an application whose sole job is to create concrete instances and introduce them to each other (aka the Composition Root). A Composition Root may encapsulate an IoC container, or it may simply use new-expressions. Composition Roots are not meant to be reusable.

  • It should be straightforward to use a library or a framework without also installing an IoC container.

  • Use constructor injection to make libraries Dependency-Injection-friendly, though for convenience you can supply some creation methods which hard-code common dependencies. These creation methods should use new-expressions, not an IoC framework.

  • Use abstract factories to make frameworks Dependency-Injection friendly. For example, a web framework may need a way to create request handlers. By relying upon an interface for that operation, frameworks allow applications to customise the creation of handlers without requiring the use of a particular container.

So to answer your question directly: don't define any Guice bindings for your library. You shouldn't make your clients depend on a particular framework. If you want to provide a way to create objects with the "normal" set of dependencies filled-in, use new-expressions encapsulated inside creation methods or builders.

3
  • well, I agree with the points, but it's possible than OP post is talking about module of an application, like *-core, *-workflow, *-data. THose kind of module will likely need the dependency framework to work and use 3rd party components (ORM, Workflow Engine,..).
    – Walfrat
    Dec 22, 2016 at 10:45
  • @Walfrat If your persistence library, web framework, whatever library requires a specific IoC container to operate, then guess what: it's a bad library. What do you do when you need to use two libraries with different IoC dependencies? Dec 22, 2016 at 13:10
  • I am not talking about a library, but a part of an application cut in modules which implements business fonctionnalities.
    – Walfrat
    Dec 22, 2016 at 13:19
0

First of all, I assume this code is some kind of an API, because otherwise you would have known if there exist two classes that do want to use different implementations.

So, if you want a more coarse-grained API, go for the first alternative. If you want to let a programmer select implementation himself, go for the second alternative. Finally, if you want both, see the "robot legs" question in the Guice FAQ.

-1

There's a third solution that I've been using instead.

Have the module accompany the class(s) it's needed for, but have multiple different versions (using inheritance in Guice) with different configurations. Then just install(...) whichever version I want. The advantage is that it's still encapsulated, but it is also customizable.

1
  • 1
    Your idea results in one configuration to make your library talk to a SQL Server database and a separate one to talk to an Oracle database. What if I'm trying to migrate my data, and I need to read from Oracle but write to SQL Server? You have to write another set of bindings in your library. What about the other way around? What if I want to use Spring instead of Guice? You end up with a combinatorial explosion of possible configurations just to keep your library reusable. Better to let applications deal with configuration - that's their job, after all. Feb 1, 2015 at 23:30

Your Answer

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

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