go-best-practices
Scannednpx machina-cli add skill Taoidle/plan-cascade/go --openclawFiles (1)
SKILL.md
2.1 KB
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(...) |
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 |
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)
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) }
})
}
}
Source
git clone https://github.com/Taoidle/plan-cascade/blob/master/builtin-skills/go/SKILL.mdView on GitHub Overview
Go Best Practices covers error handling, concurrency, and idiomatic patterns to help you write and review robust Go code. It emphasizes consistent style, meaningful error propagation, and safe concurrent execution.
How This Skill Works
It defines concrete rules for error handling (always check errors, wrap with %w for context, use sentinel errors) and prescribes idiomatic concurrency using context.Context, sync.WaitGroup, and errgroup. It also covers project structure, naming, and documentation conventions to promote readability.
When to Use It
- When starting a new Go project to set conventions.
- During code reviews to enforce consistency and idioms.
- When refactoring error handling to avoid ignored errors.
- When implementing concurrent tasks with proper cancellation.
- When writing or updating tests, especially table-driven tests.
Quick Start
- Step 1: Format and lint your code with gofmt, goimports, and golangci-lint.
- Step 2: Review and wrap errors; avoid ignoring them.
- Step 3: Adopt safe concurrency with context, WaitGroup or errgroup; fix anti-patterns.
Best Practices
- Format with gofmt and goimports; lint with golangci-lint.
- Name succinctly; provide Godoc for exported items.
- Always check and wrap errors; use sentinel errors.
- Use context.Context for cancellation and timeouts; choose appropriate concurrency primitives (WaitGroup or errgroup).
- Avoid anti-patterns: naked returns, panics, large interfaces, and init; keep code and packages well-structured.
Example Use Cases
- Load demonstrates wrapping errors with context by using fmt.Errorf and %w.
- Process shows cancellation with a context and early return on ctx.Err().
- Sentinel error pattern with defined ErrNotFound for domain errors.
- Table-driven tests pattern as seen in TestParse.
- Using errgroup to run concurrent tasks and propagate errors.
Frequently Asked Questions
Add this skill to your agents