1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# Go Code Rules
Applies to: `**/*.go`
Go-specific style and structure. Pairs with `go-testing.md` for tests and the
generic `verification.md` / `commits.md` rules. When in doubt, defer to
[Effective Go](https://go.dev/doc/effective_go) and the
[Go Code Review Comments](https://go.dev/wiki/CodeReviewComments) wiki.
## Formatting Is Not a Choice
All code is `gofmt`-clean. The bundle's PostToolUse hook runs `gofmt` and `go
vet` on every edit and blocks on a violation, and the pre-commit hook re-checks
staged files. Don't hand-format; let the tool decide. Use `goimports` (or your
editor's organize-imports) to keep the import block grouped and pruned.
## Errors
- Return errors; don't panic across an API boundary. `panic` is for genuinely
unrecoverable, programmer-error states (a corrupt invariant), not for control
flow or expected failures.
- Wrap with context as an error travels up: `fmt.Errorf("load config %s: %w",
path, err)`. The `%w` verb preserves the chain for `errors.Is` / `errors.As`.
- Handle every error where it occurs. Don't assign to `_` to silence one unless
you can state why it's safe in a comment.
- Define sentinel errors (`var ErrNotFound = errors.New("not found")`) or typed
errors when callers need to branch on the failure; callers match with
`errors.Is` / `errors.As`, never on the message string.
- Check errors before using the other return value — the value is unspecified
when `err != nil`.
## Naming and Shape
- Package names are short, lowercase, no underscores or camelCase; the name is
part of every call site (`http.Client`, not `httputil.HTTPClient`). Avoid
stutter: `chat.Message`, not `chat.ChatMessage`.
- Exported identifiers carry a doc comment that begins with the identifier
name. Unexported helpers earn a comment when the why isn't obvious.
- Accept interfaces, return concrete types. Keep interfaces small — one or two
methods — and define them in the consuming package, not alongside the
implementation.
- Avoid naked returns except in very short functions; named returns that travel
more than a few lines hide what's being returned.
## Concurrency
- Pass `context.Context` as the first parameter (`ctx context.Context`) through
any call chain that does I/O or can block; honor cancellation. Never store a
context in a struct.
- A goroutine needs a defined lifecycle — know who stops it and how. Don't
launch one without a way for it to exit (a closed channel, a cancelled
context, a `sync.WaitGroup`).
- Share memory by communicating (channels) or guard it (`sync.Mutex`); don't do
both for the same state. Run concurrent code under `go test -race`.
## Structure
- Keep functions focused. A function that fetches, parses, decodes, and saves
is four functions; the test difficulty in `go-testing.md` is the tell.
- Zero values should be useful where you can manage it (`bytes.Buffer`,
`sync.Mutex` need no constructor). When construction must validate, provide a
`NewThing` that returns `(*Thing, error)`.
- Don't add an interface, generic, or abstraction for a single implementation.
Add it when the second caller arrives, not in anticipation.
- `defer` cleanup (`f.Close()`, `mu.Unlock()`) right after acquiring the
resource, so the release is visible next to the acquire.
## Dependencies
- Keep `go.mod` tidy: run `go mod tidy` after changing imports, commit the
resulting `go.mod` and `go.sum` together.
- Prefer the standard library. Pull in a dependency when it earns its
maintenance and supply-chain cost, not for a function you could write in a
few lines.
## What Not to Do
- Don't ignore a returned error to make the line shorter.
- Don't reach for `interface{}` / `any` when a concrete type or a small
generic constraint says what you mean.
- Don't refactor surrounding code while fixing a bug — keep the diff scoped.
- Don't add comments restating what the code already says; comment the why.
|