4 ms·
Dependency injection frameworks are solutions that no one needs to solve their problem. It appears everywhere because everyone knows about the solution.
by knuthsat 6y ago
Dependency injection frameworks are solutions that no one needs to solve their problem.
It appears everywhere because everyone knows about the solution.
- darkhorse13 6y agoThis is peak HN.
- ipnon 6y agoIt's been downhill for 14 years: https://news.ycombinator.com/item?id=9224 https://news.ycombinator.com/item?id=9224
- beaconstudios 6y agoDI frameworks solve problems caused by OOP (having to assemble a service object graph). So really, they're solving a problem that programmers created for themselves.
- faeyanpiraat 6y agoConcatenating all the functions flat into one file can work for quick prototypes, but when you reach 1-2k LOC, you need to start abstracting things to keep it maintainable. Or have I missed your point?
- beaconstudios 6y agoThat's very true, but OOP just isn't a very good method of abstraction. Keeping data and code separate permits much more flexibility.
- snovv_crash 6y agoIt all depends how much state you need to manage, and how persistent it needs to be. What works in an image processing pipeline doesn't work in a web server, and what works there doesn't work in an autopilot.
- beaconstudios 6y agoI'm usually not one to talk in absolutes, but I'm near certain that procedural or functional programming beat OOP every time. The idea of hidden/encapsulated state just hurts flexibility - where OOP shines is when you have an army of junior developers and you want to encapsulate state and provide rigid interfaces so that mistakes are harder to make.
- snovv_crash 6y agoSome amount of hiding state makes APIs easier to use though. Keeping data structures coherent, for example, means you need to only interact with them through the provided interfaces. This also means that you could internally change the data structures (eg. from deque to ring buffer) and not expose the implementation details to the outside world, causing downstream breakages. What you describe makes sense for small components built by a small, tightly knit and highly skilled team. The issue is that at some point the software grows enough that you can't hold the whole thing in your head at once, or you need to make it reusable to external developers.
- EdwardDiego 6y agoDependency injection is a good pattern from a testability POV. Trying to test something that instantiates its own dependencies is frigging hard. But with DI, a service needs to talk to the database? I can either spin up an embedded DB, or, I can pass it a mock DAO to verify it is using the data layer as expected. (And of course, if there's a real DAO, I'm most likely going to write an integration test that does involve an embedded DB, just to be sure that our Postgres flavoured SQL works. And surprisingly, spinning up an embedded PG isn't that slow. And certainly better than trying to convince HSQL that it's Postgres.) That said, something I've spent years trying to beat into my fellow Java developers is that the best form of dependency injection is... constructor args. Make your dependencies constructor args, then you can "inject" whatever the hell you like that conforms to the expected type. You can stick @Autowired on the constructor if you like, go nuts. But even without, well hell, you might not actually need that DI framework, and it's still in a testable space. As soon as someone starts sticking @Autowired on class fields though, you're fucked. You're annotating JUnit tests with Spring crap, or using Mockito combined with some reflection libraries... ...it's all downhill from there. But! None of that cruft means that the DI pattern is bad. It's just that people have done very bad things in it's name.
- knuthsat 6y ago> Make your dependencies constructor args, then you can "inject" whatever the hell you like that conforms to the expected type. You can stick @Autowired on the constructor if you like, go nuts. But even without, well hell, you might not actually need that DI framework, and it's still in a testable space. Yes, this is exactly what I mean, the amount of wrong stuff that is in the constructor makes me believe DI is a solution for something else. Infinite amount of times have I encountered stuff in the constructor that shouldn't be there. Object A has a constructor with a bunch of dependencies, one of them is Object B. The proper way is for Object B to use object A instead. Blindly injecting everywhere is my problem with DI. Without these frameworks one would see that dependencies flow in a different direction if proper interfaces are defined. For example, React Context and useEffect hook is implicit DI yet people have no idea it's DI and I see codebases using React + DI framework instead. The only DI magic is the topological sort of dependencies and automatic construction. That stuff is 20 lines of additional code so that React.Context and useEffect work the same way.