Hacker News new | ask | show | jobs
by ivanche 2051 days ago
You're 100% right. People that complain about DI don't understand 2 simple facts:

1) that graph of object creation is NOT equal to graph of object usage

2) if you don't use DI, problems won't automagically go away - code will _still_ have dependencies, just they'll be hidden and tightly coupled

3 comments

I hope that's a typo because it's literally the opposite of what you're saying in #2.

It is precisely when you use a DI container that the problem is hidden, whether or not it's solved.

In most projects that use a DI container, the problem is usually not solved correctly, but the developers are oblivious and overconfident. They think, as you do, using a DI container means they did it right. False! The DI container only guarantees everything is hoisted up to the object constructor. This is NOT DEPENDENCY INVERSION. The objects can be in the constructor, but the dependency arrow can still point the wrong way. An obvious example of this I've seen a million times is an interface sitting right next to its only implementation. That's NOT Dependency Inversion.

If you don't use a DI container, the problem also may or may not be solved, but it is never obscured, it is completely visible.

It's not a typo - without DI (i.e. by using new operator freely whenever dev feels like) code still has dependencies, just this time hard-coded and invisible until you read the source.

Also, one can use DI without DI containers. Actually I prefer not using DI containers when possible.

That's the point I'd like to see discussed. What's wrong with hard-coding "new".
That multiple usages of the same concrete types requires changes on multiple places. For small programs, the di container itself can probably be skipped (i.e. instantiate an object graph by newing up). For larger programs, this is too cumbersome and therefore error-inducing.
> That multiple usages of the same concrete types requires changes on multiple places

Write a util function then, or like some like to call it, one of the many Factory pattern.

So then you’re writing your own one-off DI of sorts. And you have more code to write than if you’d just used DI.
Yup, unit tests, and in my mind, that's bad. There's two reasons:

#1 Because the language provides no means to arbitrarily mock fields of a class, an entire design pattern and framework needs to be created just to do so. Why can't the language just have such a feature?

#2 This actually temps people in building worse design, because instead of creating pure units that don't have dependencies to begin with, it facilitates the opposite of creating deeply nested chains of dependencies, because "DI framework wires it up for me". Where if you didn't have that luxury, you'd be pushed towards pure units that don't have state dependencies, and integ tests instead, which in my mind is much better overall.

#1 is just moving the goalpost. You jumped from "why new is bad" to "why can't language mock fields".

#2 What stops you from creating a complex system without having dependencies, thus avoiding DI? Also, I think it would make an interesting case study if you're willing to write it.

I spent maybe 15 years using C# and DI (for most of that time), and understand it pretty well. I still dislike it.

> just they'll be hidden and tightly coupled

They're more hidden with DI than without, in my experience.

At any rate, having left the .NET stack around 5 years ago, I certainly don't miss DI. My current code has more and better tests than my C# code ever did, so DI didn't really help me there (nor did it hinder me-- it was neutral). But my current code is much more explicit, direct, and a fair bit more compact. I'm definitely happier with it.

Compare 2 classes. Class A expects all its dependencies to be passed as constructor parameters. Class B has a default no-arg constructor, but buried inside 5 of its methods calls Dep1 dep1 = new Dep1(); or Dep2 dep2 = new Dep2(); Now, which class has obvious and loosely coupled dependencies? Which class has hidden and tightly coupled dependencies?

To me, answer is clear - class A has obvious and loosely coupled ones. Lo and behold, class A comes from program which uses DI. Class B doesn't.

Which stack did you move to?
It sounds like it's you that does not understand there are alternatives.
Been there, done that. Most popular alternative is new operators sprinkled throughout the codebase at will. Absolute horror!
I can see how IoC containers seem like a good idea to you then