<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tetsuro Mikami</title>
    <description>The latest articles on DEV Community by Tetsuro Mikami (@mickamy).</description>
    <link>https://dev.to/mickamy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F718743%2F5857c080-40ea-42de-a60f-32b5841f7f5f.jpeg</url>
      <title>DEV Community: Tetsuro Mikami</title>
      <link>https://dev.to/mickamy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mickamy"/>
    <language>en</language>
    <item>
      <title>Dependency Injection in Go: How Much Is Enough for Web APIs?</title>
      <dc:creator>Tetsuro Mikami</dc:creator>
      <pubDate>Wed, 24 Dec 2025 06:50:57 +0000</pubDate>
      <link>https://dev.to/mickamy/dependency-injection-in-go-how-much-is-enough-for-web-apis-hp7</link>
      <guid>https://dev.to/mickamy/dependency-injection-in-go-how-much-is-enough-for-web-apis-hp7</guid>
      <description>&lt;p&gt;Dependency Injection (DI) in Go often sparks debates that feel disproportionate to the actual needs of most web APIs. Discussions quickly escalate to containers, lifecycles, scopes, and dynamic resolution—despite the fact that many services have a simple, static dependency graph resolved once at startup.&lt;/p&gt;

&lt;p&gt;This article argues a straightforward position:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a typical web API, &lt;strong&gt;compile-time dependency resolution is enough&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From there, we’ll look at why runtime DI frameworks tend to be overkill, why static approaches like wire already cover most needs, and why a field-tag-based generator can simplify things even further.&lt;/p&gt;




&lt;h2&gt;
  
  
  What most web APIs actually need
&lt;/h2&gt;

&lt;p&gt;If we strip away abstractions, a large percentage of Go web APIs share the same characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stateless request handling&lt;/li&gt;
&lt;li&gt;Dependencies resolved &lt;strong&gt;once at startup&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A mostly tree-shaped dependency graph&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;config → database → repository → service → handler&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;No runtime rebinding of implementations&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In this environment, DI is not about flexibility at runtime. It’s about &lt;strong&gt;wiring correctness and maintainability&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Runtime DI frameworks: powerful, but usually unnecessary
&lt;/h2&gt;

&lt;p&gt;Frameworks such as &lt;strong&gt;fx / dig&lt;/strong&gt; or generics-based containers like &lt;strong&gt;do&lt;/strong&gt; shine when your application behaves like a framework itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modules register themselves dynamically&lt;/li&gt;
&lt;li&gt;lifecycle hooks (start/stop) matter&lt;/li&gt;
&lt;li&gt;plugins or optional components are loaded at runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For typical web APIs, however, these features often come with downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;additional APIs to learn and remember&lt;/li&gt;
&lt;li&gt;runtime error surfaces for what is fundamentally static wiring&lt;/li&gt;
&lt;li&gt;harder-to-follow control flow during startup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When dependencies are fixed and known ahead of time, &lt;strong&gt;runtime DI solves a problem you don’t really have&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Static wiring is already enough
&lt;/h2&gt;

&lt;p&gt;If dependencies are static, resolving them at compile time or generation time is a natural fit.&lt;/p&gt;

&lt;p&gt;This is where tools like &lt;strong&gt;wire&lt;/strong&gt; enter the picture. They provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compile-time dependency resolution&lt;/li&gt;
&lt;li&gt;no runtime container&lt;/li&gt;
&lt;li&gt;plain Go code as output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a normal web API, this model is already sufficient. You get safety, predictability, and zero runtime DI overhead.&lt;/p&gt;

&lt;p&gt;So far, the conclusion is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For most web APIs, static DI is enough.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where wire starts to feel heavy
&lt;/h2&gt;

&lt;p&gt;Wire’s design emphasizes explicitness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider functions&lt;/li&gt;
&lt;li&gt;provider sets&lt;/li&gt;
&lt;li&gt;injector functions per root&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This explicitness can be valuable in some organizational contexts. But in day-to-day API development, it often turns into maintenance overhead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider sets need constant updates as the graph evolves&lt;/li&gt;
&lt;li&gt;DI-specific files grow alongside business code&lt;/li&gt;
&lt;li&gt;the wiring itself becomes something developers have to reason about&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The static model is right—but the &lt;em&gt;amount of ceremony&lt;/em&gt; is not always justified.&lt;/p&gt;




&lt;h2&gt;
  
  
  A lighter static model: field-tag-based generation
&lt;/h2&gt;

&lt;p&gt;If your goal is still static wiring and generated constructors, but with less DI-specific code, a simpler model works well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;declare what you want in a container struct&lt;/li&gt;
&lt;li&gt;let a generator resolve the graph&lt;/li&gt;
&lt;li&gt;emit plain Go constructors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserHandler&lt;/span&gt; &lt;span class="s"&gt;`inject:""`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated code is just Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;svc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No runtime container. No provider sets. No reflection.&lt;/p&gt;

&lt;p&gt;This is the idea behind &lt;strong&gt;injector&lt;/strong&gt;, a field-tag-only DI code generator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mickamy/injector" rel="noopener noreferrer"&gt;https://github.com/mickamy/injector&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The link is intentionally placed here, after the argument is established, rather than as an upfront pitch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Is there still a place for wire?
&lt;/h2&gt;

&lt;p&gt;Wire can still make sense when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider sets are treated as a &lt;strong&gt;public composition API&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;explicit wiring boundaries are a deliberate design goal&lt;/li&gt;
&lt;li&gt;DI graphs are reviewed and curated as first-class artifacts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, wire’s strengths are organizational and process-driven.&lt;/p&gt;

