eduardo-sl/go-agent-skills

go-dependency-injection

Dependency injection in Go: constructor injection, wiring in main, avoiding global state, and when frameworks (wire, fx, dig) earn their complexity.

Vedi sorgente

Come usare

  1. Copia il comando e controlla il pacchetto prima di installarlo nel tuo ambiente agente.
  2. Controlla strumenti, credenziali e ambienti richiesti nel documento originale.
  3. Descrivi input e risultato desiderato; confronta l’output con le fonti.
npx skills add https://github.com/eduardo-sl/go-agent-skills --skill go-dependency-injection

Prima di iniziare

  • L’installazione non include abbonamenti, quote API o accesso ai file.
  • Stelle e installazioni indicano attività, non un test indipendente di qualità o sicurezza.
Documento Skill originale

Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.

Go Dependency Injection

DI in Go is a pattern, not a framework: pass dependencies to constructors, wire everything explicitly in main. Reach for a framework only when manual wiring measurably hurts.

1. Constructor Injection — the Default

go
// ✅ Good — dependencies are explicit parameters
type OrderService struct {
    repo     OrderRepository
    payments PaymentGateway
    logger   *slog.Logger
}

func NewOrderService(repo OrderRepository, payments PaymentGateway, logger *slog.Logger) *OrderService {
    return &OrderService{repo: repo, payments: payments, logger: logger}
}

// ❌ Bad — hidden dependencies reached through globals
func (s *OrderService) Place(ctx context.Context, o Order) error {
    db := database.Get()        // global singleton
    log.Printf("placing order") // global logger
    // untestable without touching process-wide state
}

Rules:

  • Accept interfaces for dependencies the service calls; return the

concrete type from the constructor.

  • Every dependency visible in the signature — if the list feels long,

the type does too much (split it), don't hide deps to shorten it.

  • Validate required deps in the constructor and return an error

(or accept a nil-safe default, e.g. logger = slog.Default()).

2. The Composition Root

All wiring lives in one place — main (or a run function it calls). Construction order is the dependency order, checked by the compiler:

go
func run(ctx context.Context, cfg Config) error {
    db, err := store.Open(ctx, cfg.DatabaseURL)
    if err != nil {
        return fmt.Errorf("open db: %w", err)
    }
    defer db.Close()

    orderRepo := store.NewOrderRepo(db)
    payments := stripe.NewGateway(cfg.StripeKey)
    logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

    orders := service.NewOrderService(orderRepo, payments, logger)
    server := handler.NewServer(cfg.Addr, orders)

    return server.ListenAndServe(ctx)
}
  • No package builds its own dependencies; it receives them.
  • No init() wiring, no package-level var DB *sql.DB.
  • Two binaries needing different wiring = two mains, same components.

3. Eliminating Global State

go
// ❌ Before — package-level singleton
var defaultClient *api.Client

func Fetch(id string) (*Item, error) {
    return defaultClient.Get(id)
}

// ✅ After — the dependency moves into a struct
type Fetcher struct {
    client *api.Client
}

func NewFetcher(c *api.Client) *Fetcher { return &Fetcher{client: c} }

func (f *Fetcher) Fetch(id string) (*Item, error) {
    return f.client.Get(id)
}

Migration path for a legacy codebase: introduce the struct, keep a deprecated package-level wrapper delegating to one instance built in main, move callers over, delete the wrapper.

Acceptable package-level state: pure constants, compiled regexps, sync.Once-guarded process singletons that hold no config.

4. Function Dependencies for Small Seams

A full interface is overkill for one function — inject the function:

go
type Service struct {
    now     func() time.Time
    genID   func() string
    publish func(ctx context.Context, e Event) error
}

// Production: Service{now: time.Now, genID: uuid.NewString, publish: bus.Publish}
// Test:       Service{now: fixedTime, genID: constID, publish: capture}

5. When Frameworks Earn Their Complexity

