Live data from Hacker News

The problem with dependency injection frameworks

jamesshore.com

71–80 of 92 posts

Re: The problem with dependency injection frameworks

#71
post #46

The Dependency injection pattern is just not that great in general. There are alternative patterns that are better. It is not a problem with frameworks. Think about it. If the pattern was good, then a good framework must exist. If no good framework exists then logically it is very likely that Something is wrong with the Pattern itself. Anyway the reason why DI is bad is because it's too complex. In your program, you…

DI isn't what you think it is. What you're describing is the old imperative vs OOP debate.

Re: The problem with dependency injection frameworks

#72
post #50

The alternative of wiring up your own dependencies is pretty trivial and I really prefer it. Martin Fowler calls it a Service Locator, https://martinfowler.com/articles/injection.html#UsingAServi...

FWIW a fellow who has published books on the topic calls Service Locator an anti-pattern[1]. I take no position here as usage of any pattern is contextual but it's worth a read. [1] https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Patt...

Looks like a strawman, that isn't the ServiceLocator I expect, it looks like he's writing his own DI engine.

Re: The problem with dependency injection frameworks

#73

Earlier quoted context omitted.

> I think anyone arguing for frameworks should spend some time making a serious attempt at frameworkless dependency injection. The frameworks are really doing so little for you, at occasionally horrendous cost. That is what I did, and decided a DI framework was much better. If you have a single scope, like singletons, its pretty easy to do the wiring manually. If not, then you see very quickly that your scope managem…

Passing a single "context" struct/class/whatever into everything basically solves DI. I can see using a framework for this, but it doesn't seem necessary.

Furthermore, this enables creating sub-contexts (like run this operation but with this different configuration) which is something almost impossible to do with DI frameworks.

Re: The problem with dependency injection frameworks

#74

Earlier quoted context omitted.

Passing a single "context" struct/class/whatever into everything basically solves DI. I can see using a framework for this, but it doesn't seem necessary.

Furthermore, this enables creating sub-contexts (like run this operation but with this different configuration) which is something almost impossible to do with DI frameworks.

Yeah, it's weird how such heavy frameworks often end up lacking basic features like this. That's like the first thing I'd look up how to do after the basic tutorial.

Re: The problem with dependency injection frameworks

#75
post #24

Earlier quoted context omitted.

>But these frameworks aren't magic. They're just code. "Magic" in framework parlance doesnt mean hocus pocus. It just means concealed abstraction.

Yes I’m aware. My point was it’s not that concealed once you’ve invested the time to read the docs and peek at the code of whatever framework you’re using. The time to do that is nothing compared to the time saved using these frameworks. I wasn’t sitting there thinking Harry Potter wrote Spring Boot.

Sometimes you can easily peek at this, sometimes you can't. I can see there being a good DI framework, but there's easy potential for them to be terrible. Like one of them used at my job cannot be understood from code at all (it uses special build rules) and has awful documentation. The recommended way to understand it is by copy-pasting what others have done. Once you do that, it's tolerable.

Re: The problem with dependency injection frameworks

#76

Earlier quoted context omitted.

> But these frameworks aren't magic. They're just code Some of them definitely go beyond "just code", in the sense that they actually change the normal behavior of the code. They intercept method calls, replace classes, etc. Spring is sort of famous for this: https://docs.spring.io/spring-framework/docs/3.0.0.M3/refere...

Or they use macros (e.g. in C++) to create something you can't reasonably read through.

> Or they use macros

Dark magic is still magic...

Re: The problem with dependency injection frameworks

#77
post #57
post #53

This is wrong on so many levels: > You shouldn’t need logging everywhere, for example. Your logic code should be side-effect free, and most of the rest of your code should be throwing detailed exceptions or returning errors rather than writing to the log and returning null. Being side-effect-free doesn't mean that you don't need logging to understand how the outputs were computed from inputs, when things do go wrong…

But "logging everywhere" isn't necessary to log information about the state of the system. Libraries, for example, should not have any logging, or else it should be minimal and optional. One should prefer to return errors from library code that the application code then logs, with specific relevant context and only at a point where the log message would be useful.

> Libraries, for example, should not have any logging, or else it should be minimal and optional.

You know, a year ago when log4j was having problems, a lot of people were like "why should this even exist!?" and this is exactly why.

If every single library just splats everything out to console then yes, you have a problem. But that's why logging frameworks exist - preventing a library (or more specifically a package) from splatting errors everywhere is literally a one-line change. Most of your libraries should probably run at WARN or ERROR - because their business events are not your business events.

But in a big application when something goes wrong it's super useful to turn that logging level up and see what the libraries think is going on. Jackson will usually tell you exactly why it's making the decisions it's making when it's picking deserializers or handling data. Spring or Hibernate or whatever will tell you exactly why it's making the decision it's making wiring up the dependencies and data layer and mappings.

> One should prefer to return errors from library code that the application code then logs, with specific relevant context and only at a point where the log message would be useful.

no, the "operation result wrapper class" pattern is incredibly tedious to deal with inside your program - it's one thing when it's the result of an RPC call (or HTTP service call, etc) but you absolutely do not want your operations returning a little {result : ERROR, output: null} wrapper class as a general course of business in the application.

Like yes your statement is generally true that your code should always throw exceptions that are properly scoped, that's literally table stakes here, don't let IO Exception bubble up to the top level, turn that into a RemoteServiceException or a ServiceConfigurationException etc, so that higher-level code can understand what is going on without handling 20 zillion low-level errors. That's junior coder level competence.

But don't be afraid to throw exceptions either, those are the way for higher-level processes to bail out of their processing! The Java standard library gets so crazy with IO exceptions and other low-level exceptions (I think incorrectly so, in many cases) that people get gunshy about it and get in this mindset that they have to catch everything so they don't constantly put "throws" decorators on everything. A lot of code should throw! And instantiate that higher-level exception with the low-level exception passed in so you can understand why.

Re: The problem with dependency injection frameworks

#78
post #16

I gave up on dependency injection frameworks a while ago. Now there's just some "wiring" code somewhere that wires up the components. It's small (one statement per component), trivial to write, easy to understand, and makes any kind of customisation easy (disabling whole subsystems under config, having alternative implementations for subsystems, etc), because it's just code. It's also testable! The setup code is fact…

> The setup code is factored in such a way that it's harmless to run (eg sockets aren't opened during wiring

The other side-benefit of doing this is it can become much easier to hot reload components, since you just call the Stop / Start methods of just those components.

Re: The problem with dependency injection frameworks

#79

> Furthermore, dependency injection frameworks encourage you to think in terms of globals. That’s what they inject! A single, globally-configured instance of a class. Think about it. If you one day want two different instances of an injected variable, you’ll need an impact driver to express just how screwed you are. This has all kinds of knock-on effects in terms of reducing encapsulation and separating state from be…

Yes, this guy clearly does not understand the tools involved here.

This is actually very important because injection scope can lead to program correctness errors. It is possible for DI frameworks to GC an injected class that hasn't been used for a long time, so the one you get back may not be the one you expected, or if it contains an object map it may not contain the objects you expect, etc.

https://docs.spring.io/spring-framework/docs/3.0.0.M3/refere...

Re: The problem with dependency injection frameworks

#80

Dependency Injection is just a fancy, obfuscating, name for global variables.

No. And injected classes aren't always even global, there is such a thing as a class-scoped dependency injection.

https://docs.spring.io/spring-framework/docs/3.0.0.M3/refere...

Post reply on HN