13

I have been refactoring an existing system to use dependency injection, and that work has been going smoothly.

After a while I noticed that a large number of in-house libraries became dependent upon the DI framework I used. As a result the entire project now depends upon this third-party framework.

I saw an irony in decoupling all the dependencies by making them dependent upon a shared library.

My first reaction was to create a wrapper library around the dependency framework. Therefore, I could replace this framework if needed. After estimating the work involved I realized that the resulting API would be to similar to the existing framework, and therefore make replacing it more difficult. So I abandoned the idea.

My concern is that the DI framework I'm using becomes obsolete or needs replacing.

Does there exist a development pattern when working with DI that reduces the coupling between a project and the DI framework?

Reactgular
  • 13,040
  • 4
  • 48
  • 81
  • 4
    The "don't use a DI framework" pattern. Though I must wonder if you are you solving a problem you don't really have - how likely are you to change the DI framework? – Oded Jun 15 '14 at 15:11
  • 1
    @Oded a good DI framework should be able to work with code transparently, but there are cases where that's not possible. You have to then use the DI APIs inside your classes. In those cases, it's difficult to share or change the DI framework without needing to change those classes. Since this is my first time working with that DI framework. I'm not sure if I'll need to replace it. – Reactgular Jun 15 '14 at 15:16
  • Have you considered taking the DI framework apart and studying/adjusting it to your needs? Considering that the framework itself might be open-source, you could easily stop it from turning obsolete by maintaining it yourself. Digging deeper into it is the best way to learn what is "under the hood". Perhaps there may also exist an option where you decouple parts of the DI framework and use some type of "middle-ware", but you're adding unnecessary complexity then. My best advice would be to try to keep the project from becoming obsolete. – Joe Jun 15 '14 at 17:49
  • 1
    Can you describe how your libraries became dependent on the DI framework? – Sign Jun 15 '14 at 20:36
  • @Sign: When you use a DI container, generally all of the class dependencies are fulfilled through that container. – Robert Harvey Jun 15 '14 at 20:37
  • @RobertHarvey that makes it difficult, or confusing to use, not dependent. It also wouldn't be a dependency on a single DI framework. – Sign Jun 15 '14 at 20:51
  • @Sign: The DI frameworks would only be interchangeable if they implemented the same set of interfaces (they don't). Otherwise, it's a rewrite. – Robert Harvey Jun 15 '14 at 20:52
  • 8
    Your system also depends on electricity. I suggest you decouple that first. – Idan Arye Jun 15 '14 at 21:05
  • 1
    @Sign one feature of DI is for a constructor to request a service object without changing the constructor parameters. For example; `this.fooService = DIFrameWork.Get();`. As soon as an object does this it becomes coupled to the DI framework. It solves having to refactor code to change the constructor, but creates a new dependency. – Reactgular Jun 15 '14 at 21:47
  • 3
    @MathewFoscarini Isn't this an anti-pattern? You can do it, but you shouldn't as it obfuscates the dependency. – maaartinus Jun 15 '14 at 21:52
  • @maaartinus +1 that is a very good point. Hadn't thought of it that way. – Reactgular Jun 15 '14 at 21:54
  • 1
    @IdanArye - that is not correct, electricity is just an implementation detail. You can give your program to a human or a trained animal to execute (it could take awhile of course). Or just use an analogue mechanical computer. – Den Jun 16 '14 at 09:40
  • 2
    @MathewFoscarini `DIFramework.Get()` isn't actually dependency injection; it's a related pattern called Service Locator. Lots of people dislike Service Locator because it couples you to the framework and because it's too easily abused (like Singleton). Martin Fowler has a terrific article about these patterns: http://martinfowler.com/articles/injection.html – Benjamin Hodgson Jun 16 '14 at 17:17

3 Answers3

19

Ordinary constructor injection doesn't require a framework at all. The only thing you lose out on is the ability to centralize your dependencies in a configuration file.

DI containers are an "enterprise software" pattern, used when the object graph is very large and complex. I suspect that 95% of applications do not require it.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • 5
    I agree that small projects do not *require* it, but 95+% of projects can *profit* from it. – maaartinus Jun 15 '14 at 21:02
  • 11
    @maaartinus: Unnecessary added complexity for minimal benefit. – Robert Harvey Jun 15 '14 at 21:03
  • 1
    What the? These are my stats per class: 0.5 annotation, 0.1 configuration line. So what complexity do you mean??? – maaartinus Jun 15 '14 at 21:06
  • 2
    @RobertHarvey: though I agree 100% with your statements above, the OP states he already has introduced a DI framework. Telling him "better don't" is not really an answer to his question. – Doc Brown Jun 15 '14 at 21:07
  • @RobertHarvey Well, now you've hit the nail on the head. You are likely comparing your experience to a more complex DI framework that adds complexity. I on the other hand, selected a simple open source DI framework that reduces my work load for testing the existing system. What happens when I outgrow that framework and need one that is more complex? Refactor the entire project or try to make it replaceable? Isn't this the standard de facto question most developers ask? – Reactgular Jun 15 '14 at 21:53
  • @MathewFoscarini As I'm completely lost concerning the added complexity, I asked a [corresponding question](http://programmers.stackexchange.com/q/245091/14167). The point of outgrowing the framework sounds interesting too, could maybe you elaborate? – maaartinus Jun 15 '14 at 22:27
  • 1
    @maaartinus the more the framework automates and the more *stuff* it can inject the more complex. There are XML config files, constructor injection, property injection, automatic object mocking, lazy injection, etc.. etc.. these DI frameworks can get very complex. – Reactgular Jun 15 '14 at 22:33
8

You are fully correct - using a DI framework will most probably make your code dependent from that thing. Actually, that is too surprising, since this is typically true for every other framework or foundation library, especially when that lib supports your project with some generic features used everwhere in your code. For example, when you decide to use a certain UI framework or Web framework, this decision is hard to change afterwards as soon as you have build a certain amount of code based on that library. When you decide to use a specific (maybe non-standard) String class, you cannot easily change that decision later. Such a decision is an architectural one, it is like choosing a certain programming language and try to change that decision after you have written >100K lines of code.

Having all of your code depend on a certain framework might not be a problem as long as it does what you expect from it, and as long as it is properly maintained. But it can become an issue if that's not the case. There are some strategies how to deal with that situation:

  • choose a framework from a vendor you have faith in that he can deliver you updates and new releases for several years from now

  • choose an open source framework which has few enough lines of code (and a proper license), so you can do any maintenance on your own, given the vendor vanishes from the market

  • write your own framework

  • live with the situation as long as the vendor is available, and when he really vanishes, choose a different framework and try to create an adapter which emulates the old framework using the new

The idea of creating a wrapper library beforehand is not new at all, but I have seldom seen that working, since you would have to make assumptions for a future situation for which you don't know if or when it will hit you, and what the "new" framework will look like. On the other hand, some years ago we successfully exchanged a complete UI framework in a C++ project with ~120K of lines of code by applying the adapter strategy I mentioned above.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
0

I don't think DI frameworks can really become obsolete anytime soon. What should happen to make it obsolete?

  • An invention of a new and smarter pattern maybe? However it should look like, it would require much bigger changes in the code.
  • A change in the language maybe? Even worse.

I'd say that the current DI is mature enough and I'm not aware of much happening there. You haven't specify your language, so speaking of Guice, it's fairly non-obtrusive and works with standard Java annotations (also uses their own for things not standardized, but you rarely need it). It's open sourced, widely used, and Apache licensed. What could be the problem?

I'm pretty sure that changing the DI framework would be orders of magnitude easier than changing any other library (e.g., a UI change means much more work).

maaartinus
  • 2,633
  • 1
  • 21
  • 29