Go functions
26 production-grade Go skills for Claude Code, Gemini CLI, and opencode.
npx -y skills add muratmirgun/gophers --skill go-functionsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
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.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
6.1 KB, as published. Nobody here has run it
Go Function Design
A 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.
Core Rules
- Order by use, not alphabet. Types → constructors → exported methods → unexported → utilities.
- Keep signatures on one line when reasonable. When wrapping, every parameter on its own line with a trailing comma.
- Never pass
*Interface. Pass the interface value; the underlying data can already be a pointer. - Replace naked
bool/intparameters with named types or add/* name */comments at call sites. - Printf-style functions end in
fsogo vetcan check the format. - Prefer
%qover%splus manual quoting when formatting strings for errors and logs.
File Ordering
type Server struct{ ... }
func NewServer(...) *Server { ... } // constructor next to type
func (s *Server) Start(ctx context.Context) error { ... } // exported
func (s *Server) Stop() error { ... }
func (s *Server) acceptLoop() { ... } // unexported
func parseAddr(s string) (string, error) { ... } // file-local helper
Rules:
- Types and their constructors sit together at the top.
- Exported methods come before unexported ones.
- File-local helpers go at the bottom.
- Within a section, follow rough call order.
Signature Formatting
// Fits on one line — keep it on one line
func Sum(xs []int) int
// Too long — break with every param on its own line
func (r *Repo) SaveTransaction(
ctx context.Context,
userID string,
tx Transaction,
opts ...SaveOption,
) (string, error) {
...
}
The trailing comma is required and gofmt-stable.
Avoid Naked Bool/Int Parameters
// Bad — what does `true` mean?
NewServer(":8080", true, 30, false)
// Better — call-site comments
NewServer(":8080", true /* tls */, 30 /* maxConn */, false /* readonly */)
// Best — named types or options
NewServer(":8080", WithTLS(), WithMaxConn(30))
When a single bool is genuinely binary and obvious from the function name (SetVerbose(true)), it's fine.
Read references/signatures.md for return-value styles, naked returns, function-as-parameter formatting, and the variadic-options call-site shape.
Pointers to Interfaces
// Bad
func process(r *io.Reader) { ... }
// Good
func process(r io.Reader) { ... }
An interface value already carries a pointer-sized data word. *io.Reader is a pointer to an interface — almost always a mistake.
Printf and Stringer
Functions that accept a format string should end in f:
func Logf(format string, args ...any)
go vet then checks that %s, %d, etc. match the argument types.
When formatting strings into errors or logs, prefer %q:
return fmt.Errorf("unknown key %q", key) // unknown key "foo\nbar"
%q quotes and escapes; %s plus manual quoting ("key \"" + key + "\"") is fragile.
Read references/printf-and-stringer.md for
%vvs%svs%q, implementingfmt.Stringersafely, avoidingString()infinite recursion, andfmt.Formatter.
Variadic Options at the Call Site
db.Open(addr,
db.WithCache(false),
db.WithLogger(log),
db.WithRetries(3),
)
Each option on its own line, trailing comma. Use this layout whenever the call doesn't fit on a single line.
Constructors
A constructor immediately follows its type. Use the short form when no error is possible:
type Counter struct{ n int }
func NewCounter() *Counter { return &Counter{} }
Return an error when construction can fail:
func NewClient(addr string) (*Client, error) { ... }
Don't expose a half-built type through a constructor that "always succeeds" but requires Init() afterward.
Anti-Patterns
| Anti-pattern | Why it hurts | Do this instead |
|---|---|---|
| Methods scattered randomly in the file | Hard to navigate | Group by type, exported-first |
| Five-argument wrapped signature with no trailing comma | gofmt keeps reformatting | Trailing comma |
func process(r *io.Reader) | Pointer to interface | Pass io.Reader |
Log(msg string, format bool, ...) | Combines two concerns; vet blind | Separate Log and Logf |
Open(":8080", true, false, 30) | Unreadable booleans | Named options or /* */ comments |
fmt.Errorf("got %s", key) for arbitrary key | Special chars unclear in output | %q |
Returning *MyError (concrete pointer) | Typed-nil interface trap | Return error |
Verification Checklist
- Types appear above their constructors; exported methods above unexported
- Long signatures wrap with one parameter per line and a trailing comma
- No pointer-to-interface parameters
- Bool/int parameters are either obvious from the function name or named with
/* */comments - Functions taking a format string end in
f - Errors and logs use
%qwhen formatting arbitrary strings - Constructors return
(*T, error)when construction can fail — no half-built objects
References
- references/signatures.md — multi-line wrapping, named results, function-typed parameters
- references/printf-and-stringer.md — format verbs,
fmt.Stringer, recursion traps,fmt.Formatter