Code Lib / 代码库
更新于 a month ago

golang-agent-skill

Ssaisudhir14
0.0k
saisudhir14/golang-agent-skill
84
Agent 评分

💡 摘要

该仓库提供编写生产就绪的Go代码的最佳实践,重点关注清晰性、简单性和可维护性。

🎯 适合人群

希望提高代码质量的Go开发者审查Go代码的软件工程师重构遗留Go应用程序的团队执行编码标准的技术负责人学习Go编程最佳实践的学生

🤖 AI 吐槽:看起来很能打,但别让配置把人劝退。

安全分析严重风险

风险:Critical。建议检查:是否执行 shell/命令行指令;是否发起外网请求(SSRF/数据外发);文件读写范围与路径穿越风险。以最小权限运行,并在生产环境启用前审计代码与依赖。


name: golang description: Best practices for writing production Go code. Use when writing, reviewing, or refactoring Go code. Covers error handling, concurrency, naming conventions, testing patterns, performance optimization, generics, and common pitfalls. Based on Google Go Style Guide, Uber Go Style Guide, Effective Go, and Go Code Review Comments. Updated for Go 1.25.

Go Best Practices

Battle-tested patterns from Google, Uber, and the Go team. These are practices proven in large-scale production systems, updated for modern Go (1.25).

Core Principles

Readable code prioritizes these attributes in order:

  1. Clarity: purpose and rationale are obvious to the reader
  2. Simplicity: accomplishes the goal in the simplest way
  3. Concision: high signal to noise ratio
  4. Maintainability: easy to modify correctly
  5. Consistency: matches surrounding codebase

Error Handling

Return Errors, Do Not Panic

Production code must avoid panics. Return errors and let callers decide how to handle them.

// Wrong func run(args []string) { if len(args) == 0 { panic("an argument is required") } } // Correct func run(args []string) error { if len(args) == 0 { return errors.New("an argument is required") } return nil } func main() { if err := run(os.Args[1:]); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }

Error Wrapping

Use %w when callers need to inspect the underlying error with errors.Is or errors.As. Use %v when you want to hide implementation details or at system boundaries.

// Preserve error chain for programmatic inspection if err != nil { return fmt.Errorf("load config: %w", err) } // Hide internal details at API boundaries if err != nil { return fmt.Errorf("database unavailable: %v", err) }

Keep context succinct. Avoid phrases like "failed to" that pile up as errors propagate.

// Wrong: produces "failed to x: failed to y: failed to create store: the error" return fmt.Errorf("failed to create new store: %w", err) // Correct: produces "x: y: new store: the error" return fmt.Errorf("new store: %w", err)

Joining Multiple Errors (Go 1.20+)

Use errors.Join when multiple operations can fail independently.

func validateUser(u User) error { var errs []error if u.Name == "" { errs = append(errs, errors.New("name required")) } if u.Email == "" { errs = append(errs, errors.New("email required")) } return errors.Join(errs...) } // Checking joined errors if err := validateUser(u); err != nil { if errors.Is(err, ErrNameRequired) { // handles even when joined with other errors } }

Error Types

Choose based on caller needs:

| Caller needs to match? | Message type | Approach | |------------------------|--------------|----------| | No | Static | errors.New("something bad") | | No | Dynamic | fmt.Errorf("file %q not found", file) | | Yes | Static | Exported var ErrNotFound = errors.New("not found") | | Yes | Dynamic | Custom error type with Error() method |

Sentinel Errors and errors.Is

Define sentinel errors for conditions callers need to check.

var ( ErrNotFound = errors.New("not found") ErrInvalidUser = errors.New("invalid user") ) // Checking wrapped errors if errors.Is(err, ErrNotFound) { // handles ErrNotFound even when wrapped } // Custom error types use errors.As var pathErr *os.PathError if errors.As(err, &pathErr) { fmt.Println("failed path:", pathErr.Path) }

Error Naming

Exported error variables use Err prefix. Custom error types use Error suffix.

