Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've never been convinced by DI frameworks. I've always enjoyed the fact that the Go ecosystem leans away from them and I would hope things stay that way. In my experience they just obfuscate what should be a straightforward, explicit process of setting up your app in main. The less magic happening there the better.



I have (and probably will) never voluntarily use a DI framework in any language. There's zero downside to manually doing it. It's explicit, incredibly easy, and you can easily trace backward to see how the program is constructed.


On the same note, I could never really get on with Aspect Oriented Programming. Coming from Java world, I got tired of seeing annotations everywhere and understanding what magic is going on. I like simple and straightforward languages.


You say this now, but I've had to work on 5000 line (literally, 5k lines) classes in legacy code where there are a huge number of dependencies injected manually because the class is doing initialization for a huge number of components. You could argue that this was bad design but I'm sure it didn't start out like that, but just accumulated cruft over time and was too dangerous to refactor. (if prod went down it was at least a few hundred $k down the drain). DI makes it much simpler to wire things like this up without making mistakes like accidentally initializing the wrong class implementation, etc. In polymorphism heavy situations it reduces cognitive complexity a lot.


Dependency Injection frameworks definitely seem like one of those technologies that primarily exists to allow people to get away with bad designs, rather than making it easier to create good designs.


5000 lines doesn't tell anything important. I preferred a well organize 5000 lines than 250 files of 20 lines spread randomly in various directories.

If it's 5000 lines and messy it is indeed a problem, but only because it's messy.


This is pretty much what I don't get. DI by construction is trivial and has all of the benefits of a DI framework. DI frameworks just let you move some things around, which is mostly confusing.


As someone who's liked using DI frameworks, I'm curious: if you do it manually, as your codebase gets large, doesn't it get harder to "plumb" a new object that needs to get used somewhere at a deep level? This seems like it'd get more unwieldy when refactoring.

I've never worked in a large codebase that did this manually so I'm not sure what it looks like. The large codebases I've seen that don't use DI have used something like a service locator, singletons, or constructed everything where it was needed (and used extensive mocking framework functionality for testing).


All object creation is in one place - main. So no, I should never have to go deep anywhere.


This is my take as well. Plus, if you are plumbing something that deep, the odds that your design is total shit is approaching 100%.

Manual DI reveals problems like this way earlier.

DI frameworks, IMO, are some of the most useless around. Solution seeking a problem.


I had the same thought. This looks over engineered and much harder to read than explicitly passing dependencies.


Not just that, but I don't understand why users would be so eager to kill type safety in their applications. If i'm understanding, these injection methods are totally type-unsafe and construction errors are deferred until runtime?

https://pkg.go.dev/go.uber.org/fx#Provide


I've used this framework. The exceptions being deferred until runtime were really frustrating.

If you really want to use DI in golang, for some reason, wire[1] at least still gives you type safety and compile-time failures.

1. https://github.com/google/wire


I currently have to deal with DI at work. It's a pain. When everything works, it's nice to be able to just ask for something and have it with no extra work, but good luck when things go wrong. If the DI library throws an exception, good luck figuring out what you actually need to do to resolve it. Often it's because there's a cycle in the dependency graph, but the exceptions never give you any information about what the graph looks like. It also makes it stupidly hard to track down the sources of bugs. Figuring out what classes are being used to satisfy the dozen interfaces your class asks for requires either inspecting variables in the debugger or an annoying amount of digging.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: