К основному содержанию
скилл CX Codex

go-dependency-injection — скилл для Claude Code

Скилл учит агента внедрять зависимости в Go через конструкторы и собирать всё в main. Пригодится, когда в проекте завёлся глобальный синглтон или код тяжело тестировать.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add eduardo-sl/go-agent-skills --skill go-dependency-injection -a claude-code
Открыть на GitHub

Что делает go-dependency-injection

Скилл задаёт агенту правила внедрения зависимостей в Go. По умолчанию — конструкторы: сервис получает репозиторий, платёжный шлюз и логгер параметрами, а не достаёт их из глобальных переменных. Композиционный корень один — main или вызываемая из него функция run, порядок сборки проверяет компилятор.

Отдельный раздел — как выпилить глобальное состояние. Легаси переводится постепенно: появляется структура с полем-зависимостью, рядом остаётся устаревшая обёртка уровня пакета, вызовы переезжают на структуру, обёртка удаляется. Для мелких швов вместо интерфейса подставляется функция — например, now func() time.Time.

Про фреймворки позиция прямая: ручная сборка тянет дальше, чем кажется, и run на сто строк остаётся читаемым. google/wire даёт генерацию на этапе компиляции, uber-go/fx и dig — контейнер времени выполнения с ошибками при старте. Смешивать механизмы нельзя: один корень сборки, один способ. Нужен тулчейн Go; wire и fx подключаются по желанию. Скилл уступает правилу проекта или конфигу агента, если те явно объявлены главнее.

Какие задачи решает

  • вынести глобальный синглтон в явную зависимость
  • собрать зависимости сервиса в одном main
  • сделать компонент тестируемым без правки глобального состояния
  • выбрать между ручной сборкой и google/wire
  • перевести легаси-код на конструкторы без большого рефакторинга

Примеры запросов агенту

  • Убери глобальный var DB и передай зависимость через конструктор
  • Собери все зависимости в main, без init()
  • Стоит ли здесь брать google/wire или хватит ручной сборки?

Как установить go-dependency-injection

1Через Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-dependency-injection -a claude-code

2Вручную: положить файлы

~/.claude/skills/go-dependency-injection/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/go-dependency-injection/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о go-dependency-injection

Как установить go-dependency-injection в Claude Code?

Выполните npx skills add eduardo-sl/go-agent-skills --skill go-dependency-injection -a claude-code. Скилл встанет в ~/.claude/skills/go-dependency-injection/SKILL.md.

Что делает go-dependency-injection?

Описывает, как внедрять зависимости в Go: конструкторы, сборка в main, отказ от глобального состояния. Плюс разбирает, когда оправданы wire, fx и dig.

Нужны ли wire или fx для работы скилла?

Нет, они опциональны. Базовый подход — ручная сборка в main, а фреймворки скилл советует брать только при большой связности компонентов.

Исходный текст

SKILL.md · MIT
---
name: go-dependency-injection
description: >
  Dependency injection in Go: constructor injection, wiring in main,
  avoiding global state, and when frameworks (wire, fx, dig) earn their
  complexity. Use when: "dependency injection", "wire up dependencies",
  "inject this", "remove global state", "singleton in Go", "use
  google/wire", "uber fx", "make this testable".
  Not for: interface design (go-interface-design), directory structure
  (go-project-layout), test doubles and mocks (go-test-quality).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain. wire and fx are optional.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
  author: eduardo-sl
  version: "1.1.2"
---

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

> Community default. A project skill or agent-config rule that explicitly
> supersedes `go-dependency-injection` takes precedence over this one.

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

| Tool | Model | Trade-off |
|---|---|---|
| google/wire | Compile-time code generation | Wiring stays plain Go and compiler-checked; adds a codegen step |
| uber-go/fx | Runtime container + lifecycle | App lifecycle (start/stop hooks) managed; errors surface at runtime, magic in stack traces |
| uber-go/dig | Runtime 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

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Похожие скиллы

Все скиллы по теме «Бэкенд и API» →
mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. 130 949установок claude-api официальный anthropics Справочник по Anthropic SDK и API Claude для генерации кода без устаревших параметров и выдуманных методов. 74 198установок lark-im larksuite Скилл подключает Lark IM к агенту: он отправляет сообщения, ищет историю, управляет чатами и файлами. Подойдёт для задач вокруг командных коммуникаций. CX Codex +1 472 900установок lark-event larksuite Слушает события Lark/Feishu и отдаёт их потоком NDJSON. Подходит для ботов, обработчиков сообщений и долгих подписчиков. CX Codex +1 466 800установок caveman-discover JuliusBrussee Находит точки вызова LLM в репозитории и размечает их воркфлоу для Caveman Cloud, чтобы расходы на токены не сливались в одну общую кучу. CX Codex +1 104 400установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. CX Codex +1 103 900установок

Из того же набора11

git-commit Скилл учит агента писать коммиты по Conventional Commits: тип, область, императив в заголовке. Пригодится, когда история коммитов в проекте превратилась в кашу. CX Codex +1 ★ 82звёзд репо go-troubleshooting Скилл ведёт агента по диагностике рантайм-проблем в Go: паники, дедлоки, утечки горутин и памяти, отчёты race detector. Пригодится, когда программа падает или висит, а причина неясна. CX Codex +1 ★ 82звёзд репо go-observability Скилл для Go-сервисов: помогает настроить структурные логи на log/slog, трейсы и метрики через OpenTelemetry, а также алерты по SLO. Пригодится, когда сервис уже в проде и нужно видеть, что в нём происходит. CX Codex +1 ★ 82звёзд репо go-error-handling Скилл задаёт агенту правила работы с ошибками в Go: обёртка через %w, sentinel-ошибки, свои типы и errors.Is/errors.As. CX Codex +1 ★ 82звёзд репо go-context Скилл для ИИ-агента, который проверяет и правит работу с context.Context в Go: отмена, таймауты, значения, типичные ошибки. CX Codex +1 ★ 82звёзд репо go-project-layout Подсказывает, как разложить новый Go-проект по папкам: cmd/, internal/, плоская раскладка для мелких утилит. Пригодится в самом начале, когда структура ещё не сложилась. CX Codex +1 ★ 82звёзд репо go-grpc Скилл для ИИ-агента, который ведёт разработку gRPC-сервисов на Go: proto-контракты, коды ошибок, дедлайны, интерцепторы и стриминг. CX Codex +1 ★ 82звёзд репо go-api-design Скилл ведёт агента по проектированию HTTP-обработчиков на Go: маршруты, middleware, валидация, пагинация, graceful shutdown. Пригодится, когда пишете REST-сервис с нуля или переделываете существующий. CX Codex +1 ★ 82звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой