К основному содержанию
скилл Claude Code CX Codex Cursor GitHub Copilot

golang-dependency-injection — скилл для Claude Code: как настроить

Помогает организовать внедрение зависимостей в Go-проектах: от ручных конструкторов до библиотек wire, dig, fx и do.

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

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

Скилл направляет проектирование архитектуры сервисов и помогает избавиться от глобального состояния или вызовов init(). Он поддерживает два сценария работы: проектирование новых компонентов и рефакторинг уже связанного кода.

В режиме рефакторинга агент запускает до трёх параллельных субагентов. Первый ищет глобальные переменные, второй находит жёсткие зависимости вместо интерфейсов, а третий выявляет антипаттерн service locator. Для работы требуется установленный бинарник go.

Для небольших проектов до 10 сервисов скилл рекомендует обходиться ручным внедрением через конструкторы. Ручной подход неизбежно ломается, когда сервисов становится больше 15: порядок связывания запутывается, а коду требуется управление жизненным циклом.

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

  • спроектировать внедрение зависимостей через конструкторы
  • найти скрытые зависимости и глобальные переменные в init()
  • заменить жёсткие структуры на интерфейсы в местах вызова
  • выбрать подходящую DI-библиотеку между wire, dig, fx и do

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

  • Спроектируй DI для сервиса заказов в Go без сторонних библиотек
  • Проанализируй кодовую базу и найди антипаттерны service locator
  • Помоги перевести инициализацию приложения на uber-go/fx

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

1Через Skills CLI (Vercel)

npx skills add samber/cc-skills-golang --skill golang-dependency-injection -a claude-code

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

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

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

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

Весь набор →
golang-code-style samber Скилл помогает писать понятный код на Go, разбирая правила длины строк, объявления переменных, управления потоком выполнения и комментариев. Пригодится при написании и ревью кода, обсуждении стилистики или установке стандартов проекта. Claude Code CX Codex Cursor +1 44 000установок golang-error-handling samber Скилл для идиоматичной обработки ошибок в Go: оборачивание с контекстом, проверка цепочек, структурированное логирование и интеграция с samber/oops. Применяется при создании, оборачивании, инспекции и логировании ошибок. Claude Code CX Codex Cursor +1 43 200установок golang-security samber Находит уязвимости в коде на Go, выстраивает аудит по STRIDE и DREAD и помогает закрывать инъекции, утечки секретов и ошибки в криптографии. Claude Code CX Codex Cursor +1 42 100установок golang-design-patterns samber Скилл подсказывает идиоматичные Go-паттерны для API, жизненного цикла ресурсов, graceful shutdown и архитектуры. Пригодится при проектировании и ревью кода. Claude Code CX Codex Cursor +1 41 900установок golang-performance samber Помогает находить и устранять узкие места в Go-коде: сокращает аллокации памяти, оптимизирует горячие циклы и проверяет результаты замеров. Claude Code CX Codex Cursor +1 41 800установок golang-concurrency samber Скилл задаёт правила для конкурентного кода на Go: жизненный цикл горутин, каналы и select, мьютексы, errgroup, singleflight, воркер-пулы и fan-out/fan-in пайплайны. Claude Code CX Codex Cursor +1 41 600установок golang-database samber Набор правил для работы с реляционными базами данных в Go через database/sql, sqlx и pgx. Помогает писать запросы без ORM и проверять утечки соединений. Claude Code CX Codex Cursor +1 40 700установок golang-naming samber Скилл задаёт правила имён в Go: пакеты, типы, ошибки, булевы поля и тесты. Пригодится при написании, ревью и рефакторинге кода. Claude Code CX Codex Cursor +1 40 700установок

Похожие

iii-engine-config iii-hq Помогает настроить движок iii через worker-compose.yaml или config.yaml. Задаёт порты, параметры RBAC через rbac-proxy, ограничения наблюдателей и хранилище конфигураций. Claude Code CX Codex Cursor +1 4 200установок mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. Claude Code Claude.ai 130 949установок google-agents-cli-adk-code официальный Google Скилл даёт примеры и справку по Agent Development Kit: агентам, инструментам, колбэкам, состоянию и графовым workflow. Нужен при написании кода. Claude Code CX Codex Cursor +1 511 400установок lark-im larksuite Скилл подключает Lark IM к агенту: он отправляет сообщения, ищет историю, управляет чатами и файлами. Подойдёт для задач вокруг командных коммуникаций. Claude Code CX Codex Cursor +1 472 300установок lark-event larksuite Слушает события Lark/Feishu и отдаёт их потоком NDJSON. Подходит для ботов, обработчиков сообщений и долгих подписчиков. Claude Code CX Codex Cursor +1 466 200установок caveman-discover JuliusBrussee Находит точки вызова LLM в репозитории и размечает их воркфлоу для Caveman Cloud, чтобы расходы на токены не сливались в одну общую кучу. Claude Code CX Codex Cursor +1 103 500установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. Claude Code CX Codex Cursor +1 102 900установок

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

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

