Skip to content
Back to skills

Go Functions

ASecurity

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.

  • 8 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 9, 2026
ai-agentsgobashgit

Works with

  • claude code
  • cli

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned June 9, 2026

npx -y skills add muratmirgun/gophers --skill go-functions --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Go Functions?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Go Functions
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/muratmirgun-go-functions/badge)](https://www.skillsdirectory.com/skills/muratmirgun-go-functions)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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

1. **Order by use, not alphabet.** Types → constructors → exported methods → unexported → utilities.
2. **Keep signatures on one line when reasonable.** When wrapping, every parameter on its own line with a trailing comma.
3. **Never pass `*Interface`.** Pass the interface value; the underlying data can already be a pointer.
4. **Replace naked `bool`/`int` parameters with named types** or add `/* name */` comments at call sites.
5. **Printf-style functions end in `f`** so `go vet` can check the format.
6. **Prefer `%q` over `%s` plus manual quoting** when formatting strings for errors and logs.

## File Ordering

```go
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:

1. Types and their constructors sit together at the top.
2. Exported methods come before unexported ones.
3. File-local helpers go at the bottom.
4. Within a section, follow rough call order.

## Signature Formatting

```go
// 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

```go
// 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](references/signatures.md) for return-value styles, naked returns, function-as-parameter formatting, and the variadic-options call-site shape.

## Pointers to Interfaces

```go
// 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`:

```go
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`:

```go
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](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

```go
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:

```go
type Counter struct{ n int }

func NewCounter() *Counter { return &Counter{} }
```

Return an error when construction can fail:

```go
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 `%q` when formatting arbitrary strings
- [ ] Constructors return `(*T, error)` when construction can fail — no half-built objects

## References

- [references/signatures.md](references/signatures.md) — multi-line wrapping, named results, function-typed parameters
- [references/printf-and-stringer.md](references/printf-and-stringer.md) — format verbs, `fmt.Stringer`, recursion traps, `fmt.Formatter`

Files in this skill

  • SKILL.md6.1 KB
  • references/printf-and-stringer.md2.9 KB
  • references/signatures.md3.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.