Golang Patterns
Idiomatic Go reference pack — concurrency, interfaces, generics, testing,
project structure, plus the anti-patterns agents most commonly get wrong.
Two-thesis stack:
- Clear is better than clever. Boring, explicit, maintainable Go (Jon Bodner,
Learning Go, 2nd ed.).
- Production-grade by default. Bounded goroutine lifetimes, context
threading, race-detector-clean tests, gofmt + golangci-lint on every change.
Reference Guide
Load detailed guidance based on context:
| Topic |
Reference |
Load When |
| Concurrency |
references/concurrency.md |
Goroutines, channels, select, sync primitives |
| Interfaces |
references/interfaces.md |
Interface design, io.Reader/Writer, composition |
| Generics |
references/generics.md |
Type parameters, constraints, generic patterns |
| Testing |
references/testing.md |
Table-driven tests, benchmarks, fuzzing |
| Project Structure |
references/project-structure.md |
Module layout, internal packages, go.mod |
| Idiomatic Go (anti-patterns) |
references/idiomatic-go.md |
Quick anti-pattern → idiomatic-fix tables, decision rules, agent-specific rationalization counters |
Core Workflow
- Analyze architecture — Review module structure, interfaces, and concurrency patterns
- Design interfaces — Small, focused, defined at the consumer; composition over inheritance
- Implement — Idiomatic Go with proper error handling and context propagation; run
go vet ./... before proceeding
- Lint & validate — Run
golangci-lint run and fix all reported issues before proceeding
- Optimize — Profile with pprof, write benchmarks, eliminate allocations
- Test — Table-driven tests with
-race, fuzzing, 80%+ coverage; race detector must pass before committing
Core Pattern Example
Goroutine with context cancellation and error propagation:
// worker runs until ctx is cancelled or an error occurs.
// Errors are returned via errCh; the caller must drain it.
func worker(ctx context.Context, jobs <-chan Job, errCh chan<- error) {
for {
select {
case <-ctx.Done():
errCh <- fmt.Errorf("worker cancelled: %w", ctx.Err())
return
case job, ok := <-jobs:
if !ok {
return // jobs channel closed; clean exit
}
if err := process(ctx, job); err != nil {
errCh <- fmt.Errorf("process job %v: %w", job.ID, err)
return
}
}
}
}
func runPipeline(ctx context.Context, jobs []Job) error {
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
jobCh := make(chan Job, len(jobs))
errCh := make(chan error, 1)
go worker(ctx, jobCh, errCh)
for _, j := range jobs {
jobCh <- j
}
close(jobCh)
select {
case err := <-errCh:
return err
case <-ctx.Done():
return fmt.Errorf("pipeline timed out: %w", ctx.Err())
}
}
Key properties: bounded goroutine lifetime via ctx, error propagation with
%w, no goroutine leak on cancellation.
Constraints
MUST DO
- Run gofmt and golangci-lint on all code
- Add
context.Context as first param on all blocking operations
- Handle every error explicitly (no naked
_ discards without justification)
- Write table-driven tests with subtests
- Document all exported functions, types, and packages
- Use
X | Y union constraints for generics (Go 1.18+)
- Propagate errors with
fmt.Errorf("...: %w", err)
- Run race detector on tests (
-race flag)
MUST NOT DO
- Ignore errors (no
_ = thatMightFail() without a comment)
- Use
panic for normal error handling
- Spawn goroutines without a clear lifecycle
- Skip context cancellation handling
- Reach for reflection without a measured performance reason
- Mix sync and async patterns carelessly
- Hardcode configuration (functional options or env vars)
Output Templates
When implementing Go features, provide:
- Interface definitions (contracts first)
- Implementation files with proper package structure
- Test file with table-driven tests
- Brief explanation of any concurrency patterns used
Pairing
golang-pro agent — broader architectural / DevOps coverage; delegates
pattern detail here. Load both when active Go development is in scope.
Provenance
Initial content adapted from
jeffallan/claude-skills (MIT,
skills/golang-pro) and the prior wardrobe idiomatic-go skill (Bodner-derived
anti-pattern tables, now at references/idiomatic-go.md). See LICENSES.md.
1---2name: golang-patterns3description: Use when writing, reviewing, or refactoring Go code. Triggers on .go files, go.mod presence, or any task involving Go programming — concurrency (goroutines, channels, context), interfaces, generics, error handling, table-driven testing, or microservice/CLI architecture. Pairs with the `golang-pro` agent, which delegates pattern detail here.4---56# Golang Patterns78Idiomatic Go reference pack — concurrency, interfaces, generics, testing,9project structure, plus the anti-patterns agents most commonly get wrong.10Two-thesis stack:1112- **Clear is better than clever.** Boring, explicit, maintainable Go (Jon Bodner,13 *Learning Go*, 2nd ed.).14- **Production-grade by default.** Bounded goroutine lifetimes, context15 threading, race-detector-clean tests, gofmt + golangci-lint on every change.1617## Reference Guide1819Load detailed guidance based on context:2021| Topic | Reference | Load When |22|-------|-----------|-----------|23| Concurrency | `references/concurrency.md` | Goroutines, channels, select, sync primitives |24| Interfaces | `references/interfaces.md` | Interface design, io.Reader/Writer, composition |25| Generics | `references/generics.md` | Type parameters, constraints, generic patterns |26| Testing | `references/testing.md` | Table-driven tests, benchmarks, fuzzing |27| Project Structure | `references/project-structure.md` | Module layout, internal packages, go.mod |28| Idiomatic Go (anti-patterns) | `references/idiomatic-go.md` | Quick anti-pattern → idiomatic-fix tables, decision rules, agent-specific rationalization counters |2930## Core Workflow31321. **Analyze architecture** — Review module structure, interfaces, and concurrency patterns332. **Design interfaces** — Small, focused, defined at the consumer; composition over inheritance343. **Implement** — Idiomatic Go with proper error handling and context propagation; run `go vet ./...` before proceeding354. **Lint & validate** — Run `golangci-lint run` and fix all reported issues before proceeding365. **Optimize** — Profile with pprof, write benchmarks, eliminate allocations376. **Test** — Table-driven tests with `-race`, fuzzing, 80%+ coverage; race detector must pass before committing3839## Core Pattern Example4041Goroutine with context cancellation and error propagation:4243```go44// worker runs until ctx is cancelled or an error occurs.45// Errors are returned via errCh; the caller must drain it.46func worker(ctx context.Context, jobs <-chan Job, errCh chan<- error) {47 for {48 select {49 case <-ctx.Done():50 errCh <- fmt.Errorf("worker cancelled: %w", ctx.Err())51 return52 case job, ok := <-jobs:53 if !ok {54 return // jobs channel closed; clean exit55 }56 if err := process(ctx, job); err != nil {57 errCh <- fmt.Errorf("process job %v: %w", job.ID, err)58 return59 }60 }61 }62}6364func runPipeline(ctx context.Context, jobs []Job) error {65 ctx, cancel := context.WithTimeout(ctx, 30*time.Second)66 defer cancel()6768 jobCh := make(chan Job, len(jobs))69 errCh := make(chan error, 1)7071 go worker(ctx, jobCh, errCh)7273 for _, j := range jobs {74 jobCh <- j75 }76 close(jobCh)7778 select {79 case err := <-errCh:80 return err81 case <-ctx.Done():82 return fmt.Errorf("pipeline timed out: %w", ctx.Err())83 }84}85```8687Key properties: bounded goroutine lifetime via `ctx`, error propagation with88`%w`, no goroutine leak on cancellation.8990## Constraints9192### MUST DO93- Run gofmt and golangci-lint on all code94- Add `context.Context` as first param on all blocking operations95- Handle every error explicitly (no naked `_` discards without justification)96- Write table-driven tests with subtests97- Document all exported functions, types, and packages98- Use `X | Y` union constraints for generics (Go 1.18+)99- Propagate errors with `fmt.Errorf("...: %w", err)`100- Run race detector on tests (`-race` flag)101102### MUST NOT DO103- Ignore errors (no `_ = thatMightFail()` without a comment)104- Use `panic` for normal error handling105- Spawn goroutines without a clear lifecycle106- Skip context cancellation handling107- Reach for reflection without a measured performance reason108- Mix sync and async patterns carelessly109- Hardcode configuration (functional options or env vars)110111## Output Templates112113When implementing Go features, provide:1141. Interface definitions (contracts first)1152. Implementation files with proper package structure1163. Test file with table-driven tests1174. Brief explanation of any concurrency patterns used118119## Pairing120121- **`golang-pro` agent** — broader architectural / DevOps coverage; delegates122 pattern detail here. Load both when active Go development is in scope.123124## Provenance125126Initial content adapted from127[jeffallan/claude-skills](https://github.com/jeffallan/claude-skills) (MIT,128`skills/golang-pro`) and the prior wardrobe `idiomatic-go` skill (Bodner-derived129anti-pattern tables, now at `references/idiomatic-go.md`). See [`LICENSES.md`](../../LICENSES.md).