AgentSkillsCN

go-best-practices

适用场景:当用户正在编写 Go 代码、探讨 Go 设计模式、审查 Go 代码,或在 Go 项目中提出诸如“在 Go 中,最好的做法是……”之类的疑问时。 不适用场景:非 Go 语言相关的问题,或与 Go 编程无关的通用性问题。

SKILL.md
--- frontmatter
name: go-best-practices
description: |
  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

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
  • Call t.Parallel() for independent tests
  • Use t.Helper() in test helpers
  • Test behavior, not implementation
  • Use testify for assertions when it improves readability
go
func TestAdd(t *testing.T) {
    tests := []struct {
        name string
        a, b int
        want int
    }{
        {"positive numbers", 2, 3, 5},
        {"with zero", 5, 0, 5},
        {"negative numbers", -2, -3, -5},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            t.Parallel()
            got := Add(tt.a, tt.b)
            if got != tt.want {
                t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
            }
        })
    }
}

Package Organization

  • Package names should be short and lowercase: user not userService
  • Avoid package-level state: Use dependency injection
  • One package per directory: No multi-package directories
  • internal/ for non-public packages: Prevents external imports

Naming Conventions

  • Use MixedCaps or mixedCaps: Not underscores
  • Acronyms should be consistent: URL, HTTP, ID (all caps for exported, all lower otherwise)
  • Short names for short scopes: i for loop index, err for errors
  • Descriptive names for exports: ReadConfig not RC

Code Organization

  • Declare variables close to use
  • Use defer for cleanup immediately after resource acquisition
  • Group related declarations
  • Order: constants, variables, types, functions

Anti-Patterns to Avoid

  • Empty interface (interface{} or any): Use specific types when possible
  • Global state: Prefer dependency injection
  • Naked returns: Always name what you're returning
  • Stuttering: user.UserService should be user.Service
  • init() functions: Prefer explicit initialization
  • Complex constructors: Use functional options pattern

When in Doubt

  • Refer to Effective Go
  • Check the Go standard library for examples
  • Use go vet and staticcheck for automated guidance

This skill is powered by Gopher Guides training materials. For comprehensive Go training, visit gopherguides.com.