| name | go-functions |
| 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. |
| user-invocable | false |
| license | MIT |
| compatibility | Designed for Claude Code or similar AI coding agents. Plain Go (any supported version). |
| metadata | {"author":"muratmirgun","version":"0.1.0","openclaw":{"emoji":"ƒ","homepage":"https://github.com/muratmirgun/gophers","requires":{"bins":["go"]},"install":[]}} |
| allowed-tools | Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) |
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/int parameters with named types or add /* name */ comments at call sites.
- Printf-style functions end in
f so go vet can check the format.
- Prefer
%q over %s plus manual quoting when formatting strings for errors and logs.
File Ordering
type Server struct{ ... }
func NewServer(...) *Server { ... }
func (s *Server) Start(ctx context.Context) error { ... }
func (s *Server) Stop() error { ... }
func (s *Server) acceptLoop() { ... }
func parseAddr(s string) (string, error) { ... }
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
func Sum(xs []int) int
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
NewServer(":8080", true, 30, false)
NewServer(":8080", true , 30 , false )
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
func process(r *io.Reader) { ... }
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)
%q quotes and escapes; %s plus manual quoting ("key \"" + key + "\"") is fragile.
Read references/printf-and-stringer.md for %v vs %s vs %q, implementing fmt.Stringer safely, avoiding String() infinite recursion, and fmt.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
References