golang
Master Go development using production-grade best practices merged from the Google and Uber style guides. Use whenever writing Go code, designing APIs, handling errors, managing goroutines, or configuring linters.
Golang Engineering Standards
This skill synthesizes the absolute best practices from the ecosystem (Uber Guide, Google Guide, and community consensus) to ensure written Go code is idiomatic, performant, and safe.
1. Interface & API Design
- Accept Interfaces, Return Structs: Define interfaces where they are consumed (by the caller), not where they are implemented. Return concrete structs from constructors so callers can use all methods or mock as needed.
- Context is King:
context.Contextmust always be the first parameter of any function doing I/O or asynchronous work. - Never Store Context: Do not store
context.Contextinside structs. It is meant to flow entirely through the function stack. - No Dependency Injection via Context: Only use
context.WithValuefor request-scoped data (like trace IDs, user claims). Never use it to pass databases, loggers, or configuration.
2. Error Handling
- Wrapping Options: Use
fmt.Errorf("doing operation: %w", err)to preserve the underlying error forerrors.Isorerrors.As. Use%vonly if you explicitly want to hide the underlying error's identity. - Never Log AND Return: Pick one. If you log an error, handle it there. If you return it, let the caller log it. Doing both creates duplicate noise in APM systems.
- Sentinel Errors: Define top-level exported errors for standard package failure modes (
var ErrNotFound = errors.New(...)). Useerrors.Is(err, ErrNotFound)rather than string comparisons.
3. Concurrency & Goroutines
- Know When To Stop: Never start a goroutine without knowing exactly how and when it will terminate. Unbounded or untracked goroutines cause devastating memory leaks.
- Coordination: Use
sync.WaitGroupto wait for a pool of workers. - Channels vs Mutexes:
- Use
chanto pass ownership of data between concurrent routines. - Use
sync.Mutexto protect shared state accessed from multiple routines.
- Use
- Lock Discipline: Keep the critical section of a lock as short as physically possible. Never perform I/O while holding a mutex.
4. Naming Conventions (No Stuttering)
- Getters: Go does not use
Getprefixes for getters. If a struct has anOwnerfield, the getter isOwner(), notGetOwner(). The setter would beSetOwner(). - Stuttering: Avoid package/type name redundancy.
- Bad:
user.UserConfig,log.Logger. - Good:
user.Config,log.Entry.
- Bad:
- Interfaces: Single-method interfaces should end in
-er(Reader,Writer,Formatter). - Short Variable Names: Idiomatic Go uses very short variables for scope-limited entities (
idxinstead ofindex,binstead ofbuffer,rinstead ofreader).
5. Performance & Data Structures
- Capacity Pre-allocation: Always use
make([]T, 0, capacity)ormake(map[K]V, capacity)when the target size is known. This dramatically reduces heap allocations during append loops. - Nil vs Empty: A
nilslice (var names []string) is idiomatically correct, functionally identical to a zero-length slice, and requires zero allocations. Use it overnames := []string{}unless JSON formatting explicitly demands an empty array[]instead ofnull.
6. Testing
- Table-Driven Tests: Always utilize
[]struct{ name string ... }iterated viat.Run()for clear, modular test cases. - t.Helper(): Ensure any custom assertion or setup function immediately calls
t.Helper()so test runner output points to the actual failure site, not the inside of the utility function.
7. Tooling & Enforcement
- The agent should prioritize running
go fmt ./...andgolangci-lint run(if available) before confirming code completion.