4 ms·
I wonder, is there a good even-handed critique out there of the dependency-injection pattern and related philosophies? For me and probably a lot of people here
by brundolf 6y ago
I wonder, is there a good even-handed critique out there of the dependency-injection pattern and related philosophies?
For me and probably a lot of people here, the pattern fundamentally offends my sensibilities; mainly, but not exclusively, because it forces you to put everything into classes. I'd much rather pass plain functions when I need inversion of control, and use closures if I really need to "configure" some piece of code. I'd also prefer to import and pass down those functions explicitly, instead of having values magically resolve in some runtime context that lives outside of the "real language". I do acknowledge that languages like Java don't, or at least didn't for a long time, support these other language features and so may have had no choice but to use DI as a crutch. But I've also seen it used in languages that do have those features, like JavaScript.
On the other hand, I'm not sure I've used the pattern enough to critique it fairly. And obviously it's been used for decades at many very large and successful companies. So what I'd really like is to hear from someone who's experienced with both worlds about the advantages and disadvantages, assuming that both exist.
- anamexis 6y agoI'm curious what you think the fundamental difference is between passing configuration through functions and closures, and passing it with classes. Classes are just fancy closures, after all.
- rraghur 6y agoDiscussion a couple of days around .Net 5 release announcement ended up going into di vs no di.. I'm on mobile but you can get to it from my comment history
- rraghur 6y agoMore ceremony & semantic load of course and you end up with having to define single use abstractions so that you can mock them in tests I've long been in the pro DI camp and used to think that interfaces and brittle tests were unavoidable.. Only after i recently got into FP with f#, I've come to appreciate how i used to conflate good IoC design with DI usage.. I'm pretty sure that I'm not alone
- jolux 6y agoIf you find yourself creating a lot of single-use abstractions, I think you're probably doing something wrong. In particular a lot of containers (I know Autofac) support Func<> very well. As for ceremony and semantic load, I can't argue here, though I think following DI restricts some of the semantic load that comes with abstracting mainly through inheritance and through managing stateful dependencies.
- brundolf 6y agoI look at classes as holders of mutable state. While a closure can technically hold mutable state, subjectively I feel there's a convention that closure captures are often treated as constant (mainly by association with the functional paradigm).
- sk5t 6y agoOne doesn't need to think of classes that way, though. A class could hold immutable references to immutable objects/functions/whatever (these are often the easiest classes of all to reason about). Call me a weirdo, but I enjoy using Spring DI with Scala. It's quite easy to inject into a constructor like "class Foo(f: Int => String)" even if a little bit of "manual currying" is sometimes needed.
- brundolf 6y agoSpring DI implies automatic DI containers, right? So how would that work with an abstract function type (as opposed to a specific class that gets instantiated)?
- sk5t 6y agoI actually like fairly explicit XML-based config with Spring. Something like "<constructor-arg value='#{thing.fnFor("x")}'/>" for example. Connects the pieces without relying on inference/magic.
- tybit 6y agoIt’s not clear whether you dislike DI in general or specifically DI containers. I think it’s an important point to clarify because DI on its own absolutely does not live outside of the real language and while it may be much more common to use classes than functions it’s not necessary. I agree with your feelings in relation to DI containers however.
- brundolf 6y agoI wasn't actually aware of the distinction. I think you're right, that what I mainly dislike are DI containers. If DI just means "passing some value to something for it to use later" - which would even include currying, really - then yeah, I suppose I don't have a problem with DI/IoC themselves.
- vips7L 6y agoDI has nothing to do with the differences between classes/objects and functions/closures, DI and IoC are about reusable code and being able to switch out implementations. You can do IoC in either pattern. In Java functions/closures and objects/classes are the same thing. You have the best of both worlds. You can for instance define a function that takes an argument a and a function b and pass it either a functional lambda or a class that implements said function: static void doSomething(int a, Runnable b) { if (a > 0) { b.run(); } } doSomething(1, () -> System.out.println("hello")); Runnable r = new SomeClassThatImplementsRunnable(); doSomething(0, r);
- Fire-Dragon-DoL 6y agoIoC container is not DI and IoC container is a pattern with a lot of downsides. In Ruby, I use [the doctrine of useful objects](http://docs.eventide-project.org/user-guide/useful-objects.html http://docs.eventide-project.org/user-guide/useful-objects.h...), which without a gem is very clear, no meta magic and it boils down to just DI with setters and getters. Simple and effective. And it has the power of locality over an IoC container. That being said, please remember that a class and a closure are essentially the same thing with a different syntax.
- brundolf 6y agoI posted this under another reply, but yes, I didn't actually realize the distinction of "containers" and how that's just one specialization of the pattern. Containers appear to be the main thing that bothers me, particularly when the container implementation requires that all injectable entities are classes and not functions. It creates this "viral" effect where nearly everything you implement ends up having to be wrapped up in a class, even when there's no reason to do so other than the injection container.
- Fire-Dragon-DoL 6y agook! Yeah the ioc pattern is not great, there are better alternatives out there without the need of having an object dependent on the entirety of the software.
- Merad 6y agoIME most in DI heavy C# code (e.g. Asp.Net Core) you're using classes but those classes are really just a set of named functions bundled together with their dependencies, not unlike a closure. It's not very common to see classes that are stateful. I've never tried it but I'm fairly certain that most C# IOC containers should allow you to resolve functions if you really wanted to go that route.