8 ms·
I've used dependency injection heavily in Java in previous jobs, and, later, spent a few years doing Golang at another job. I never missed it. What does depend
by BobbyJo 5y ago
I've used dependency injection heavily in Java in previous jobs, and, later, spent a few years doing Golang at another job. I never missed it.
What does dependency injection give you that a simple combination of Singletons, Constructors, and Factories doesn't? I feel like the only thing you get is the ability to combine multiple independent dependency trees without having to make a sane structure. Kind of like, what redux does for state in JavaScript. It make things easier because it takes away some responsibility, but, in my eyes, that responsibility is an important one, and ignoring it makes code very hard to reason about.
- saturn_vk 5y agoI think you are confusing dependency injecting with frameworks that facilitate it. You are probably using the former with constructors
- BobbyJo 5y agoWhat's the difference? Isn't the 'injection' part the part where you don't need to connect point A and point B?
- taeric 5y agoSorta. The pattern is having standard method of injecting dependencies. Having a framework just saves you having to do the actual injecting, manually. This is easy to see in frameworks like dagger, which compile time generate the boilerplate you could manually do. And if everything is a singleton with no lifetime management, the framework doesn't buy you too much. The pattern, though, is kind of nice. I rarely have to question how a dependent section of code is linked to the one I'm at. (Contrast to python, where I don't know what is going to happen if I add that import...)
- BobbyJo 5y ago> (Contrast to python, where I don't know what is going to happen if I add that import...) I felt that in my bones.
- bluefirebrand 5y agoThis is actually something I've been trying to talk about with a new hire at my job. We are running a nodejs stack, and he comes from a strict OOP C# background. I've never worked in a strict OOP paradigm, coming from Python and JavaScript mostly myself. I've been puzzled by his insistence that DI is important. He wants us to implement DI containers and take a "code to interfaces not implementations" approach. To me theres not really any value in this approach in JavaScript. I don't know Go, but I get the impression this stuff is also not as valuable there. My question is always "what does this get me and what does it cost me?". Outside of strict OOP paradigms like C# and Java, it's pretty unclear what the benefits are to me.
- danmur 5y agoI've found DI pretty useful when building frameworks, it gives you a sort of generic plugin system. Plus you can hide it from consumers if that makes sense. If you're just building applications I'm not sure it's worthwhile.
- bluefirebrand 5y agoThe argument I always hear is DI makes your code more testable. Which is probably true in some cases, but I find most of my code is pretty testable without it. Haven't run into any tests I've wanted to build where I couldn't.
- mdpye 5y agoHow do you test the code which determines when to fire the torpedoes, without actually firing the torpedoes every time you run the tests?
- bluefirebrand 5y agoBy using a mock?
- mdpye 5y ago
- twodave 5y agoI came here to ask a similar question. I’ve spent most of my career writing C# where DI is prevalent. Over the Christmas holiday I picked up golang a bit. When I went to learn about DI for golang it seemed very counter to the principles of the language so I simply moved on. What am I missing out on?
- mdpye 5y agoDo you distinguish between dependency injection (frameworks) and general inversion of control? Because what I think of dependency injection is extremely common in golang - they made interfaces satisfy structurally rather than nominally so that consumers could specify interfaces which anyone is free to satisfy. That the consumer owns the interface (packages shouldn't export interfaces for concretes they implement) is a pretty core tenet, and goes hand in hand with good dependency injection (IoC). DI frameworks are extremely rare (and IME even more painful to use), because injecting your dependencies explicitly is straightforward. But injected they should be.
- azth 5y agoBecause golang doesn't have constructors, you're forced to implement functions that mimic them yourself. And the language still doesn't prevent you from directly instantiating the struct yourself, meaning it is always possible to bypass the "constructor functions". This is quite terrible and opens up your code to errors. Furthermore, DI frameworks also usually have lifecycle management, which is quite handy in many cases.
- twodave 5y agoFine, but that applies to even data structures and other domain types, which even in a more classically-OO language you wouldn’t pipe through a DI framework. I think DI as a code organization concept is great, but if I have to write a factory for every struct anyway then it’s not any harder to simply use those as a rule and define module boundaries sensibly as a way to determine which code should be using new vs the factory methods. You have a good point wrt lifecycle management, but I feel like that’s actually a separate class of problem.
- cfors 5y agoAgree. I really can only imagine this being useful for an organization that publishes dozens of different libraries that a "product team" needs to use such as logging, database access, secret managers, etc. At that point, speaking the common language of a DI framework might be easier. For example, rather than have to read the GoDoc for every single constructor i'm supposed to use, I can just see how to use my DI framework to set up this client library and move on with my life. That being said, DI always strikes me as a layer of abstraction that I don't need in my day to day. But I don't work somewhere at Google/Uber scale so YMMV.
- cle 5y agoThere's nothing special about DI frameworks there. If a client library has some sane defaults preferred by the devs, then call a constructor that sets the defaults for you. You don't need DI for that. IME at tech megacorps, DI just obfuscates and distracts, shifting the focus onto understanding the accidental complexity it introduces instead of dealing with the intrinsic complexity of the dependency relationships.
- tasubotadas 5y ago>What does dependency injection give you that a simple combination of Singletons, Constructors, and Factories doesn't? You don't need to create a "simple combination" of Singletons, Constructors, and Factories.
- BobbyJo 5y agoDon't you? In Java I still had to create the Singleton/Constructor/Factory etc. and register it with the framework as a provider of that type.
- mkdirp 5y ago> What does dependency injection give you that a simple combination of Singletons, Constructors, and Factories doesn't? Easy refactoring of an interface/constructor? I've been using go for a while, and I decided to follow the advise of not using a DI for my project. Every time I refactor a constructor, it is a fun hunt to make the same changes everywhere I'm using that constructor.
- bbkane 5y agoDoesn't the compiler tell you exactly what needs to change?
- marvinblum 5y agoOr the IDE. GoLand from JetBrains is very helpful there.
- mkdirp 5y agoIt does, but having to go through every single error to fix the issues isn't that easy depending on the number of dependants.
- BobbyJo 5y agoThat's true. However, the decoupling that occurs when refactoring one and not the other creates two different code structures, often with different levels of abstraction. I saw the same thing happening with a combination of react and redux, an it made debugging weird behaviors really, really, hard.
- tadfisher 5y agoThat's exactly what a Factory is for; you defer construction and pass around an object that knows how to create an instance. Then you're hunting at the root of your call tree to swap out a Factory instead of throughout your codebase to change a constructor call. This is also what DI amounts to in practice. Frameworks abstract over it in the name of DRY, but at the same time introduce all the downsides of frameworks.
- 5y ago
- gefhfffh 5y agoPlease don't confuse DI with DI containers. With DI you still have all the responsibility.
- lr4444lr 5y agoJust come out and say it: DI is an anti-pattern. No implementation of it that I'd ever use was doable without a good config file schema, and at that point I have to ask: why not just have a declarative build system in the first place as the modern generation of Devops tools does? DI just burdens and litters code unnecessarily with awareness of build files.
- isbvhodnvemrwvn 5y agoYou, as many people here, are again mistaking dependency injection with dependency injection containers. You don't need containers for dependency injection, most codebases can just wire everything by hand without any problem.
- lr4444lr 5y agoWhat's an example of what you're talking about? Because the delegator pattern is not CI, and that's the only thing that's coming to mind that you might mean.
- akshayshah 5y agoFx author (in part) here - replied in a separate comment. I mostly agree with you, but DI offers some ecosystem-wide benefits that may be useful in some environments.
- likeabbas 5y agoSuch as?
- awill88 5y agoI want to say thanks to your team for open sourcing this library so the community can discuss. It’s ambitious and to me feels like a right size approach to the problem, for all the heartache around DI, it seems like it’s different strokes for different folks but that doesn’t mean we should all be taking a collective shit on the engineers who are trying their best to provide a way to organize service complexity strategically. Well done.
- tonfreed 5y agoI feel the same way. IoC is a great pattern, but DI frameworks that try to magically sort out dependencies are just overkill especially in go imho
- catlifeonmars 5y agoI mostly agree. I think there are two cases where using a DI framework make sense: 1. Complex lifecycle management, maybe. For example say you need to restart a set of go routines after loading a new configuration, without killing the process. I’m on the fence about this one. 2. When there is a combinatorially large number of components that need to be combined arbitrarily at runtime. The only examples I’ve seen for this in the wild are games and simulations using an ECS (entity-component-system) and queries to discover components that fit a certain criteria.