{"id":17775,"plugin_id":"plugins_6a7b1e3e30948191aea92f131b0f6ca9","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:14:20.991Z","digest":"0531e163863d4666b64416b36c7077fd85705a9f4ed26a21556d0b8689e5287b","against":null,"payload":{"description":"Use when organising functions in a Go file, formatting signatures, designing return values, or naming Printf-style helpers. Covers in-file ordering (type → ctor → exported → unexported → utils), multi-line signature shape, naked-parameter clarity, pointer-vs-value receivers, and the `f`-suffix rule. Apply proactively to any new function. Functional options: see go-functional-options.","included_files":[{"relative_path":"agents/openai.yaml","size_in_bytes":216},{"relative_path":"references/printf-and-stringer.md","size_in_bytes":2962},{"relative_path":"references/signatures.md","size_in_bytes":3529}],"name":"go-functions","skill_md_contents":"---\nname: go-functions\ndescription: \"Use when organising functions in a Go file, formatting signatures, designing return values, or naming Printf-style helpers. Covers in-file ordering (type → ctor → exported → unexported → utils), multi-line signature shape, naked-parameter clarity, pointer-vs-value receivers, and the `f`-suffix rule. Apply proactively to any new function. Functional options: see go-functional-options.\"\nlicense: MIT\ncompatibility: \"Designed for Claude Code or similar AI coding agents. Plain Go (any supported version).\"\nallowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*)\n---\n\n# Go Function Design\n\nA function's surface is read more often than its body. Optimize for the reader: predictable ordering in the file, signatures that scan, no hidden bool flags.\n\n## Core Rules\n\n1. **Order by use, not alphabet.** Types → constructors → exported methods → unexported → utilities.\n2. **Keep signatures on one line when reasonable.** When wrapping, every parameter on its own line with a trailing comma.\n3. **Never pass `*Interface`.** Pass the interface value; the underlying data can already be a pointer.\n4. **Replace naked `bool`/`int` parameters with named types** or add `/* name */` comments at call sites.\n5. **Printf-style functions end in `f`** so `go vet` can check the format.\n6. **Prefer `%q` over `%s` plus manual quoting** when formatting strings for errors and logs.\n\n## File Ordering\n\n```go\ntype Server struct{ ... }\n\nfunc NewServer(...) *Server { ... }     // constructor next to type\n\nfunc (s *Server) Start(ctx context.Context) error { ... } // exported\nfunc (s *Server) Stop() error           { ... }\n\nfunc (s *Server) acceptLoop() { ... }   // unexported\n\nfunc parseAddr(s string) (string, error) { ... } // file-local helper\n```\n\nRules:\n\n1. Types and their constructors sit together at the top.\n2. Exported methods come before unexported ones.\n3. File-local helpers go at the bottom.\n4. Within a section, follow rough call order.\n\n## Signature Formatting\n\n```go\n// Fits on one line — keep it on one line\nfunc Sum(xs []int) int\n\n// Too long — break with every param on its own line\nfunc (r *Repo) SaveTransaction(\n    ctx context.Context,\n    userID string,\n    tx Transaction,\n    opts ...SaveOption,\n) (string, error) {\n    ...\n}\n```\n\nThe trailing comma is required and `gofmt`-stable.\n\n### Avoid Naked Bool/Int Parameters\n\n```go\n// Bad — what does `true` mean?\nNewServer(\":8080\", true, 30, false)\n\n// Better — call-site comments\nNewServer(\":8080\", true /* tls */, 30 /* maxConn */, false /* readonly */)\n\n// Best — named types or options\nNewServer(\":8080\", WithTLS(), WithMaxConn(30))\n```\n\nWhen a single bool is genuinely binary and obvious from the function name (`SetVerbose(true)`), it's fine.\n\n> Read [references/signatures.md](references/signatures.md) for return-value styles, naked returns, function-as-parameter formatting, and the variadic-options call-site shape.\n\n## Pointers to Interfaces\n\n```go\n// Bad\nfunc process(r *io.Reader) { ... }\n\n// Good\nfunc process(r io.Reader) { ... }\n```\n\nAn interface value already carries a pointer-sized data word. `*io.Reader` is a pointer to an interface — almost always a mistake.\n\n## Printf and Stringer\n\nFunctions that accept a format string should end in `f`:\n\n```go\nfunc Logf(format string, args ...any)\n```\n\n`go vet` then checks that `%s`, `%d`, etc. match the argument types.\n\nWhen formatting strings into errors or logs, prefer `%q`:\n\n```go\nreturn fmt.Errorf(\"unknown key %q\", key) // unknown key \"foo\\nbar\"\n```\n\n`%q` quotes and escapes; `%s` plus manual quoting (`\"key \\\"\" + key + \"\\\"\"`) is fragile.\n\n> Read [references/printf-and-stringer.md](references/printf-and-stringer.md) for `%v` vs `%s` vs `%q`, implementing `fmt.Stringer` safely, avoiding `String()` infinite recursion, and `fmt.Formatter`.\n\n## Variadic Options at the Call Site\n\n```go\ndb.Open(addr,\n    db.WithCache(false),\n    db.WithLogger(log),\n    db.WithRetries(3),\n)\n```\n\nEach option on its own line, trailing comma. Use this layout whenever the call doesn't fit on a single line.\n\n## Constructors\n\nA constructor immediately follows its type. Use the short form when no error is possible:\n\n```go\ntype Counter struct{ n int }\n\nfunc NewCounter() *Counter { return &Counter{} }\n```\n\nReturn an error when construction can fail:\n\n```go\nfunc NewClient(addr string) (*Client, error) { ... }\n```\n\nDon't expose a half-built type through a constructor that \"always succeeds\" but requires `Init()` afterward.\n\n## Anti-Patterns\n\n| Anti-pattern | Why it hurts | Do this instead |\n|---|---|---|\n| Methods scattered randomly in the file | Hard to navigate | Group by type, exported-first |\n| Five-argument wrapped signature with no trailing comma | `gofmt` keeps reformatting | Trailing comma |\n| `func process(r *io.Reader)` | Pointer to interface | Pass `io.Reader` |\n| `Log(msg string, format bool, ...)` | Combines two concerns; `vet` blind | Separate `Log` and `Logf` |\n| `Open(\":8080\", true, false, 30)` | Unreadable booleans | Named options or `/* */` comments |\n| `fmt.Errorf(\"got %s\", key)` for arbitrary key | Special chars unclear in output | `%q` |\n| Returning `*MyError` (concrete pointer) | Typed-nil interface trap | Return `error` |\n\n## Verification Checklist\n\n- [ ] Types appear above their constructors; exported methods above unexported\n- [ ] Long signatures wrap with one parameter per line and a trailing comma\n- [ ] No pointer-to-interface parameters\n- [ ] Bool/int parameters are either obvious from the function name or named with `/* */` comments\n- [ ] Functions taking a format string end in `f`\n- [ ] Errors and logs use `%q` when formatting arbitrary strings\n- [ ] Constructors return `(*T, error)` when construction can fail — no half-built objects\n\n## References\n\n- [references/signatures.md](references/signatures.md) — multi-line wrapping, named results, function-typed parameters\n- [references/printf-and-stringer.md](references/printf-and-stringer.md) — format verbs, `fmt.Stringer`, recursion traps, `fmt.Formatter`\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}