Live data from Hacker News

Dependency injection in Go with Uber-go/fx

vincent.composieux.fr

31–40 of 96 posts

Re: Dependency injection in Go with Uber-go/fx

#31
post #19

Earlier quoted context omitted.

How do you convince the when-to-fire-logic to act on a mock, if the torpedo implementation is not provided from outside it? I'm wondering if I have the terminology understood differently to other people, because to me, DI == IoC. DI Frameworks are build on top of the concept that dependencies will be injected, but doing it explicitly in your start-up code is the same thing to me.

No, you understand perfectly well! This is the same conversation I had with the new hire I mentioned. And as the other comment here mentioned, it's JavaScript. You simply overwrite the object method with the mock at runtime of the test, then restore it after the test finishes running. Most JS testing frameworks do this under the hood I believe, without any change in how you write your code. It's a fundamental differe…

Right. Facepalm. I kind of missed the bit where we shifted paradigms.

My personal preference would still be to be explicit, to echew secret mutable state even in the tests, but that's just me. My personal baggage makes phrases like "then restore it after the test finishes" bring me out in a cold sweat ;)

I guess I sympathise with your colleague, but I agree it's not idiomatic, and not being idiomatic is not helpful in a team.

Re: Dependency injection in Go with Uber-go/fx

#32
post #29
post #21

I'd like someone who knows more about software engineering than I do to tell me why I'd use this over some big globals-but-not-really App struct that holds all of the various dependencies of my app that I can just pass into the different parts of it so they can all access what they need. If those struct members are typed to interfaces and not types, then it's just as testable, too, because you can drop in mocks as re…

We use Uber/fx in the org I work. Took me a while to buy into it, because as you said, it doesn't seem any better than hand-written code. But after a few years I noticed fx was being adopted by more and more teams, and it reduces cross-project contribution friction, some teams started building conventions around it, and more importantly, iterating on these conventions, etc. It's become just really handy for us. This…

Same. It’s nice to publish an fx module that implements a middleware that plugs into all of the 12000+ microservices we run. One example is adding a debug/flame graph endpoint to your service- it’s a one line import into your app.

Re: Dependency injection in Go with Uber-go/fx

#33
"Dependency Injection" should be just shorthand jargon for "pass a pointer/reference to the dependency into the constructor".

Unfortunately, thanks to enterprisey-OO zealotry, it's become a terrible monstrosity of frameworks, obfuscation-by-configurable-injection, and other terrible practices.

Every single application I've worked on where DI (in practice, not theory) is in use has been fragile, hard to debug, hard to test, and hard to maintain.

And this particular framework looks like it has all the markings of making any go application worse.

Re: Dependency injection in Go with Uber-go/fx

#34
post #21

I'd like someone who knows more about software engineering than I do to tell me why I'd use this over some big globals-but-not-really App struct that holds all of the various dependencies of my app that I can just pass into the different parts of it so they can all access what they need. If those struct members are typed to interfaces and not types, then it's just as testable, too, because you can drop in mocks as re…

It's not terrible to have one big struct, but sometimes it can inhibit the reuse of components in more than one system.

When you call a function that takes this struct as an argument, how do you know which members of the struct really need to be populated? Its dependencies aren't clearly documented. (They are over-specified. It's like a function with many unused arguments.)

If a subsystem only uses some members of the struct and you want to enforce that, maybe you pass in a smaller struct, or pass the struct members as separate arguments.

This is something you'll likely have to do if you want to extract a library for other people to use. Libraries are used in multiple systems, which might or might not have their own big struct.

Re: Dependency injection in Go with Uber-go/fx

#35
post #32
post #29

Earlier quoted context omitted.

We use Uber/fx in the org I work. Took me a while to buy into it, because as you said, it doesn't seem any better than hand-written code. But after a few years I noticed fx was being adopted by more and more teams, and it reduces cross-project contribution friction, some teams started building conventions around it, and more importantly, iterating on these conventions, etc. It's become just really handy for us. This…

Same. It’s nice to publish an fx module that implements a middleware that plugs into all of the 12000+ microservices we run. One example is adding a debug/flame graph endpoint to your service- it’s a one line import into your app.

The Go convention for adding features like that is

    import _ "example.com/feature"
Á la https://pkg.go.dev/net/http/pprof

Reads a heck of a lot easier!

Re: Dependency injection in Go with Uber-go/fx

#36
post #12
post #2

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…

> 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.

Doesn't the compiler tell you exactly what needs to change?

Re: Dependency injection in Go with Uber-go/fx

#37
This is the exact kind of thing that makes working in Java or .NET codebases a complete misery.

Application wireup should be explicit, and if that results in “too much” code it means (in most cases) that the design is too complex.

Re: Dependency injection in Go with Uber-go/fx

#38

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.

Re: Dependency injection in Go with Uber-go/fx

#40
We at Khan Academy are planning a blog post soon about how we've been approaching dependency injection in Go. I touched upon this in my GopherCon talk last year[1]. I like the system because it's pretty straightforward and builds upon Go's context with a bit of reflection:

[1]: https://youtu.be/MysHL0XYJeA?t=680

    var ktx interface {
        kacontext.Base
        log.KAContext
        datastore.KAContext
        gqlclient.KAContext
        web.AuthedServiceContext
        web.AuthedUserContext
    } = kacontext.Upgrade(ctx)
With this approach, you ask for the just the interfaces you need from the context and you have statically typed access to those resources.

I expect the blog post will be live within a couple of weeks (but haven't seen a draft yet, so no guarantees): https://blog.khanacademy.org/engineering

Post reply on HN