Go Patterns
File Structure
Order: package → import → const → var → type → functions/methods
Package Organization
text
project/ ├── cmd/<name>/main.go # Entry points ├── internal/<domain>/ # Private packages │ ├── types.go # Types, const, var, errors │ ├── repository.go # Interface + implementation │ └── service.go # Business logic ├── pkg/ # Public packages └── go.mod
Rules
- •No hardcoding - Use const, config, or inject
- •Interface at consumer - Define where used, not where implemented
- •Context first - Always first parameter, never store in struct
- •Errors wrapped -
fmt.Errorf("context: %w", err) - •Constructor pattern -
func NewX(...) *X - •Options pattern -
func NewX(opts ...Option) *Xfor complex config - •Table-driven tests -
tests := []struct{ name, input, want }{...}
Concurrency
| Need | Pattern |
|---|---|
| Background work | go func() { ... }() with context |
| Multiple sources | for { select { case <-ctx.Done(): ... } } |
| Parallel ops with errors | errgroup.WithContext(ctx) |
| Shared state | sync.Mutex |
| One-time init | sync.Once |
| Wait for goroutines | sync.WaitGroup |
| Streaming work | channels + worker pool |
| Fan-out/fan-in | See reference |
See references/concurrency.go for Pool, FanOut, Merge, Semaphore.
References
- •references/errors.go - Error handling utilities
- •references/concurrency.go - Worker pool, fan-out, semaphore
Checklist
- •const/var at file top?
- •No hardcoded values?
- •Interface at consumer?
- •Context as first param?
- •Errors wrapped with context?
- •Table-driven tests?
- •Background work? →
go func()with context - •Multiple sources? →
select { } - •Parallel ops? → errgroup
- •Shared state? → sync.Mutex
- •One-time init? → sync.Once
- •Wait for goroutines? → sync.WaitGroup
- •Streaming work? → channels + worker pool