Interface design
Keep interfaces small and define them where they are consumed.
Canonical guidance
- prefer concrete types until abstraction is needed
- define interfaces at the point of use, usually on the consumer side
- keep interfaces small, often one or a few methods
- use interfaces to describe behavior, not taxonomy
Use when
- mocking or testing call boundaries
- abstracting over multiple implementations
- reviewing exported APIs
Avoid
- exporting interfaces just because there is one implementation
- giant “god interfaces”
- adding an interface layer before a second implementation exists
Preferred pattern
type Fetcher interface {
Fetch(ctx context.Context, id string) (User, error)
}
Anti-pattern
type ServiceManagerInterface interface {
Start() error
Stop() error
Fetch(ctx context.Context, id string) (User, error)
Save(ctx context.Context, u User) error
Delete(ctx context.Context, id string) error
}
Explanation: This anti-pattern is common in enterprise-style codebases, but oversized interfaces freeze unnecessary abstraction into APIs too early.
Why
- small interfaces are easier to satisfy and reason about
- consumer-owned interfaces avoid over-design in providers
Related pages
Sources
- Go Data Structures: Interfaces - Russ Cox
- Effective Go - Go Team
- Go Code Review Comments - Go Team