# Go Best Practices

> Go coding best practices. Use when writing or reviewing Go code. Covers error handling, concurrency, and idiomatic patterns.

- Skill: `taoidle/go-best-practices` (Agent Skill)
- Install (CLI): `npx skillmds@latest add taoidle/go-best-practices`
- Raw SKILL.md: https://api.skillmd.com/api/skills/taoidle/go-best-practices/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: taoidle (https://skillmd.com/u/taoidle)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/taoidle/go-best-practices

---


# Go Best Practices

## Code Style

| Rule | Guideline |
|------|-----------|
| Formatter | `gofmt` or `goimports` |
| Linter | `golangci-lint` |
| Naming | Short, clear; avoid stuttering |
| Comments | Godoc for exported items |

## Error Handling

| Rule | Guideline |
|------|-----------|
| Always check | Never ignore errors |
| Wrap context | `fmt.Errorf("ctx: %w", err)` |
| Sentinel errors | `var ErrNotFound = errors.New(...)` |

```go
func Load(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("load config %s: %w", path, err)
    }
    // ...
}
```

## Project Structure

```
cmd/appname/main.go
internal/config/
internal/service/
go.mod
```

## Concurrency

| Pattern | Usage |
|---------|-------|
| `context.Context` | Cancellation, timeouts |
| `sync.WaitGroup` | Wait for goroutines |
| `errgroup.Group` | Goroutines with errors |

```go
func Process(ctx context.Context, items []Item) error {
    for _, item := range items {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
            if err := process(item); err != nil { return err }
        }
    }
    return nil
}
```

## Anti-Patterns

| Avoid | Use Instead |
|-------|-------------|
| Naked returns | Explicit returns |
| `panic` for errors | Return errors |
| Large interfaces | Small, focused |
| `init()` | Explicit init |

## Testing (Table-Driven)

```go
func TestParse(t *testing.T) {
    tests := []struct{ name, input string; want int; wantErr bool }{
        {"valid", "42", 42, false},
        {"invalid", "abc", 0, true},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := Parse(tt.input)
            if (err != nil) != tt.wantErr { t.Errorf("err=%v, want=%v", err, tt.wantErr) }
            if got != tt.want { t.Errorf("got=%v, want=%v", got, tt.want) }
        })
    }
}
```

