skills/ferhatelmas/goodies/uber-go-style

uber-go-style

SKILL.md

When writing or modifying Go code, follow these rules based on the Uber Go Style Guide.

Guidelines

Interfaces

  • Never use pointers to interfaces; pass interfaces as values
  • Verify interface compliance at compile time: var _ http.Handler = (*Handler)(nil)

Receivers

  • Value receivers can be called on pointers and values; pointer receivers only on pointers or addressable values

Mutexes

  • Zero-value sync.Mutex and sync.RWMutex are valid; don't use new(sync.Mutex)
  • Don't embed mutexes in structs; use a named field mu sync.Mutex

Slices and Maps at Boundaries

  • Copy slices and maps received as arguments if you store them (prevent caller mutation)
  • Copy slices and maps before returning them if they expose internal state

Defer

  • Use defer to clean up resources (files, locks). The overhead is negligible

Channels

  • Channel size should be one or unbuffered (zero). Any other size requires strong justification

Enums

  • Start enums at one with iota + 1 unless zero value is a meaningful default

Time

  • Use time.Time for instants, time.Duration for periods
  • Include unit in field names when time.Duration can't be used: IntervalMillis
  • Use RFC 3339 for timestamp strings

Errors

  • Use errors.New for static errors, fmt.Errorf for dynamic
  • Export error vars (ErrFoo) for caller matching via errors.Is; use custom types with Error suffix for errors.As
  • Wrap errors with %w (caller can match) or %v (opaque); avoid "failed to" prefixes: use "new store: %w" not "failed to create new store: %w"
  • Prefix exported error vars with Err, unexported with err
  • Handle errors once: either wrap and return, or log and degrade gracefully; never log AND return

Type Assertions

  • Always use the "comma ok" form: t, ok := i.(string)

Panics

  • Don't panic in production code; return errors instead
  • In tests, use t.Fatal not panic
  • Only acceptable for program initialization: template.Must(...)

Atomics

  • Prefer go.uber.org/atomic types (atomic.Bool, etc.) over raw sync/atomic for type safety

Mutable Globals

  • Avoid mutable globals; use dependency injection instead

Embedding Types

  • Don't embed types in public structs; delegate methods explicitly
  • Embedding leaks implementation details and inhibits type evolution

Built-In Names

  • Never shadow predeclared identifiers (error, string, len, cap, etc.)

init()

  • Avoid init(). Make it deterministic, no I/O, no global state mutation
  • Prefer var _defaultFoo = defaultFoo() or initialization in main()

Exit

  • Call os.Exit or log.Fatal only in main(); all other functions return errors
  • Prefer a single run() error function called from main() for testability

Field Tags

  • Always use field tags in marshaled structs: json:"price"

Goroutines

  • Don't fire-and-forget goroutines; every goroutine must have a way to stop and be waited on
  • Use sync.WaitGroup for multiple goroutines, a done channel for single ones
  • No goroutines in init(); expose objects with Shutdown()/Close() methods

Performance

  • Use strconv over fmt for primitive-to-string conversion
  • Don't repeatedly convert fixed strings to []byte; do it once
  • Specify capacity for slices: make([]T, 0, size) and maps: make(map[K]V, size)

Style

Formatting

  • Soft line length limit of 99 characters
  • Be consistent above all else

Declarations

  • Group similar declarations (const, var, type) but only group related items
  • Two import groups: standard library, then everything else (separated by blank line)

Naming

  • Package names: lowercase, no underscores, short, not plural, not "common/util/shared/lib"
  • Function names: MixedCaps; test functions may use underscores for grouping
  • Import aliases only when package name doesn't match last path element or on conflict
  • Prefix unexported globals with _ (except error vars which use err prefix)

Functions

  • Sort functions by rough call order; group by receiver
  • Exported functions first, after struct/const/var; NewXYZ() right after type definition
  • Utility functions at end of file

Control Flow

  • Reduce nesting: handle errors/special cases first, return early
  • Eliminate unnecessary else: use default value + conditional override
  • Reduce variable scope: if err := doThing(); err != nil

Variables

  • Use := for local variables with explicit values
  • Use var for zero-value declarations and empty slices
  • nil is a valid slice; return nil not []int{}; check emptiness with len(s) == 0

Parameters

  • Avoid naked bool parameters; use C-style comments or custom types for clarity

Strings

  • Use raw string literals to avoid escaping: `unknown error:"test"`

Structs

  • Use field names in struct initialization (enforced by go vet)
  • Omit zero-value fields unless they provide meaningful context
  • Use var s MyStruct for zero-value structs, not s := MyStruct{}
  • Use &T{Name: "bar"} not new(T) for struct references
  • Place embedded types at top of field list, separated by blank line

Maps

  • Use make(map[K]V) for empty/programmatic maps; use literals for fixed sets
  • Provide capacity hints when size is known

Printf

  • Declare format strings as const for go vet analysis
  • Name Printf-style functions with f suffix: Wrapf, not Wrap

Patterns

Test Tables

  • Use table-driven tests with subtests for repetitive test logic
  • Name the slice tests, each case tt, use give/want prefixes
  • Avoid complex conditional logic in table tests; split into separate test functions instead
  • For parallel table tests, ensure loop variables are scoped correctly

Functional Options

  • Use the functional options pattern for constructors with 3+ parameters
  • Implement with an Option interface and unexported options struct
  • Prefer concrete types over closures for debuggability and testability

Linting

  • Run at minimum: errcheck, goimports, revive, govet, staticcheck
  • Use golangci-lint as the lint runner
  • Lint consistently across the entire codebase
Weekly Installs
3
GitHub Stars
1
First Seen
Feb 13, 2026
Installed on
opencode2
claude-code2
github-copilot2
codex2
kimi-cli2
gemini-cli2