Выполните команду npx skills add samber/cc-skills-golang --skill golang-dependency-injection -a claude-code. Скилл сразу станет доступен для работы с Go-проектами.

Что делает скилл golang-dependency-injection?

Он помогает составить граф зависимостей, выбрать подход к DI под размер проекта и провести миграцию с глобальных переменных на чистые интерфейсы.

Когда стоит переходить с ручного связывания на DI-библиотеку?

Ручной подход хорош для систем менее чем из 10 сервисов. Если компонентов больше 15 либо проекту нужны ленивая инициализация и контроль остановки, пора внедрять библиотеки вроде wire или fx.

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

SKILL.md · MIT
---
name: golang-dependency-injection
description: "Comprehensive guide for dependency injection (DI) in Golang. Covers why DI matters (testability, loose coupling, separation of concerns, lifecycle management), manual constructor injection, and DI library comparison (google/wire, uber-go/dig, uber-go/fx, samber/do). Use this skill when designing service architecture, setting up dependency injection, refactoring tightly coupled code, managing singletons or service factories, or when the user asks about inversion of control, service containers, or wiring dependencies in Go. For a specific DI library, → See `samber/cc-skills-golang@golang-google-wire`, `samber/cc-skills-golang@golang-uber-dig`, `samber/cc-skills-golang@golang-uber-fx`, or `samber/cc-skills-golang@golang-samber-do` skills."
user-invocable: true
license: MIT
compatibility: Designed for Claude Code, Codex or similar harness, and for projects using Golang.
metadata:
  author: samber
  version: "1.3.1"
  openclaw:
    emoji: "🔌"
    homepage: https://github.com/samber/cc-skills-golang
    requires:
      bins:
        - go
    install: []
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs AskUserQuestion
paths:
  - "**/*.go"
---

**Persona:** You are a Go software architect. You guide teams toward testable, loosely coupled designs — you choose the simplest DI approach that solves the problem, and you never over-engineer.

**Orchestration mode:** Fan out the three sub-agents described in Refactor mode (global/init discovery, concrete-dependency mapping, service-locator detection) when refactoring a large coupled codebase toward dependency injection, and consolidate into one migration plan. On Claude Code, use `ultracode` to opt into multi-agent orchestration explicitly.

**Modes:**

- **Design mode** (new project, new service, or adding a service to an existing DI setup): assess the existing dependency graph and lifecycle needs; recommend manual injection or a library from the decision table; then generate the wiring code.
- **Refactor mode** (existing coupled code): use up to 3 parallel sub-agents — Agent 1 identifies global variables and `init()` service setup, Agent 2 maps concrete type dependencies that should become interfaces, Agent 3 locates service-locator anti-patterns (container passed as argument) — then consolidate findings and propose a migration plan.

