TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Dependency injection in Go with Uber-go/fx

57 pointsby ekoabout 3 years ago

17 comments

osclartoabout 3 years ago
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.
评论 #30489674 未加载
评论 #30490221 未加载
评论 #30491201 未加载
评论 #30491912 未加载
BobbyJoabout 3 years ago
I&#x27;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.<p>What does dependency injection give you that a simple combination of Singletons, Constructors, and Factories doesn&#x27;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 redux does for state in JavaScript. It make things easier because it takes away some responsibility, but, in my eyes, that responsibility is an important one, and ignoring it makes code very hard to reason about.
评论 #30488377 未加载
评论 #30488560 未加载
评论 #30488399 未加载
评论 #30488673 未加载
评论 #30488442 未加载
评论 #30500067 未加载
评论 #30490362 未加载
评论 #30493131 未加载
评论 #30489074 未加载
评论 #30488909 未加载
评论 #30488484 未加载
sidllsabout 3 years ago
&quot;Dependency Injection&quot; <i>should</i> be just shorthand jargon for &quot;pass a pointer&#x2F;reference to the dependency into the constructor&quot;.<p>Unfortunately, thanks to enterprisey-OO zealotry, it&#x27;s become a terrible monstrosity of frameworks, obfuscation-by-configurable-injection, and other terrible practices.<p>Every single application I&#x27;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.<p>And this particular framework looks like it has all the markings of making any go application worse.
评论 #30490911 未加载
评论 #30490056 未加载
jen20about 3 years ago
This is the exact kind of thing that makes working in Java or .NET codebases a complete misery.<p>Application wireup should be explicit, and if that results in “too much” code it means (in most cases) that the design is too complex.
dangoorabout 3 years ago
We at Khan Academy are planning a blog post soon about how we&#x27;ve been approaching dependency injection in Go. I touched upon this in my GopherCon talk last year[1]. I like the system because it&#x27;s pretty straightforward and builds upon Go&#x27;s context with a bit of reflection:<p>[1]: <a href="https:&#x2F;&#x2F;youtu.be&#x2F;MysHL0XYJeA?t=680" rel="nofollow">https:&#x2F;&#x2F;youtu.be&#x2F;MysHL0XYJeA?t=680</a><p><pre><code> var ktx interface { kacontext.Base log.KAContext datastore.KAContext gqlclient.KAContext web.AuthedServiceContext web.AuthedUserContext } = kacontext.Upgrade(ctx) </code></pre> With this approach, you ask for the just the interfaces you need from the context and you have statically typed access to those resources.<p>I expect the blog post will be live within a couple of weeks (but haven&#x27;t seen a draft yet, so no guarantees): <a href="https:&#x2F;&#x2F;blog.khanacademy.org&#x2F;engineering" rel="nofollow">https:&#x2F;&#x2F;blog.khanacademy.org&#x2F;engineering</a>
评论 #30491269 未加载
sneakabout 3 years ago
I&#x27;d like someone who knows more about software engineering than I do to tell me why I&#x27;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.<p>If those struct members are typed to interfaces and not types, then it&#x27;s just as testable, too, because you can drop in mocks as required.<p>What am I missing? This just seems like a way of obfuscating the fact that, in any modern program, we&#x27;re going to need 3-20 &quot;global variables&quot; that aren&#x27;t actually global global (but in practice are singletons in the process).
评论 #30489236 未加载
评论 #30489536 未加载
评论 #30496170 未加载
评论 #30489116 未加载
pbiswalabout 3 years ago
For a slightly different take on this problem, check out Wire (<a href="https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;wire" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;wire</a>).
评论 #30489159 未加载
mgrundabout 3 years ago
Full disclaimer: Uber employee using fx daily as well as in hobby projects. Post reflect my personal opinion and is not related to Uber.<p>It really does work really well in practice:<p>- It pretty simple and lightweight so it’s blazingly fast even though it happens at runtime (in contrast to e.g. the Java DI frameworks I’ve seen)<p>- The module concept is extremely powerful to make modules that plug in with zero effort<p>- Modules have a lot of autonomy (unlike wire, as I understand it - I have no personal experience with it), like being able to do things at various stages of the application lifecycle (startup, shutdown hooks), collaboratively populate dependency groups (e.g. implementing handlers or middlewares independently and injecting them separately using the grouping mechanism), optional dependencies<p>Once you have a nice standard library of common modules (this is really crucial for it to work well IMO), it’s a huge speedup to make a high-quality service. My biggest issue with it is that it doesn’t match structs with interfaces, so you effectively end up depending on structs&#x2F;pointers or returning interfaces.
评论 #30494598 未加载
akshayshahabout 3 years ago
TL;DR: I played a fairly large role in writing this package, and I wouldn’t use it outside Uber’s environment at that time (thousands of engineers, thousands of microservices, tens of thousands of Go repositories).<p>At the time we wrote Fx, Uber had ~1500 engineers writing Go. The company had 25 million lines of Go, spread across more than a thousand microservices and an unknown number of shared libraries (likely hundreds, perhaps as many as a thousand). Nearly every project was in a separate git repository, with effectively no tools to make large cross-repository refactorings. As an engineering organization, we struggled to make relatively simple cross-cutting changes.<p>For example, we spent years rolling out distributed tracing. The actual change required was simple: upgrade all your dependencies to something recent-ish, add the tracing library, construct a tracer in main (or something main-adjacent), use the tracer to construct an RPC interceptor, and add the interceptor to your API server. All in, we&#x27;re talking about ~20 lines of code and a dependency upgrade. It took multiple TPMs, spreadsheets, quarterly planning, and several high-level edicts to get this mostly done.<p>Why were changes so painful? At root, because nobody cared much about most of the Go repositories. From the perspective of the teams who nominally owned the code (often after several reorganizations over the years), the code worked fine and solved the business purpose - why invest time in changing anything? On the ground, changes were painful. Go&#x27;s simplicity makes semantic versioning _very_ restrictive, so trying to pull in a year&#x27;s worth of dependency updates often produced a variety of breakages. (Keep in mind that many of these libraries were used only in a handful of projects and weren&#x27;t particularly carefully designed or maintained.) Taking on all this pain to change 20 lines of code in main was a difficult sell.<p>Fx codified some basic back-compat best practices (if you&#x27;re paranoid) - mostly param and result structs, so constructors have more flexibility to add inputs and outputs. Fx also made most of these problems a negotiation directly between library authors, leaving the microservice team out of the picture: the &quot;standard Uber stuff&quot; package provides a distributed tracer, and the &quot;RPC stuff&quot; package takes an _optional_ tracer and installs the appropriate interceptor. No changes to main or application logic necessary, just a dependency update (which is hopefully safer, since more libraries are forced to follow better semver practices). The reflection-based wiring came with lots of magic and downsides, but the tradeoff was worth it across the engineering organization - it made us _overall_ more able to change our own systems.<p>Bluntly, IMO Fx made individual codebases less understandable (especially codebases carefully maintained by engineers who like Go). It made the whole company&#x27;s code more maintainable. The bulk of the Go engineers at the company agreed (the developer experience org tracked NPS, which went from double-digit negative to +40ish).<p>In the years since Fx, I left Uber and the company has moved most of their Go to a monorepo. I&#x27;m not sure what the current cost&#x2F;benefit tradeoff of this approach is.
jmyeetabout 3 years ago
Dependency injection really took root in Java. The reason is actually because if a design flaw: lack of duck typing combined with the ability to specify concrete types in Method signatures.<p>Go doesn’t really have this problem so I’m not convinced it needs DI at all.<p>C++ doesn’t really have much DI mindshare because it has templates (and macros).<p>Goice (Guice for Go) anyone?
kcartlidgeabout 3 years ago
I started off decades ago with stuff like Delphi, PHP, and Python, all without DI. About 2001 I started with C# and I found properly implemented DI in .Net to be a killer feature.<p>However I loved it so much that I then wrote my own Node DI package (property and constructor injection). It didn&#x27;t take long before I abandoned the idea - Node doesn&#x27;t really fit with DI.<p>And I feel the same about Go. Some languages (eg C#, Java) work amazing with DI. For some others (eg Node, Go) it simply feels <i>wrong</i>. I can&#x27;t put my finger on why, but reading the sample Go code in the original article makes me feel how I do when (in film) I see a human body with a limb bent to an unnatural angle.<p>Just to clarify I&#x27;m all up for well designed IOC with Node and Go, I&#x27;m just unconvinced it should be done with DI.
lkxijlewlfabout 3 years ago
Oh, please no. Just stop already. We don&#x27;t need the enterprisification of every fucking language.
jmullabout 3 years ago
Maybe it&#x27;s just my bad luck, but the projects I&#x27;ve seen from the inside where DI was used, it all turned into a dogawful blob of spaghetti code.<p>It was OK -- quite good, really -- in small projects... but of course pretty much any organizing principle is workable in small projects. Good organization needs to scale up.<p>I&#x27;m not quite ready to write it off.<p>For one, those large projects used a framework. Perhaps the lack of friction helped lead to thoughtless injection.<p>And, of course, no organization scheme can prevent the spaghetti when the project and its leadership are disorganized.<p>So I&#x27;m not quite ready to write it off, but I&#x27;m awfully skeptical. And it certainly doesn&#x27;t seem necessary.
JulianMorrisonabout 3 years ago
Given that Go modules can depend on private interfaces that specify only the methods they need, dependency injection of the pass-dependencies-to-the-constructor style seems almost built in. Not automated as such, but easy.
评论 #30490696 未加载
awill88about 3 years ago
I think we should also comment on the quality of the framework. I use a home grown approach too. It doesn’t mean I’m not hoping for something to come along and disrupt (for the better) my approach for the “right” abstraction.<p>That’s what is missing from the conversation: do the abstractions seem justified based on the problems it claims to solve.<p>Who knows, it could be as influential as jquery was for web development in 2006 (I’m exaggerating of course).<p>I just find the tone is generally dismissive and that robs viewers the chance to evaluate the tool within the problem space: DI injection for Go.
tonfreedabout 3 years ago
This feels unnecessarily complex. I fell in love with Go after years of dealing with Spring&#x27;s DI, and I haven&#x27;t found a situation since where dependency injection would have made my life any easier.<p>I dunno, maybe it&#x27;d be more useful for a more generic framework but I wouldn&#x27;t use this in any of my code.
armitronabout 3 years ago
This looks absolutely terrible and I would never accept it in any code review.
评论 #30494378 未加载