Claude
Skills
Sign in
Back

golang

Included with Lifetime
$97 forever

Go language conventions, idioms, and toolchain. Invoke when task involves any interaction with Go code — writing, reviewing, refactoring, debugging, or understanding Go projects.

Productivity

What this skill does


# Go

Simplicity is the highest Go virtue. Resist abstraction until the cost of not abstracting is proven.

## References

Extended examples, code patterns, and detailed rationale for the rules below live in `${CLAUDE_SKILL_DIR}/references/`.

- **[`${CLAUDE_SKILL_DIR}/references/idioms.md`]** — Naming, declarations, interfaces, receivers, configuration,
  embedding: extended code examples for each idiom, Go/bad vs good comparisons, decision criteria tables
- **[`${CLAUDE_SKILL_DIR}/references/gotchas.md`]** — Variable shadowing, defer traps, slice mutation, strings, copy
  safety: annotated code showing each pitfall with fix patterns, global state examples
- **[`${CLAUDE_SKILL_DIR}/references/errors.md`]** — Error creation, wrapping, Is/As, structured errors (golib/e): error
  type decision tree, golib/e API (sentinels, fields, logging), wrapping context examples
- **[`${CLAUDE_SKILL_DIR}/references/concurrency.md`]** — Goroutines, channels, context, sync, errgroup, data races:
  worker lifecycle patterns, pipeline/fan-out/fan-in code, data race scenarios with fixes
- **[`${CLAUDE_SKILL_DIR}/references/testing.md`]** — Table tests, subtests, assertions, test doubles, benchmarks: full
  table-test template, testify usage, parallel subtests, httptest/iotest utilities
- **[`${CLAUDE_SKILL_DIR}/references/structure.md`]** — Project layout, packages, imports, file organization: package
  naming examples, import grouping, backward-incompatible change staged workflow

## Naming

### Variables — The Distance Rule

Name length scales with scope distance.

- **Loop index** — single letter: `i`, `j`, `k`
- **Short function local** — 1-3 chars: `r` (reader), `b` (buffer), `ctx`
- **Function parameter** — short but clear: `name`, `path`, `opts`
- **Package-level** — descriptive: `defaultTimeout`, `maxRetries`
- **Exported** — self-documenting: `ErrNotFound`, `DefaultClient`

### Receivers

Use 1-2 letter type abbreviation: `c` for `Client`, `s` for `Server`. Never `self`, `this`, `me`. Be consistent across
all methods of a type.

### Initialisms

All-caps for known initialisms: `URL`, `HTTP`, `ID`, `API`, `SQL`, `XML`. In mixed identifiers: `userID`, `httpClient`,
`xmlHTTPRequest`.

### Packages

- Short, lowercase, singular: `user`, `http`, `auth`
- Named by what they provide, not what they contain
- Never `util`, `common`, `misc`, `shared`, `helpers`, `types`
- Callers use package name as prefix — don't stutter: `widget.New()` not `widget.NewWidget()`

### Getters and Setters

No `Get` prefix on getters. Setter uses `Set` prefix: `u.Name()` not `u.GetName()`, `u.SetName(n)`.

### Interface Names

One-method interfaces use method name plus `-er`: `Reader`, `Writer`, `Formatter`, `Stringer`. Honor canonical names —
if your type has `String() string`, call it `String`, not `ToString`.

### Constants

MixedCaps only — never `ALL_CAPS` or `K` prefix. Name by role, not value. If a constant has no role beyond its value,
don't define it. `const MaxRetries = 12` (good) vs `const Twelve = 12` (bad).

### Unexported Globals

Plain lowercase: `defaultPort`, `maxRetries`. Error values use `err` prefix: `errNotFound`.

### Avoid Repetition

- Package name is part of every qualified reference: `widget.New()` not `widget.NewWidget()`
- Don't encode type in name: `var users int` not `var numUsers int`
- Strip context obvious from scope: method on `*Project` uses `Name()` not `ProjectName()`

## Interfaces

- **Consumer-side.** Define where used, not where implemented. Producers return concrete types.
- **No premature interfaces.** Wait for a concrete need. Don't define "for mocking."
- **Accept interfaces, return structs.**
- **Never pointer-to-interface.** Interfaces are already reference types.
- **Small interfaces.** Prefer 1-3 methods. `io.Reader` (1 method) is more powerful than any 10-method interface.
- **Compile-time verification.** `var _ http.Handler = (*Handler)(nil)`.

