go-dependency-injection
정보
이 스킬은 Go에서 의존성 주입을 구현하는 방법에 대한 지침을 제공하며, 전역 상태를 피하기 위해 생성자 주입과 `main()` 함수 내 명시적 와이어링에 중점을 둡니다. Wire, Fx, Dig 같은 프레임워크 사용 시기와 수동 의존성 관리의 선택 기준을 설명합니다. 의존성 연결, 테스트 용이성 향상, 싱글톤 제거에 관한 질문에 이 스킬을 활용하되, 인터페이스 설계나 프로젝트 구조 관련 주제에는 사용하지 마십시오.
빠른 설치
Claude Code
추천npx skills add eduardo-sl/go-agent-skills -a claude-code/plugin add https://github.com/eduardo-sl/go-agent-skillsgit clone https://github.com/eduardo-sl/go-agent-skills.git ~/.claude/skills/go-dependency-injectionClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
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
// ✅ 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:
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-levelvar DB *sql.DB. - Two binaries needing different wiring = two mains, same components.
3. Eliminating Global State
// ❌ 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:
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: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
- Every service/handler receives dependencies via constructor parameters
- No package-level mutable singletons (
var DB,var logger,Get()accessors) - All wiring concentrated in main/run — no
init()construction - Dependencies accepted as interfaces (or funcs), concrete types returned
- Constructors validate required dependencies
- Components testable by passing fakes — no process-global setup in tests
- If a DI tool is used: exactly one, at the composition root only
go build ./...passes — wiring errors surface at compile time
GitHub 저장소
자주 묻는 질문
go-dependency-injection Skill이란 무엇인가요?
go-dependency-injection은(는) eduardo-sl이(가) 만든 Claude Skill입니다. Skill은 Claude가 필요할 때 불러오는 지침과 리소스를 묶어 추가 프롬프트 없이 go-dependency-injection 관련 작업을 수행할 수 있게 합니다.
go-dependency-injection은(는) 어떻게 설치하나요?
이 페이지의 설치 명령을 사용하세요. go-dependency-injection을(를) Claude Code 플러그인으로 추가하거나 저장소를 skills 디렉터리에 복제한 다음 Claude를 다시 시작해 Skill을 불러옵니다.
go-dependency-injection은(는) 어떤 카테고리에 속하나요?
go-dependency-injection은(는) 테스팅 카테고리에 속합니다.
go-dependency-injection은(는) 무료로 사용할 수 있나요?
네. go-dependency-injection은(는) AIMCP에 등록되어 있으며 무료로 설치할 수 있습니다.
연관 스킬
이 Claude Skill은 MMLU, GSM8K를 포함한 60개 이상의 표준화된 학술 과제에서 LLM 성능을 벤치마크하기 위해 lm-evaluation-harness를 실행합니다. 개발자들이 모델 품질을 비교하고, 학습 진행 상황을 추적하거나 학술 결과를 보고할 수 있도록 설계되었습니다. 이 도구는 HuggingFace와 vLLM 모델을 포함한 다양한 백엔드를 지원합니다.
이 스킬은 cron 표현식을 사용하여 Worker를 스케줄링하기 위한 Cloudflare Cron Triggers 구현에 관한 포괄적인 지식을 제공합니다. 주기적 작업, 유지보수 작업, 자동화된 워크플로우 설정 방법을 다루며, 잘못된 cron 표현식이나 시간대 문제 같은 일반적인 이슈들을 해결하는 방법을 포함합니다. 개발자들은 이를 통해 스케줄된 핸들러 구성, cron 트리거 테스트, Workflows 및 Green Compute와의 연동 작업을 수행할 수 있습니다.
이 Claude Skill은 Python 스크립트를 통해 로컬 웹 애플리케이션을 테스트하기 위한 Playwright 기반 툴킷을 제공합니다. 프론트엔드 검증, UI 디버깅, 스크린샷 캡처, 로그 확인 기능을 지원하며 서버 라이프사이클을 관리합니다. 브라우저 자동화 작업에 사용하되 컨텍스트 오염을 방지하기 위해 소스 코드를 읽지 않고 스크립트를 직접 실행하세요.
이 스킬은 테스트 통과를 확인한 후 체계적인 통합 옵션을 제시하여 개발자가 완성된 작업을 마무리하도록 돕습니다. 구현이 완료된 후 머지, PR 생성, 브랜치 정리와 같은 워크플로우를 안내합니다. 코드가 준비되고 테스트가 완료되었을 때 개발 프로세스를 체계적으로 마무리하기 위해 사용하세요.
