Skip to content
Back to skills

Go Pro

ASecurity

Idiomatic Go: project layout, error handling, concurrency with goroutines/channels, interfaces, and tooling. Use when writing, reviewing, or structuring Go programs and services.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentsgosqltestingapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add aicodedecode/awesome-muse-skills --skill go-pro --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Go Pro?

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

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

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-pro
description: Idiomatic Go: project layout, error handling, concurrency with goroutines/channels, interfaces, and tooling. Use when writing, reviewing, or structuring Go programs and services.
category: development
---

# Go Pro

## Overview

Go rewards **simplicity and explicitness**: small interfaces, explicit error handling, and
concurrency as a first-class but carefully-managed tool. The best Go code is boring in the best
way — obvious control flow, minimal abstraction, and the standard library doing heavy lifting.

This skill covers professional Go: module layout, error handling philosophy, goroutine/channel
patterns, interface design, and the tooling (`go vet`, `gofmt`, linters) that keeps Go codebases
uniform and reliable.

## When to use

- Starting or structuring a Go module/service.
- Writing or reviewing Go for idiom and correctness.
- Designing concurrency (goroutines, channels, worker pools).
- Handling errors, context propagation, and graceful shutdown.
- Setting up linting, testing, and CI for Go.

## Core concepts

- **Errors are values.** Return them, check them, wrap them with context (`fmt.Errorf("…: %w", err)`).
  Sentinel errors for expected cases, custom types when callers must distinguish. Never ignore an
  error without a comment saying why (`_ = f.Close()` on read-only files is the rare exception).
- **Interfaces: small and consumer-defined.** Accept interfaces, return structs. The `io.Reader` /
  `io.Writer` philosophy: one- or two-method interfaces defined where *used*, not where implemented.
  Empty interfaces (`any`) in APIs push type problems to runtime — constrain with generics or
  concrete types.
- **Concurrency: share memory by communicating.** Goroutines + channels for orchestration; `sync`
  primitives for shared state. `context.Context` carries cancellation/deadlines through call chains
  — always the first parameter, never stored in structs. Worker pools bound concurrency; `errgroup`
  manages fan-out/fan-in with error propagation.
- **Project layout (standard-ish).** `cmd/<app>/main.go` (thin), `internal/` for private packages,
  `pkg/` only for genuinely reusable libraries. Flat is fine for small services — don't create
  twelve packages for 2,000 lines. Package names: short, lowercase, no underscores (`httpx` not
  `http_utils`).
- **Defer for cleanup, and mind loop gotchas.** `defer` runs LIFO at function return — perfect for
  `Close`/`Unlock`. In Go 1.22+ loop variables are per-iteration (the old capture bug is gone),
  but know your toolchain version when reading older code.
- **Testing is built in.** Table-driven tests, `t.Run` subtests, `testify` optional but common,
  `httptest` for handlers, `-race` in CI always. Benchmarks (`BenchmarkXxx`) for hot paths.

## Practical workflow

1. **Scaffold:** `go mod init <module>`, `cmd/` + `internal/` layout, `.golangci.yml` with a
   curated linter set, `go vet` + `gofmt -l` in CI (gofmt diff = fail).
2. **Write the happy path first**, then handle every error return explicitly. Wrap with context
   at boundaries (where you have the most information), check/log at the top.
3. **Thread `context.Context`** through I/O paths; respect cancellation in loops and workers;
   set timeouts on outbound calls (`http.Client{Timeout: …}`).
4. **Concurrency pattern selection:**
   - Fan-out/fan-in with results → `errgroup.Group` + channels.
   - Bounded parallelism → worker pool with buffered channel.
   - Periodic work → `time.Ticker` + context cancellation, not `time.Sleep` loops.
   - Never leak goroutines: every spawned goroutine must have an exit path.
5. **Graceful shutdown.** Catch SIGTERM/SIGINT → cancel root context → stop accepting → drain
   in-flight with a timeout → exit. `http.Server.Shutdown(ctx)` exists; use it.
6. **Review checklist:** errors wrapped with context, no ignored errors, contexts plumbed,
   goroutine exit paths, no data races (`go test -race`), exported symbols documented.

Idiomatic snippets:

```go
// Wrap errors with context at the boundary
func LoadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("load config %s: %w", path, err)
    }
    ...
}

// errgroup fan-out
g, ctx := errgroup.WithContext(ctx)
for _, id := range ids {
    g.Go(func() error { return process(ctx, id) })
}
if err := g.Wait(); err != nil { return err }
```

## Common pitfalls

- **Ignoring errors.** `val, _ := strconv.Atoi(s)` sprinkled everywhere. Handle or document why not.
- **Goroutine leaks.** Spawning goroutines blocked forever on channel sends with no receiver.
  Every goroutine needs a `ctx.Done()` / close-channel exit.
- **Copying locks.** Passing `sync.Mutex` by value (go vet flags it). Use pointers for structs
  containing locks; `go vet` in CI catches this.
- **Interface pollution.** `type Service interface { 25 methods }` — huge interfaces are hard to
  mock and hard to implement. Small interfaces, composed as needed.
- **Premature optimization with sync.** Reaching for atomics and lock-free tricks before profiling.
  A plain mutex is fast; correctness first, `pprof` second.
- **Global state.** Package-level `var db *sql.DB` mutated in tests causes order-dependent flakes.
  Inject dependencies; keep globals read-only after init.
- **Not running `-race`.** Data races are silent until production. `go test -race ./...` in CI,
  always — it's the cheapest concurrency bug-finder in the industry.

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…