&lt;p&gt;If your project doesn’t need that level of explicitness, wire becomes harder to justify.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Runtime DI (fx/dig, do)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Powerful, but often overkill for standard web APIs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Static DI (wire)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sufficient for most APIs, but verbose&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Static + minimal (injector)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same guarantees, less ceremony&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For the common case—stateless web APIs with stable dependency graphs—&lt;strong&gt;static wiring is enough&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And if you can keep that wiring static &lt;em&gt;and&lt;/em&gt; reduce the amount of DI-specific code you maintain, that’s an even better outcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Dependency Injection doesn’t need to be a framework-level decision for most Go web APIs. It’s a startup detail.&lt;/p&gt;

&lt;p&gt;Resolve dependencies once. Generate plain Go code. Keep the wiring boring.&lt;/p&gt;

&lt;p&gt;If wire already feels sufficient—but a bit heavy—the field-tag-based approach is a natural next step.&lt;/p&gt;

&lt;p&gt;In that sense, &lt;strong&gt;injector is not a radical alternative&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s simply asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If static DI is enough… why not make it simpler?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Dependency Injection in Go, Reduced to Field Tags</title>
      <dc:creator>Tetsuro Mikami</dc:creator>
      <pubDate>Thu, 18 Dec 2025 01:47:08 +0000</pubDate>
      <link>https://dev.to/mickamy/dependency-injection-in-go-reduced-to-field-tags-4h1o</link>
      <guid>https://dev.to/mickamy/dependency-injection-in-go-reduced-to-field-tags-4h1o</guid>
      <description>&lt;p&gt;Dependency Injection (DI) in Go often feels heavier than it should be.&lt;/p&gt;

&lt;p&gt;Once a project grows, you start seeing patterns like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large provider sets&lt;/li&gt;
&lt;li&gt;Dedicated wiring files (for tools like &lt;code&gt;wire&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Initialization order that humans must carefully maintain&lt;/li&gt;
&lt;li&gt;DI-specific code spreading across the codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time, the amount of code written &lt;em&gt;for DI itself&lt;/em&gt; can rival the actual business logic.&lt;/p&gt;

&lt;p&gt;I wanted to see how far DI could be simplified in Go.&lt;/p&gt;

&lt;p&gt;That experiment became &lt;strong&gt;injector&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Idea
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;All dependency injection is declared using struct field tags.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nothing else.&lt;/p&gt;

&lt;p&gt;No provider sets.&lt;br&gt;
No DSL.&lt;br&gt;
No runtime reflection.&lt;/p&gt;

&lt;p&gt;The container declares &lt;em&gt;what&lt;/em&gt; is injected.&lt;br&gt;
Providers declare &lt;em&gt;how&lt;/em&gt; values are constructed.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Container
&lt;/h2&gt;

&lt;p&gt;A container is just a struct. Fields marked with the &lt;code&gt;inject&lt;/code&gt; tag are managed by injector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="s"&gt;`inject:""`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;inject&lt;/code&gt; tag is intentionally minimal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is a marker only&lt;/li&gt;
&lt;li&gt;It carries no configuration by default&lt;/li&gt;
&lt;li&gt;It simply means “this field is injected by injector”&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Providers
&lt;/h2&gt;

&lt;p&gt;A provider is any top-level function that returns a value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewUserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="n"&gt;infra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function must be top-level (no receiver)&lt;/li&gt;
&lt;li&gt;Parameters are dependencies&lt;/li&gt;
&lt;li&gt;The return value is the provided type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Injector discovers providers automatically via static analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Generated Code
&lt;/h2&gt;

&lt;p&gt;Running the generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;injector generate ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Produces plain Go code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewDatabaseConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no runtime magic.&lt;br&gt;
The generated code is readable, debuggable, and type-safe.&lt;/p&gt;


&lt;h2&gt;
  
  
  Interface-First by Default
&lt;/h2&gt;

&lt;p&gt;Injector works naturally with interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewUserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="n"&gt;infra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container exposes only interfaces.&lt;br&gt;
Concrete implementations remain private.&lt;/p&gt;

&lt;p&gt;This keeps application boundaries clean without adding DI-specific abstractions.&lt;/p&gt;


&lt;h2&gt;
  
  
  Handling Multiple Providers
&lt;/h2&gt;

&lt;p&gt;If multiple providers return the same type, injector requires an explicit choice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DatabaseConfig&lt;/span&gt; &lt;span class="s"&gt;`inject:"provider:NewPrimaryDatabaseConfig"`&lt;/span&gt;
    &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="s"&gt;`inject`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A blank (&lt;code&gt;_&lt;/code&gt;) field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does not expose the dependency&lt;/li&gt;
&lt;li&gt;Declares a provider override&lt;/li&gt;
&lt;li&gt;Applies globally within the container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Provider selection remains centralized and explicit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Field Tags?
&lt;/h2&gt;

&lt;p&gt;Go structs already represent dependency lists.&lt;/p&gt;

&lt;p&gt;Adding extra configuration layers often makes DI harder to reason about, not easier.&lt;/p&gt;

&lt;p&gt;By limiting DI declarations to field tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependencies are visible at a glance&lt;/li&gt;
&lt;li&gt;Configuration stays local&lt;/li&gt;
&lt;li&gt;The mental model stays small&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DI should be infrastructure, not the focus of the codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;Injector is intentionally small and opinionated.&lt;/p&gt;

&lt;p&gt;The current goal is not feature breadth, but clarity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marker-based containers&lt;/li&gt;
&lt;li&gt;Provider-based resolution&lt;/li&gt;
&lt;li&gt;Compile-time dependency graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Future ideas exist, but they can wait until real-world usage drives them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/mickamy/injector" rel="noopener noreferrer"&gt;https://github.com/mickamy/injector&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback is very welcome — especially around the design trade-offs and edge cases.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
