1
lurch
3y

How do folks feel about IoC/DI?

I used Spring and Angular for the first few years of my career, so it seemed like it was a mandatory pattern of a framework and my team would never deploy an app that couldn't use it (even if it was just a Lamda or something, we found smaller DI libraries). Now I work in Express and React, and I look back and feel that those patterns required me to write more code, created more complexity, and wasn't any easier to read or understand, and was way more bug prone, and debugging the injection pipeline itself was effectively not possible.

I guess I'm wondering: what do people feel that it buys them?

Comments
  • 0
    It provides a huge advantage when it comes to unit testing simply because you can quickly mock everything you don't want to test.

    It certainly adds some complexity to the code (although not a lot, in C# at least) but I feel it makes the code less buggy rather than more as you can much quicker locate what component is misbehaving in large, interconnected projects.
  • 0
    You can do DI in React though, although IMO it's easier to expose as much functionality as possible with optional callback props.
  • 0
    In JS/TS I often do a really light variant of DI where my modules take functions returning their dependencies as arguments. Constructors aren't a good choice because a) they assume that you want to create a new instance and b) OOP in JavaScript is broken.
  • 0
    Applying this to React would mean that your components are essentially HOCs wrapping HOCs of their dependencies.
  • 0
    This sounds excessive, but eg. if your object may be able to provide extra information to the factory or the default factory of the target object takes extra arguments, you can wire these in a very intuitive manner using several tiny functions.
  • 0
    @ostream Which is especially strange because Java back when the design pattern thing was invented was just about the most painful environment to implement DI in, and it required a set of very inobvious assumptions regarding the types of injected things and the conditions where they would be needed. Passing factories as parameters is trivial and beautiful in languages that have lambda functions and don't depend as much on classes.
  • 0
    @kwilliams I do get the generally accessibility for unit tests because it becomes easier to mock particular dependencies for classes so tha dependant gets exactly what they need.

    I'd agree with @ostream because when you're in JavaScript-land, Jest allows you to actually replace import content which is just as useful without the weight/complexity of DI to your application. But I don't see why you couldn't just do a provider like this:

    `export const serviceProvider = environment === "mock" ? mockProvider : realProvider;`

    Tree shaking cleans the mockProvider from your build and I know you shouldn't add code in src to support testing, but it sounds like that's what DI is doing anyways.

    As for @lbfalvy ( don't get why you'd want DI in React (or any framework that doesn't require it to work, like Angular which breaks without it), reads like a lot of extra complexity, adding DI to help you debug problems caused by DI. I'd rather just use context for state and just import services.
  • 0
    @lurch I was more talking about JS or TS in general, but DI has other benefits than testing. For example it forces you to actually define an interface and follow it, which is valuable for a lot of people who got used to dynamic typing.
  • 1
    @lbfalvy I would say that's the nice thing about TS in general with building mocks is that you're not going to compile if you claim to implement an interface that you're not implementing. And these days, React + TS work pretty solid out of the box. I do wish they just mandated it though, like Angular. Even if they mandated it with a really light TSConfig that allows you to basically just write JS in a TS file for those who don't want to be forced into it.
  • 0
    @lurch This way where typings exist they are expected to work in very strict tsconfigs. If they mandated typings for a loose tsconfig, clean, strict typings would not exist for lots of components and there would be even less motivation in the userbase to write them.
  • 1
    I agree, but I feel like it would be better than the current default (which I consider CRA to be the default) of no types.
  • 0
    I think you should use it, its one the things that leads to better design.
    It’s massively helpful.

    Bit surprised you thought using it caused you more code though. Apart from registering with an IOC container what more code is there?
  • 0
    @TrevorTheRat I don't see how it couldn't cause more code. You have to define the IoC container (except in languages with package scanning like Java), and then import, and then define your injection. All of that code being out of your control, rather than just importing the service you want and using it. I still haven't really heard the value besides ease of defining mocks for tests, but imo that defeats the rule of "don't add testing code to src," but defining your architecture to support it.

    This all being said, I also just kind of hate OOP and feel that it's associated "patterns" are really the ways that you manage the shortcomings of OOP as an architecture.
  • 0
    @lurch fair enough, I’ve tended to do most config by convention so it hasn’t caused me to create much more code.

    It helps with testing bit it’s also a good way of injecting strategies and just decoupling things.
    Guess if you don’t like OO you’re never going to like DI
  • 0
    @TrevorTheRat I despise OO and while I don't like DI containers, I like the homemade semi-organized version of IoC that I described above so much that I need a reason to exclude it from a project.
Add Comment