## Receivers

### Pointer vs Value

Use **pointer receiver** when: method mutates receiver, receiver contains `sync.Mutex` or similar, receiver is a large
struct, or in doubt (default to pointer).

Use **value receiver** when: receiver is a small immutable value type (like `time.Time`), receiver is a map/func/chan
(already reference types), all fields are value types with no mutability needs.

**Never mix** receiver types on a single type.

### Maps, Funcs, and Channels

Already reference types. Never use pointers to them: `func process(m map[string]int)` not
`func process(m *map[string]int)`.

## Context

- **First parameter.** `func Foo(ctx context.Context, ...)`.
- **Never store in structs.** Pass through call chains explicitly.
- **`context.Background()` only at the top level** — in `main()` or test setup.
- **Never include `context.Context` in option structs** — pass as separate parameter.

## Declarations

### Variable Style

- `var` for zero values: `var s string`, `var mu sync.Mutex`
- `:=` for initializations: `s := "hello"`, `n := computeSize()`
- Top-level: use `var`, omit type if obvious: `var defaultPort = 8080`
- Specify type when it differs from expression: `var e error = myError{}`

### Slices

- Nil slices are valid and preferred: `var s []string`
- Non-nil zero-length only when JSON encoding matters: `s := []string{}` (nil encodes as `null`, empty slice as `[]`)
- Check empty: `len(s) == 0`, not `s == nil`
- Pre-allocate when size known: `make([]T, 0, n)`

### Maps

- `make(map[K]V)` for programmatic population; `make(map[K]V, n)` with capacity hint
- Literal for fixed content: `map[string]int{"a": 1, "b": 2}`

### Structs

- Always use field names in literals
- Omit zero-value fields unless they provide meaningful context
- Zero-value struct: `var user User`
- Pointer: `&T{}` over `new(T)`

### Enums

Start `iota` at 1 to distinguish from zero-value (unless zero-value has meaning):
`const ( StatusActive Status = iota + 1; ... )`.

### Named Result Parameters

Use when they disambiguate or document caller obligations. Don't use just to enable naked returns, or when the name
repeats the type.

## Functions

- **Synchronous default.** Let callers add concurrency.
- **Return errors, never exit.** Only `main()` calls `os.Exit`/`log.Fatal`.
- **`defer` for cleanup.** Always.
- **Early return on error.** Happy path at minimum indentation.
- **Accept `io.Reader`, not filenames.** Improves reusability and testability.
- **Close transient resources.** `defer r.Body.Close()`, `defer rows.Close()`, `defer f.Close()`.

## Error Handling

### Core Rules

- **Always check errors.** Never discard with `_`.
- **Handle once.** Log OR return — never both. If logging, degrade gracefully (don't return the error). If returning,
  wrap with context and let the caller decide.
- **Wrap with context.** Prefer structured errors when the project uses them: `ErrNotFound.Wrap(err)` or
  `e.NewFrom("context", err)`. Standard fallback: `fmt.Errorf("context: %w", err)`. Avoid "failed to" prefix in both.
- **Error strings**: lowercase, no trailing punctuation. They compose: `"read config: open file: permission denied"`.
- **Don't panic.** Return errors. Reserve panic for truly irrecoverable states.
- **Use `errors.Is`/`errors.As`** — never `==` or direct type assertion on wrapped errors.

### Error Creation

- **No match needed, static message** — `errors.New("not found")`
- **No match needed, dynamic message** — `fmt.Errorf("file %q missing", name)`
- **Caller must match, static message** — exported `var ErrNotFound = errors.New(...)`
- **Caller must match, dynamic message** — custom error type with `Error()` method

### Sentinel Errors

Naming: exported `ErrXxx`, unexported `errXxx`. Always wrap sentinels before returning so callers use `errors.Is`, not
`==`.

### Custom Error Types

Naming: exported `XxxError`, unexported `xxxError`. Implement `Error() string`. Callers match with `errors.As`.

### Structured Errors (golib/e)

When a project uses a structured error package like golib/e, prefer it consistently 

Related in Productivity