var ( ErrNotFound = errors.New("not found") ErrInvalidUser = errors.New("invalid user") ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s not found", e.Resource) }

Handle Errors Once

Do not log an error and also return it. The caller will likely log it again.

// Wrong: logs and returns, causing duplicate logs if err != nil { log.Printf("could not get user %q: %v", id, err) return err } // Correct: wrap and return, let caller decide if err != nil { return fmt.Errorf("get user %q: %w", id, err) } // Also correct: log and degrade gracefully without returning error if err := emitMetrics(); err != nil { log.Printf("could not emit metrics: %v", err) }

Error Strings

Do not capitalize error strings or end with punctuation. They often appear mid-sentence in logs.

// Wrong fmt.Errorf("Something bad happened.") // Correct fmt.Errorf("something bad happened")

Indent Error Flow

Keep the happy path at minimal indentation. Handle errors first.

// Wrong if err != nil { // error handling } else { // normal code } // Correct if err != nil { return err } // normal code continues

Concurrency

Channel Size

Channels should have size zero (unbuffered) or one. Any other size requires justification about what prevents filling under load.

// Wrong: arbitrary buffer c := make(chan int, 64) // Correct c := make(chan int) // unbuffered: synchronous handoff c := make(chan int, 1) // buffered: allows one pending send

Goroutine Lifetimes

Document when and how goroutines exit. Goroutines blocked on channels will not be garbage collected even if the channel is unreachable.

// Document exit conditions func (w *Worker) Run(ctx context.Context) error { for { select { case <-ctx.Done(): return ctx.Err() case job := <-w.jobs: w.process(job) } } }

Use errgroup for Concurrent Operations

Prefer errgroup.Group over manual sync.WaitGroup for error-returning goroutines.

import "golang.org/x/sync/errgroup" func processItems(ctx context.Context, items []Item) error { g, ctx := errgroup.WithContext(ctx) for _, item := range items { g.Go(func() error { return process(ctx, item) }) } return g.Wait() // returns first error, cancels others via ctx } // With concurrency limit func processItemsLimited(ctx context.Context, items []Item) error { g, ctx := errgroup.WithContext(ctx) g.SetLimit(10) // max 10 concurrent goroutines for _, item := range items { g.Go(func() error { return process(ctx, item) }) } return g.Wait() }

Prefer Synchronous Functions

Synchronous functions are easier to reason about and test. Let callers add concurrency when needed.

// Wrong: forces concurrency on caller func Fetch(url string) <-chan Result // Correct: caller can wrap in goroutine if needed func Fetch(url string) (Result, error)

Zero Value Mutexes

The zero value of sync.Mutex is valid. Do not use pointers to mutexes or embed them in exported structs.

// Wrong mu := new(sync.Mutex) // Wrong: exposes Lock/Unlock in API type SMap struct { sync.Mutex data map[string]string } // Correct type SMap struct { mu sync.Mutex data map[string]string }

Atomic Operations (Go 1.19+)

Use the standard library's typed atomics. External packages are no longer necessary.

import "sync/atomic" type Counter struct { value atomic.Int64 } func (c *Counter) Inc() { c.value.Add(1) } func (c *Counter) Value() int64 { return c.value.Load() } // Also available: atomic.Bool, atomic.Pointer[T], atomic.Uint32, etc.

sync.Map Performance (Go 1.24+)

The sync.Map implementation was significantly improved in Go 1.24. Modifications of disjoint sets of keys are much less likely to contend on larger maps, and there is no longer any ramp-up time required to achieve low-contention loads.


Naming

MixedCaps Always

Go uses MixedCaps, never underscores. This applies even when it breaks other language conventions.

// Wrong MAX_LENGTH, max_length, HTTP_Server // Correct MaxLength, maxLength, HTTPServer

Initialisms

Initialisms maintain consistent case: URL not Url, ID not Id, HTTP not Http.

// Wrong xmlHttpRequest, serverId, apiUrl // Correct xmlHTTPRequest, serverID, apiURL

Short Variable Names

Variables should be short, especially with limited scope. The further from declaration a name is used, the more descriptive it needs to be.

// Good for local scope for i, v := range items { } r := bufio.NewReader(f) // Global or struct fields need more context var DefaultTimeout = 30 * time.Second

Receiver Names

Use one or two letter abbreviations of the type. Be consistent across methods. Do not use generic names like this, self, or me.

// Wrong func (this *Client) Get() {} func (c *Client) Get() {} func (cl *Client) Post() {} // inconsistent // Correct func (c *Client) Get() {} func (c *Client) Post() {}

Pointer vs Value Receivers

| Use pointer receiver when | Use value receiver when | |---------------------------|-------------------------| | Method modifies the receiver | Struct is small and immutable | | Struct is large (avoid copying) | Method doesn't modify state | | Consistency with other methods | Receiver is a map, func, or chan | | Struct contains sync.Mutex | Basic types (int, string, etc.) |

// Pointer: modifies state func (s *Server) Shutdown() error { s.running = false return s.listener.Close() } // Value: small, read-only func (p Point) Distance(q Point) float64 { return math.Hypot(p.X-q.X, p.Y-q.Y) }

Package Names

Package names are lowercase, single words. Avoid util, common, misc, api, types. The package name becomes part of the identifier at call sites.

// Wrong package chubby type ChubbyFile struct{} // chubby.ChubbyFile is redundant // Correct package chubby type File struct{} // chubby.File reads well

Avoid Repetition in Names

Do not repea

五维分析
清晰度9/10
创新性7/10
实用性9/10
完整性8/10
可维护性9/10
优缺点分析

优点

  • 全面覆盖Go最佳实践
  • 专注于错误处理和并发
  • 基于行业标准的指导方针

缺点

  • 对初学者可能过于复杂
  • 并非每个指导方针都有示例
  • 并非所有实践都适合每个项目

相关技能

pytorch

S
toolCode Lib / 代码库
92/ 100

“它是深度学习的瑞士军刀,但祝你好运能从47种安装方法里找到那个不会搞崩你系统的那一个。”

agno

S
toolCode Lib / 代码库
90/ 100

“它承诺成为智能体领域的Kubernetes,但得看开发者有没有耐心学习又一个编排层。”

nuxt-skills

S
toolCo-Pilot / 辅助式
90/ 100

“这本质上是一份组织良好的小抄,能把你的 AI 助手变成一只 Nuxt 框架的复读机。”

免责声明:本内容来源于 GitHub 开源项目,仅供展示和评分分析使用。

版权归原作者所有 saisudhir14.