Loading...
Loading...
Use when writing, reviewing, or refactoring Go code; when handling errors (fmt.Errorf, %w, sentinel, errors.Is, errors.As); when deciding between panic, error return, and log.Fatal; when writing tests (table-driven, t.Helper, t.Fatal vs t.Error, goroutines); when designing API surface (option struct, variadic options, channel direction, context); when naming functions, methods, packages, receivers, or test doubles; when laying out packages and imports; when initializing variables or building strings.
npx skill4agent add cicdteam/google-go-style google-go-stylereferences/*.mdGetUser()GetUser()bytes.Bufferbytes.BytesBufferwidget.Newwidget.NewWidgetthisselfme_func (c *Config)func (config *Config)URLIDHTTPDBUserIDServeHTTPuserIDurlPathUrlIdHttpStubFakeSpyMockAlwaysChargesAlwaysDeclinesutilcommonhelpermodel*_test.goicdbuserCountpollIntervalSandboxSbxfmt.Errorf("doing X: %w", err)%wouter: middle: inner%werrors.Iserrors.As%v%wfmt.Errorf("%w: invalid header", ErrParse)ErrFoovar ErrNotFound = errors.New("not found")os.Openfmt.Errorf("could not open settings.txt: %v", err)fmt.Errorf("launch codes unavailable: %v", err)return err\nfmt.Errorf("something bad happened")"Something bad happened."status.Errorf(codes.X, ...)%werrorcontext.Contexterrorreferences/errors.mderrorlog.Fatalpanicmaininiterrordefer recover()MustXMustParsetemplate.Mustrecover()panic("unreachable")log.FatalfFatalreferences/panics.mdassert.Equalrequire.NotNilif got != want { t.Errorf(...) }cmp.Equalcmp.Diffgo-cmpt.Errort.Fatalt.Fatalt.Runt.Fatalt.Errorcontinuet.FatalFailNowFatalfSkipNowt.Errort.Fatalwg.Wait(){name: "empty", input: "", want: ""}t.Helper()t.FatalfYourFunc(%v) = %v, want %vreferences/tests.md:=var x Ti := 42var coords Pointcoords := Point{}var t []stringt := []string{}lencaprangeappendnew(T)&T{}new&T{}==nillen(s) == 0+fmt.Sprintfstrings.Buildertext/templatemake([]T, 0, n)make(map[K]V, n)nif *x { ctx, cancel := ...; }ctxifctx, cancel = ...=var cancel func()references/strings-and-vars.mdcontext.Contextfunc F(ctx context.Context, ...) errorcontext.Context<-chan Tchan<- Tcontext.Context...Option*string*io.Readerreferences/api-design.md// Encode writes the JSON encoding of req to w.CloseStopctx.Donecontext.Contextreferences/documentation.mdinternal/utilcommonhelpermainimport .pbfoopb "path/to/foo_go_proto"references/package-layout.md%v%w| Situation | Choose | Why |
|---|---|---|
Caller will | | Preserves type/sentinel through the chain |
| Crossing an external boundary (RPC, IPC, storage); caller wants canonical codes | | Don't leak internal error types over the wire |
| Logging or human-display only; no programmatic inspection | | |
| Same error is logged here AND returned upward | | Wrapping a logged-then-returned error confuses the chain |
Sentinel categorisation first ( | | Reader sees the category first |
| Adding context around a wrapped error (the common case) | | Chain prints newest→oldest naturally: |
| Underlying error already carries this info | nothing — | Wrapping without adding info is noise |
| Just propagating without analysis | nothing — | Don't wrap for the sake of wrapping |
| Situation | Choose | Why |
|---|---|---|
| ≤ 3 parameters, all required, all distinct types | Positional args | Smallest mechanism |
| Many parameters, most callers set most of them | Option struct (last param) | Self-documenting field names; grows without breaking call sites |
| Many parameters, most callers set none | Variadic options ( | Zero overhead at simple call sites |
| Options need failure validation | Variadic options returning | Can't validate in struct construction |
| Third-party packages must define options | Variadic options with exported | Struct fields can't be extended |
| Same option set used by multiple functions | Option struct | Reuse + share + write helpers on the struct |
| First positional arg, never in option struct | Convention |
paniclog.Fatalerror| Situation | Choose | Why |
|---|---|---|
| Library detects normal failure | | Caller decides |
| Library detects an "impossible" invariant violation | | Caller can't recover anyway |
Bad flag/config in | | Stack trace useless; user wants the message |
| Internal package consistency check that has been verified by tests | | More reliable than |
Parser internals that always have a matching | | Plumbing errors through deep recursion is noise |
| Package-level var initializer needs a value derived from a fallible call | | Init-time only; |
| HTTP handler crashes mid-request | never | State is corrupted; let the process crash and restart |
t.Errort.Fatalt.Errorfcontinue| Situation | Choose |
|---|---|
Multiple independent assertions in one | |
| Setup failure — rest of test cannot proceed | |
| First failure makes subsequent assertions misleading (e.g. encoded ≠ expected, can't decode meaningfully) | |
| Table loop without subtests, this case is broken | |
Inside | |
| Worker goroutine inside a test | |
| Test helper called from main test goroutine | |
| Situation | Choose | Example |
|---|---|---|
| Initializing with a known non-zero value | | |
| Need a zero value, ready for use | | |
Need a | | |
Need a | | |
| Empty slice for return / accumulation | | not |
| Empty map (must be initialized to write) | | nil map can be read but not written |
| Pre-sized slice/map (perf-sensitive, size known) | | Don't over-pre-allocate |
references/errors.mderrors.Is/Asreferences/naming.mdreferences/api-design.mdreferences/tests.mdcmpreferences/panics.mdinitlog.Fatallog.Exitreferences/documentation.mdreferences/package-layout.mdinternal/references/strings-and-vars.mdnew&T{}