> **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-dependency-injection` skill takes precedence.

# Dependency Injection in Go

Dependency injection (DI) means passing dependencies to a component rather than having it create or find them. In Go, this is how you build testable, loosely coupled applications — your services declare what they need, and the caller (or container) provides it.

This skill is not exhaustive. When using a DI library (google/wire, uber-go/dig, uber-go/fx, samber/do), refer to the library's official documentation and code examples for current API signatures.

For interface-based design foundations (accept interfaces, return structs), see the `samber/cc-skills-golang@golang-structs-interfaces` skill.

## Best Practices Summary

1. Dependencies MUST be injected via constructors — NEVER use global variables or `init()` for service setup
2. Small projects (< 10 services) SHOULD use manual constructor injection — no library needed
3. Interfaces MUST be defined where consumed, not where implemented — accept interfaces, return structs
4. NEVER use global registries or package-level service locators
5. The DI container MUST only exist at the composition root (`main()` or app startup) — NEVER pass the container as a dependency
6. **Prefer lazy initialization** — only create services when first requested
7. **Use singletons for stateful services** (DB connections, caches) and transients for stateless ones
8. **Mock at the interface boundary** — DI makes this trivial
9. **Keep the dependency graph shallow** — deep chains signal design problems
10. **Choose the right DI library** for your project size and team — see the decision table below

## Why Dependency Injection?

| Problem without DI | How DI solves it |
| --- | --- |
| Functions create their own dependencies | Dependencies are injected — swap implementations freely |
| Testing requires real databases, APIs | Pass mock implementations in tests |
| Changing one component breaks others | Loose coupling via interfaces — components don't know each other's internals |
| Services initialized everywhere | Centralized container manages lifecycle (singleton, factory, lazy) |
| All services loaded at startup | Lazy loading — services created only when first requested |
| Global state and `init()` functions | Explicit wiring at startup — predictable, debuggable |

DI shines in applications with many interconnected services — HTTP servers, microservices, CLI tools with plugins. For a small script with 2-3 functions, manual wiring is fine. Don't over-engineer.

## Manual Constructor Injection (No Library)

For small projects, pass dependencies through constructors. See [Manual DI examples](./references/manual-di.md) for a complete application example.

```go
// ✓ Good — explicit dependencies, testable
type UserService struct {
    db     UserStore
    mailer Mailer
    logger *slog.Logger
}

func NewUserService(db UserStore, mailer Mailer, logger *slog.Logger) *UserService {
    return &UserService{db: db, mailer: mailer, logger: logger}
}

// main.go — manual wiring
func main() {
    logger := slog.Default()
    db := postgres.NewUserStore(connStr)
    mailer := smtp.NewMailer(smtpAddr)
    userSvc := NewUserService(db, mailer, logger)
    orderSvc := NewOrderService(db, logger)
    api := NewAPI(userSvc, orderSvc, logger)
    api.ListenAndServe(":8080")
}
```

```go
// ✗ Bad — hardcoded dependencies, untestable
type UserService struct {
    db *sql.DB
}

func NewUserService() *UserService {
    db, _ := sql.Open("postgres", os.Getenv("DATABASE_URL")) // hidden dependency
    return &UserService{db: db}
}
```

Manual DI breaks down when:

- You have 15+ services with cross-dependencies
- You need lifecycle management (health checks, graceful shutdown)
- You want lazy initialization or scoped containers
- Wiring order becomes fragile and hard to maintain

## DI Library Comparison

Go has three main approaches to DI libraries:

- [google/wire examples](./references/google-wire.md) — Compile-time code generation
- [uber-go/dig + fx examples](./references/uber-dig-fx.md) — Reflection-based framework
- [samber/do examples](./references/samber-do.md) — Generics-based, no code generation

### Decision Table

| Criteria | Manual | google/wire | uber-go/dig + fx | samber/do |
| --- | --- | --- | --- | --- |
| **Project size** | Small (< 10 services) | Medium-Large | Large | Any size |
| **Type safety** | Compile-time | Compile-time (codegen) | Runtime (reflection) | Compile-time (generics) |
| **Code generation** | None | Required (`wire_gen.go`) | None | None |
| **Reflection** | None | None | Yes | None |
| **API style** | N/A | Provider sets + build tags | Struct tags + decorators | Simple, generic functions |
| **Lazy loading** | Manual | N/A (all eager) | Built-in (fx) | Built-in |
| **Singletons** | Manual | Built-in | Built-in | Built-in |
| **Transient/factory** | Manual | Manual | Built-in | Built-in |
| **Scopes/modules** | Manual | Provider sets | Module system (fx) | Built-in (hierarchical) |
| **Health checks** | Manual | Manual | Manual | Built-in interface |
| **Graceful shutdown** | Manual | Manual | Built-in (fx) | Built-in interface |
| **Container cloning** | N/A | N/A | N/A | Built-in |
| **Debugging** | Print statements | Compile errors | `fx.Visualize()` | `ExplainInjector()`, web interface |
| **Go version** | Any | Any | Any | 1.18+ (generics) |
| **Learning curve** | None | Medium | High | Low |

### Quick Comparison: Wiring Style

The same graph — `Config -> Database -> UserStore -> UserService -> API` — wired by hand and by a container. The contrast is what the wiring code encodes: an ordered call sequence you maintain, versus a set of providers the container orders for you.

```go
// Manual — you own the order; adding a dependency means editing every call site downstream
cfg := NewConfig()
db := NewDatabase(cfg)
store := NewUserStore(db)
svc := NewUserService(store)
api := NewAPI(svc)
api.Run()
// No shutdown hooks, health checks, or lazy loading — add them yourself

