WHEN: User is writing Go code, asking about Go patterns, reviewing Go code, or asking questions like "what's the best way to..." in Go projects WHEN NOT: Non-Go languages, general questions unrelated to Go programming
View on GitHubSelect agents to install to:
npx add-skill https://github.com/gopherguides/gopher-ai/blob/main/plugins/go-dev/skills/go-best-practices/SKILL.md -a claude-code --skill go-best-practicesInstallation paths:
.claude/skills/go-best-practices/# Go Best Practices Skill
Apply idiomatic Go patterns and best practices from Gopher Guides training materials.
## When Helping with Go Code
### Error Handling
- **Wrap errors with context**: Use `fmt.Errorf("operation failed: %w", err)`
- **Check errors immediately**: Don't defer error checking
- **Return errors, don't panic**: Panics are for unrecoverable situations only
- **Create sentinel errors** for expected conditions: `var ErrNotFound = errors.New("not found")`
- **Use errors.Is() and errors.As()** for error comparison
```go
// Good
if err != nil {
return fmt.Errorf("failed to process user %s: %w", userID, err)
}
// Avoid
if err != nil {
log.Fatal(err) // Don't panic on recoverable errors
}
```
### Interface Design
- **Accept interfaces, return structs**: Functions should accept interfaces but return concrete types
- **Keep interfaces small**: Prefer single-method interfaces
- **Define interfaces at point of use**: Not where the implementation lives
- **Don't export interfaces unnecessarily**: Only if users need to mock
```go
// Good - interface defined by consumer
type Reader interface {
Read(p []byte) (n int, err error)
}
func ProcessData(r Reader) error { ... }
// Avoid - exporting implementation details
type Service interface {
Method1() error
Method2() error
Method3() error // Too many methods
}
```
### Concurrency
- **Don't communicate by sharing memory; share memory by communicating**
- **Use channels for coordination, mutexes for state**
- **Always pass context.Context as first parameter**
- **Use errgroup for coordinating goroutines**
- **Avoid goroutine leaks**: Ensure goroutines can exit
```go
// Good - using errgroup
g, ctx := errgroup.WithContext(ctx)
for _, item := range items {
item := item // capture loop variable
g.Go(func() error {
return process(ctx, item)
})
}
if err := g.Wait(); err != nil {
return err
}
```
### Testing
- **Use table-driven tests** for multiple scenarios