Manual wiring scales further than expected — a 100-line run function is still readable and compiler-checked. Consider a tool when wiring crosses hundreds of components or many teams share one binary.

ToolModelTrade-off
google/wireCompile-time code generationWiring stays plain Go and compiler-checked; adds a codegen step
uber-go/fxRuntime container + lifecycleApp lifecycle (start/stop hooks) managed; errors surface at runtime, magic in stack traces
uber-go/digRuntime container (fx's core)Same runtime trade-offs, no lifecycle layer

Decision rule: prefer manual wiring; if generation becomes necessary prefer wire (failures at compile time beat failures at startup); adopt fx only when you also want its lifecycle management and your team accepts the runtime container.

Never mix models: one composition root, one mechanism.

6. Wire Example (when chosen)

go
//go:build wireinject

func InitializeServer(cfg Config) (*handler.Server, error) {
    wire.Build(
        store.Open,
        store.NewOrderRepo,
        stripe.NewGateway,
        service.NewOrderService,
        handler.NewServer,
    )
    return nil, nil // replaced by generated code
}

wire generates the ordered constructor calls; the generated file is committed and reviewed like handwritten code.

Verification Checklist

  1. Every service/handler receives dependencies via constructor parameters
  2. No package-level mutable singletons (var DB, var logger, Get() accessors)
  3. All wiring concentrated in main/run — no init() construction
  4. Dependencies accepted as interfaces (or funcs), concrete types returned
  5. Constructors validate required dependencies
  6. Components testable by passing fakes — no process-global setup in tests
  7. If a DI tool is used: exactly one, at the composition root only
  8. go build ./... passes — wiring errors surface at compile time

Correlati per attività

dallo stesso repository

Altri Skills

Tutti gli Skills
eduardo-sl
Community

go-ci

Continuous integration for Go projects: GitHub Actions pipelines, caching, golangci-lint setup, test/coverage gates, vulnerability scanning, build matrices, and Makefile targets. Use when: "set up CI", "GitHub Actions for Go", "add lint to the pipeline", "CI is slow", "coverage gate", "build matrix", "write a Makefile", "run govulncheck in CI". Not for: commit conventions (git-commit), choosing or auditing dependencies (go-dependency-audit), writing the tests themselves (go-test-quality).

installazioni
1
GitHub Stars
71
Aggiornato
18 ago
eduardo-sl
Community

go-cli

Build command-line tools in Go: flag handling, subcommands, stdin/stdout discipline, exit codes, signal handling, and when Cobra/Viper earn their weight over the standard library. Use when: "build a CLI", "add a subcommand", "parse flags", "exit codes", "handle Ctrl+C", "cobra command", "read from stdin", "CLI UX". Not for: HTTP APIs (go-api-design), scaffolding (go-project-layout), service configuration (go-architecture-review).

installazioni
1
GitHub Stars
71
Aggiornato
18 ago
eduardo-sl
Community

go-coding-standards

Go coding standards and style conventions grounded in Effective Go, Go Code Review Comments, and production-proven idioms. Use when writing or reviewing Go code, enforcing naming conventions, import ordering, variable declarations, struct initialization, or formatting rules. Trigger examples: "check Go style", "fix formatting", "review naming", "Go conventions". Not for: architecture (go-architecture-review), concurrency (go-concurrency-review), performance tuning (go-performance-review).

installazioni
1
GitHub Stars
71
Aggiornato
18 ago
eduardo-sl
Community

go-context

Correct usage of context.Context in Go: propagation, cancellation, timeouts, deadlines, values, and common anti-patterns. Use when: "context usage", "context.Context", "context cancellation", "timeout", "context.WithTimeout", "context.WithCancel", "context values", "context propagation". Not for: concurrency beyond context (go-concurrency-review), HTTP middleware (go-api-design), error handling (go-error-handling).

installazioni
1
GitHub Stars
71
Aggiornato
18 ago