// Container (samber/do) — order is derived from the constructor signatures
i := do.New()
do.Provide(i, NewConfig)
do.Provide(i, NewDatabase)
do.Provide(i, NewUserStore)
do.Provide(i, NewUserService)
api := do.MustInvoke[*API](i)
api.Run()
defer i.Shutdown() // shutdown and health checks come from the container
```

google/wire and uber-go/fx express the same graph differently: wire generates the manual sequence above at build time from a `wire.Build` provider list (cleanup via `func()` returned by providers, no lifecycle hooks), while fx registers providers with `fx.Provide` and resolves them by reflection at runtime with `OnStart`/`OnStop` hooks. Full wiring examples for each: [google/wire](./references/google-wire.md), [uber-go/dig + fx](./references/uber-dig-fx.md), [samber/do](./references/samber-do.md).

## Testing with DI

DI makes testing straightforward — inject mocks instead of real implementations:

```go
// Define a mock
type MockUserStore struct {
    users map[string]*User
}

func (m *MockUserStore) FindByID(ctx context.Context, id string) (*User, error) {
    u, ok := m.users[id]
    if !ok {
        return nil, ErrNotFound
    }
    return u, nil
}

// Test with manual injection
func TestUserService_GetUser(t *testing.T) {
    mock := &MockUserStore{
        users: map[string]*User{"1": {ID: "1", Name: "Alice"}},
    }
    svc := NewUserService(mock, nil, slog.Default())

    user, err := svc.GetUser(context.Background(), "1")
    if err != nil {
        t.Fatalf("unexpected error: %v", err)
    }
    if user.Name != "Alice" {
        t.Errorf("got %q, want %q", user.Name, "Alice")
    }
}
```

### Testing with samber/do — Clone and Override

Container cloning creates an isolated copy where you override only the services you need to mock:

```go
func TestUserService_WithDo(t *testing.T) {
    // Create a test injector with mock implementation
    testInjector := do.New()

    // Provide the mock UserStore interface
    do.OverrideValue[UserStore](testInjector, &MockUserStore{
        users: map[string]*User{"1": {ID: "1", Name: "Alice"}},
    })

    // Provide other real services as needed
    do.Provide[*slog.Logger](testInjector, func(i *do.Injector) (*slog.Logger, error) {
        return slog.Default(), nil
    })

    svc := do.MustInvoke[*UserService](testInjector)
    user, err := svc.GetUser(context.Background(), "1")
    // ... assertions
}
```

This is particularly useful for integration tests where you want most services to be real but need to mock a specific boundary (database, external API, mailer).

## When to Adopt a DI Library

| Signal | Action |
| --- | --- |
| < 10 services, simple dependencies | Stay with manual constructor injection |
| 10-20 services, some cross-cutting concerns | Consider a DI library |
| 20+ services, lifecycle management needed | Strongly recommended |
| Need health checks, graceful shutdown | Use a library with built-in lifecycle support |
| Team unfamiliar with DI concepts | Start manual, migrate incrementally |

## Common Mistakes

| Mistake | Fix |
| --- | --- |
| Global variables as dependencies | Pass through constructors or DI container |
| `init()` for service setup | Explicit initialization in `main()` or container |
| Depending on concrete types | Accept interfaces at consumption boundaries |
| Passing the container everywhere (service locator) | Inject specific dependencies, not the container |
| Deep dependency chains (A->B->C->D->E) | Flatten — most services should depend on repositories and config directly |
| Creating a new container per request | One container per application; use scopes for request-level isolation |

## Cross-References

- → See `samber/cc-skills-golang@golang-samber-do` skill for detailed samber/do usage patterns
- → See `samber/cc-skills-golang@golang-structs-interfaces` skill for interface design and composition
- → See `samber/cc-skills-golang@golang-testing` skill for testing with dependency injection
- → See `samber/cc-skills-golang@golang-project-layout` skill for DI initialization placement

## References

- [samber/do/v2 documentation](https://do.samber.dev) | [github.com/samber/do/v2](https://github.com/samber/do)
- [google/wire user guide](https://github.com/google/wire/blob/main/docs/guide.md)
- [uber-go/fx documentation](https://uber-go.github.io/fx/)
- [uber-go/dig](https://github.com/uber-go/dig)

© samber · MIT · samber/cc-skills-golang

Смотрите также

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

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