go-anti-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Go Anti-Patterns Skill

Go语言反模式处理技能

Operator Context

技能运行机制

This skill operates as an operator for Go anti-pattern detection and remediation, configuring Claude's behavior to identify over-engineering, premature abstraction, and idiomatic violations in Go code. It implements the Pattern Recognition architectural approach -- scan, detect, explain, remediate -- with Domain Intelligence embedded in Go-specific heuristics.
本技能作为Go语言反模式检测与修复的操作组件,用于配置Claude的行为,以识别Go代码中的过度工程、过早抽象以及不符合语言惯用法的问题。它采用模式识别架构方法——扫描、检测、解释、修复——并嵌入了针对Go语言的领域智能启发式规则。

Hardcoded Behaviors (Always Apply)

硬性规则(始终适用)

  • CLAUDE.md Compliance: Read and follow repository CLAUDE.md before reviewing
  • Over-Engineering Prevention: Flag complexity only when simpler Go exists; never add complexity while removing it
  • Evidence-Based Detection: Every flagged anti-pattern must cite specific code location and explain concrete harm
  • YAGNI Enforcement: Do not suggest abstractions (interfaces, generics, channels) without 2+ concrete use cases
  • Preserve Working Code: Flag patterns for awareness; do not rewrite working code without explicit request
  • Idiomatic Go Priority: Recommendations must align with Go proverbs and standard library conventions
  • 遵循CLAUDE.md规范:在审查代码前阅读并遵循仓库中的CLAUDE.md文档
  • 防止过度工程:仅当存在更简洁的Go实现方案时才标记复杂度问题;修复过程中绝不能引入新的复杂度
  • 基于证据的检测:每个标记的反模式必须引用具体代码位置,并说明其造成的实际危害
  • 执行YAGNI原则:在没有2个及以上具体使用场景的情况下,不建议引入抽象(接口、泛型、通道)
  • 保留可运行代码:仅标记模式以引起注意;未经明确请求,不得重写可运行代码
  • 优先遵循Go语言惯用法:建议必须符合Go语言谚语及标准库约定

Default Behaviors (ON unless disabled)

默认行为(默认开启,可关闭)

  • Quick Detection Table: Use the detection guide to scan code systematically
  • One Pattern at a Time: Address anti-patterns individually, not in bulk rewrites
  • Context-Aware Severity: Rate impact as low/medium/high based on codebase context
  • Show Both Versions: Present current code alongside recommended alternative
  • Root Cause Explanation: Explain WHY the pattern is harmful, not just that it is
  • Scope Limitation: Only flag patterns within the files under review
  • 快速检测表:使用检测指南系统性地扫描代码
  • 逐个处理模式:单独处理每个反模式,不进行批量重写
  • 上下文感知的严重程度:根据代码库上下文将影响程度分为低/中/高
  • 展示对比版本:同时呈现当前代码与推荐的替代方案
  • 根因解释:解释该模式为何有害,而非仅指出其是反模式
  • 范围限制:仅标记待审查文件中的模式

Optional Behaviors (OFF unless enabled)

可选行为(默认关闭,可开启)

  • Full Codebase Scan: Scan entire repository for anti-pattern instances
  • Metrics Collection: Count anti-pattern occurrences by type
  • Auto-Refactor: Apply fixes directly instead of only flagging them
  • Historical Analysis: Check git history for when anti-patterns were introduced
  • 全代码库扫描:扫描整个仓库以查找反模式实例
  • 指标收集:按类型统计反模式出现次数
  • 自动重构:直接应用修复,而非仅标记问题
  • 历史分析:检查git历史以确定反模式的引入时间

What This Skill CAN Do

本技能可实现的功能

  • Detect the 7 core Go anti-patterns with code-level evidence
  • Provide idiomatic Go alternatives with before/after examples
  • Explain the concrete harm each pattern causes (complexity, bugs, maintenance)
  • Distinguish between genuine anti-patterns and acceptable trade-offs
  • Guide incremental cleanup without destabilizing working code
  • 结合代码级证据检测7种核心Go语言反模式
  • 提供符合Go语言惯用法的替代方案,并附带前后对比示例
  • 解释每种模式造成的实际危害(复杂度、bug、维护成本)
  • 区分真正的反模式与可接受的权衡方案
  • 指导增量式清理,避免破坏可运行代码

What This Skill CANNOT Do

本技能无法实现的功能

  • Rewrite entire codebases (use systematic-refactoring instead)
  • Detect non-Go anti-patterns (use language-specific skills)
  • Optimize performance (use performance profiling tools)
  • Replace code review (use go-code-review for comprehensive review)
  • Judge patterns without seeing the surrounding context

  • 重写整个代码库(请使用systematic-refactoring技能)
  • 检测非Go语言的反模式(请使用对应语言的专属技能)
  • 优化性能(请使用性能分析工具)
  • 替代代码审查(请使用go-code-review技能进行全面审查)
  • 在不了解周边上下文的情况下评判模式

Instructions

操作步骤

Step 1: Scan for Anti-Patterns

步骤1:扫描反模式

Use the Quick Detection Guide to systematically check code under review.
Code SmellDetection QuestionIf Yes
Interface with one implDo you have 2+ implementations?Remove interface
Goroutine + WaitGroupIs work I/O bound or CPU heavy?Use sequential loop
fmt.Errorf("error: %w")
Does wrap add context?Add operation + ID
Channel for return valueIs there actual concurrency?Use regular return
Generic with one typeUsed with multiple types?Use concrete type
Context in pure functionDoes function do I/O?Remove context param
Tiny extracted functionCalled from 2+ places?Inline it
使用快速检测指南系统性地检查待审查代码。
代码异味检测问题如果是
仅一个实现的接口是否有2个及以上的实现?移除接口
Goroutine + WaitGroup操作是I/O密集型还是CPU密集型?使用顺序循环
fmt.Errorf("error: %w")
包装是否添加了上下文信息?添加操作内容及ID
用于返回值的通道是否存在实际并发场景?使用常规返回值
仅一种类型的泛型是否用于多种类型?使用具体类型
纯函数中的Context函数是否执行I/O操作?移除Context参数
提取的小型函数是否在2个及以上位置被调用?内联该函数

Step 2: Classify and Report

步骤2:分类并报告

For each detected anti-pattern, produce a structured report:
ANTI-PATTERN DETECTED:
- Pattern: [Name from catalog below]
- Location: [File:line]
- Issue: [What is wrong with current approach]
- Impact: [Complexity/performance/maintainability cost]
- Severity: [Low/Medium/High]
- Recommendation: [Simpler Go alternative]
针对每个检测到的反模式,生成结构化报告:
检测到反模式:
- 模式:[以下目录中的名称]
- 位置:[文件:行号]
- 问题:当前实现方式的问题所在
- 影响:[复杂度/性能/可维护性成本]
- 严重程度:[低/中/高]
- 建议:[更简洁的Go语言替代方案]

Step 3: Provide Remediation

步骤3:提供修复方案

Show before/after code. Reference the detailed examples in
references/code-examples.md
for full patterns.

展示前后对比代码。完整模式请参考
references/code-examples.md
中的详细示例。

Anti-Pattern Catalog

反模式目录

AP-1: Premature Interface Abstraction

AP-1:过早接口抽象

Detection: Interface exists with exactly one implementation.
Why it harms Go code:
  • Interfaces should be discovered, not invented upfront
  • Go philosophy: "Accept interfaces, return concrete types"
  • Adds cognitive overhead without providing flexibility
Fix: Start with concrete types. Add interface ONLY when you need 2+ implementations (e.g., adding a mock for tests or a cache layer).
go
// BAD: Interface before need
type UserRepository interface {
    GetUser(id string) (*User, error)
}
type PostgresUserRepository struct{ db *sql.DB }
// Only one implementation exists

// GOOD: Concrete type first
type UserRepository struct{ db *sql.DB }
func (r *UserRepository) GetUser(id string) (*User, error) { ... }
// Add interface when second implementation appears
检测方式:接口仅存在一个实现。
为何会损害Go代码
  • 接口应是被发现的,而非预先设计的
  • Go语言哲学:“接受接口,返回具体类型”
  • 增加认知负担却未提供灵活性
修复方案:从具体类型开始。仅当需要2个及以上实现时(例如为测试添加mock或缓存层)再添加接口。
go
// 不良示例:提前定义接口
type UserRepository interface {
    GetUser(id string) (*User, error)
}
type PostgresUserRepository struct{ db *sql.DB }
// 仅存在一个实现

// 良好示例:先使用具体类型
type UserRepository struct{ db *sql.DB }
func (r *UserRepository) GetUser(id string) (*User, error) { ... }
// 当出现第二个实现时再添加接口

AP-2: Goroutine Overkill for Sequential Work

AP-2:针对顺序操作滥用Goroutine

Detection: Goroutines + WaitGroup + channels for operations that are not I/O bound or CPU intensive.
Why it harms Go code:
  • Concurrency overhead may exceed processing time
  • Makes debugging harder (race conditions, unpredictable ordering)
  • WaitGroup + channel + error handling adds significant complexity
Fix: Use a sequential loop. Add concurrency ONLY after profiling proves it helps for I/O-bound or CPU-intensive work.
go
// BAD: Goroutines for simple iteration
errCh := make(chan error, len(items))
var wg sync.WaitGroup
for _, item := range items {
    wg.Add(1)
    go func(item Item) { defer wg.Done(); ... }(item)
}

// GOOD: Sequential is clearer
for _, item := range items {
    if err := process(item); err != nil {
        return fmt.Errorf("process item %s: %w", item.ID, err)
    }
}
检测方式:针对非I/O密集型或非CPU密集型操作使用Goroutines + WaitGroup + 通道。
为何会损害Go代码
  • 并发开销可能超过处理时间
  • 增加调试难度(竞态条件、不可预测的执行顺序)
  • WaitGroup + 通道 + 错误处理会显著增加复杂度
修复方案:使用顺序循环。仅当性能分析证明对I/O密集型或CPU密集型操作有帮助时,再添加并发。
go
// 不良示例:为简单迭代使用Goroutine
errCh := make(chan error, len(items))
var wg sync.WaitGroup
for _, item := range items {
    wg.Add(1)
    go func(item Item) { defer wg.Done(); ... }(item)
}

// 良好示例:顺序执行更清晰
for _, item := range items {
    if err := process(item); err != nil {
        return fmt.Errorf("process item %s: %w", item.ID, err)
    }
}

AP-3: Error Wrapping Without Context

AP-3:无上下文的错误包装

Detection: Error wraps that add "error", "failed", or no meaningful information.
Why it harms Go code:
  • Error messages should form a narrative from top to bottom
  • Missing context makes debugging require source code inspection
  • Vague wraps like "error: %w" or "failed: %w" waste the wrap
Fix: Include the operation being performed and relevant identifiers.
go
// BAD: No context
return nil, fmt.Errorf("error: %w", err)
return nil, fmt.Errorf("failed: %w", err)

// GOOD: Narrative context
return nil, fmt.Errorf("load config from %s: %w", path, err)
return nil, fmt.Errorf("parse config JSON from %s: %w", path, err)
检测方式:错误包装仅添加了“error”、“failed”或无意义信息。
为何会损害Go代码
  • 错误消息应自上而下形成完整的问题描述
  • 缺少上下文会导致调试时需要查看源代码
  • 像“error: %w”或“failed: %w”这样模糊的包装是无效的
修复方案:包含正在执行的操作及相关标识符。
go
// 不良示例:无上下文信息
return nil, fmt.Errorf("error: %w", err)
return nil, fmt.Errorf("failed: %w", err)

// 良好示例:带有上下文的描述
return nil, fmt.Errorf("load config from %s: %w", path, err)
return nil, fmt.Errorf("parse config JSON from %s: %w", path, err)

AP-4: Channel Misuse for Simple Communication

AP-4:针对简单通信误用通道

Detection: Channels used where a return value or direct function call suffices.
Why it harms Go code:
  • Channels are for communication between goroutines
  • Without actual concurrency, channels add ceremony without benefit
  • Error handling becomes awkward (need separate error channel)
Fix: Use standard return values. Reserve channels for worker pools, fan-out/fan-in, and event streams.
go
// BAD: Channel for simple return
func GetUserName(id string) <-chan string {
    ch := make(chan string, 1)
    go func() { ch <- fetchUser(id).Name }()
    return ch
}

// GOOD: Direct return
func GetUserName(id string) (string, error) {
    user, err := fetchUser(id)
    if err != nil { return "", err }
    return user.Name, nil
}
检测方式:在可使用返回值或直接函数调用的场景下使用通道。
为何会损害Go代码
  • 通道用于goroutine之间的通信
  • 在无实际并发的场景下,通道只会增加形式化开销而无益处
  • 错误处理变得繁琐(需要单独的错误通道)
修复方案:使用标准返回值。仅在工作池、扇出/扇入、事件流场景下使用通道。
go
// 不良示例:使用通道返回简单结果
func GetUserName(id string) <-chan string {
    ch := make(chan string, 1)
    go func() { ch <- fetchUser(id).Name }()
    return ch
}

// 良好示例:直接返回结果
func GetUserName(id string) (string, error) {
    user, err := fetchUser(id)
    if err != nil { return "", err }
    return user.Name, nil
}

AP-5: Generic Abuse for Single-Use Cases

AP-5:针对单一使用场景滥用泛型

Detection: Type parameters used with only one concrete type instantiation.
Why it harms Go code:
  • Generics add complexity (type parameters, constraints)
  • Only valuable when you actually need multiple concrete types
  • Go prioritizes simplicity over premature generalization
Fix: Use concrete types. Add generics when you have 2+ type instantiations for data structures, algorithms, or shared behavior.
go
// BAD: Generic with one type
type Container[T any] struct{ value T }
// Only ever used as Container[string]

// GOOD: Concrete type
type StringContainer struct{ value string }
检测方式:类型参数仅用于一种具体类型实例化。
为何会损害Go代码
  • 泛型会增加复杂度(类型参数、约束)
  • 仅当确实需要多种具体类型时才有价值
  • Go语言优先考虑简洁性而非过早泛化
修复方案:使用具体类型。仅当数据结构、算法或共享行为需要2个及以上类型实例化时,再添加泛型。
go
// 不良示例:仅一种类型的泛型
type Container[T any] struct{ value T }
// 仅被用作Container[string]

// 良好示例:使用具体类型
type StringContainer struct{ value string }

AP-6: Context Soup

AP-6:Context混乱

Detection:
context.Context
parameter in functions that perform no I/O, cancellation, or deadline checks.
Why it harms Go code:
  • Context is for cancellation, deadlines, and request-scoped values
  • In pure computation, context adds noise to signatures
  • Suggests the function might do I/O when it does not
Fix: Reserve context for functions that do I/O, should be cancellable, or carry request-scoped values.
go
// BAD: Context in pure function
func CalculateTotal(ctx context.Context, prices []float64) float64 { ... }

// GOOD: No context needed
func CalculateTotal(prices []float64) float64 { ... }
检测方式
context.Context
参数被用于不执行I/O、取消操作或截止时间检查的函数中。
为何会损害Go代码
  • Context用于取消操作、截止时间及请求作用域的值传递
  • 在纯计算函数中,Context会增加签名的冗余
  • 暗示函数可能执行I/O操作,但实际并未执行
修复方案:仅在执行I/O、可取消或携带请求作用域值的函数中使用Context。
go
// 不良示例:纯函数中的Context
func CalculateTotal(ctx context.Context, prices []float64) float64 { ... }

// 良好示例:无需Context
func CalculateTotal(prices []float64) float64 { ... }

AP-7: Unnecessary Function Extraction

AP-7:不必要的函数提取

Detection: Tiny functions (1-5 lines) called from exactly one place, extracted to satisfy complexity metrics.
Why it harms Go code:
  • Adds indirection without adding clarity
  • Reader must jump between functions to understand a simple flow
  • Satisfying cyclomatic complexity tools is not a valid reason
When TO extract: Reused in 2+ places, complex enough to warrant its own name, needs independent testing, or represents a distinct logical operation.
When NOT to extract: To satisfy metrics tools, for trivial operations called once, or when the function name just describes what the code obviously does.
go
// BAD: Extracted for metrics
func (opts AuditorOpts) parsePort() (int, error) {
    if opts.Port == "" { return 5672, nil }
    return strconv.Atoi(opts.Port)
}
// Called exactly once from buildConnectionURL

// GOOD: Inline when called once
func (opts AuditorOpts) buildConnectionURL() (string, error) {
    port := 5672
    if opts.Port != "" {
        var err error
        port, err = strconv.Atoi(opts.Port)
        if err != nil { return "", fmt.Errorf("parse port %q: %w", opts.Port, err) }
    }
    return fmt.Sprintf("amqp://%s:%d", opts.Host, port), nil
}

检测方式:小型函数(1-5行)仅在一个位置被调用,提取该函数仅是为了满足复杂度指标。
为何会损害Go代码
  • 增加了间接性,却未提升清晰度
  • 读者需要在函数间跳转才能理解简单流程
  • 满足圈复杂度工具的要求并非合理理由
何时应提取函数:在2个及以上位置被复用、复杂度足够高需要独立命名、需要独立测试,或代表独立逻辑操作时。
何时不应提取函数:为满足指标工具要求、仅被调用一次的 trivial 操作,或函数名称仅描述代码显而易见的功能时。
go
// 不良示例:为满足指标提取函数
func (opts AuditorOpts) parsePort() (int, error) {
    if opts.Port == "" { return 5672, nil }
    return strconv.Atoi(opts.Port)
}
// 仅在buildConnectionURL中被调用一次

// 良好示例:仅被调用一次时内联
func (opts AuditorOpts) buildConnectionURL() (string, error) {
    port := 5672
    if opts.Port != "" {
        var err error
        port, err = strconv.Atoi(opts.Port)
        if err != nil { return "", fmt.Errorf("parse port %q: %w", opts.Port, err) }
    }
    return fmt.Sprintf("amqp://%s:%d", opts.Host, port), nil
}

Go-Specific Phantom Problem Indicators

Go语言特有的“伪问题”迹象

Watch for solutions looking for problems:
  • Adding interfaces when concrete types suffice
  • Implementing channels when simple function calls work
  • Creating goroutines for inherently sequential operations
  • Over-abstracting with generics for single-use cases
  • Adding middleware layers for simple HTTP handlers
  • Creating worker pools for low-throughput scenarios

注意那些为了解决不存在的问题而引入的方案:
  • 在具体类型足够用时添加接口
  • 在简单函数调用可行时实现通道
  • 为本质上是顺序的操作创建goroutine
  • 针对单一使用场景过度抽象泛型
  • 为简单HTTP处理程序添加中间件层
  • 为低吞吐量场景创建工作池

Error Handling

错误处理

Error: "False Positive -- Pattern Is Intentional"

错误:“误报——模式是有意为之”

Cause: Detected anti-pattern is actually justified by context (e.g., interface for testing boundary, generic for library API). Solution: Check for 2+ implementations or concrete future need. If justified, note as acceptable trade-off and move on.
原因:检测到的反模式实际上符合上下文需求(例如,为测试边界添加的接口、为库API设计的泛型)。 解决方案:检查是否存在2个及以上实现或明确的未来需求。如果合理,将其标记为可接受的权衡方案并继续处理其他问题。

Error: "Refactoring Breaks Tests"

错误:“重构破坏测试”

Cause: Tests depended on the anti-pattern structure (e.g., mocking an interface that gets removed). Solution: Update tests to use the concrete type. If removal would require major test rewrite, flag as tech debt rather than fixing immediately.
原因:测试依赖于反模式的结构(例如,模拟了一个将被移除的接口)。 解决方案:更新测试以使用具体类型。如果移除操作需要大量重写测试,将其标记为技术债务而非立即修复。

Error: "Team Disagrees on Pattern"

错误:“团队对模式存在分歧”

Cause: Different Go style preferences or legacy conventions in the codebase. Solution: Defer to existing codebase conventions. Flag in review comments rather than changing unilaterally. Cite Go proverbs or standard library examples as evidence.

原因:代码库中存在不同的Go语言风格偏好或遗留约定。 解决方案:遵循现有代码库的约定。在审查评论中标记问题,而非单方面修改。引用Go语言谚语或标准库示例作为依据。

Examples

示例

Example 1: Code Review Detection

示例1:代码审查检测

User says: "Review this Go service for anti-patterns" Actions:
  1. Scan using Quick Detection Guide table
  2. Flag each detected pattern with location and severity
  3. Provide before/after for highest-severity items
  4. Document findings in structured report format Result: Prioritized list of anti-patterns with remediation guidance
用户说:“审查这个Go服务中的反模式” 操作:
  1. 使用快速检测表进行扫描
  2. 标记每个检测到的模式,并注明位置和严重程度
  3. 为最高严重程度的问题提供前后对比方案
  4. 以结构化报告格式记录发现 结果:带有修复指导的优先反模式列表

Example 2: Specific Pattern Question

示例2:特定模式问题

User says: "Should I add an interface for this repository?" Actions:
  1. Check how many implementations exist or are planned
  2. If only one: recommend concrete type (AP-1)
  3. If testing boundary: suggest consumer-side interface
  4. Explain Go's "accept interfaces, return structs" philosophy Result: Evidence-based recommendation with Go idiom context

用户说:“我应该为这个仓库添加接口吗?” 操作:
  1. 检查现有或计划中的实现数量
  2. 如果只有一个实现:建议使用具体类型(AP-1)
  3. 如果是测试边界:建议在消费者端定义接口
  4. 解释Go语言“接受接口,返回结构体”的哲学 结果:基于证据的建议,并附带Go语言惯用法上下文

References

参考资料

This skill uses these shared patterns:
  • Anti-Rationalization - Prevents shortcut rationalizations
  • Verification Checklist - Pre-completion checks
本技能使用以下共享模式:
  • 反合理化 - 防止不合理的自我辩解
  • 验证清单 - 完成前检查

Domain-Specific Anti-Rationalization

Go语言特有的反合理化

RationalizationWhy It Is WrongRequired Action
"This interface might be needed later"YAGNI; future is unknownStart concrete, extract when needed
"Goroutines make it faster"Concurrency has overhead; profile firstProve bottleneck exists before adding goroutines
"Context should be everywhere"Context is for I/O and cancellation onlyRemove from pure functions
"Generics make it more flexible"Flexibility without use cases is complexityUse concrete types until 2+ instantiations
"Small functions are always better"Indirection has cognitive costInline single-use trivial functions
自我辩解错误原因要求操作
“这个接口以后可能会用到”违反YAGNI原则;未来不可知从具体类型开始,需要时再提取接口
“Goroutine会让代码更快”并发存在开销;需先进行性能分析在添加goroutine前证明存在性能瓶颈
“Context应在所有地方使用”Context仅用于I/O和取消操作从纯函数中移除Context
“泛型会让代码更灵活”无使用场景的灵活度只会增加复杂度在有2个及以上实例化场景前使用具体类型
“小型函数总是更好”间接性会增加认知成本内联仅被调用一次的trivial函数

Reference Files

参考文件

  • ${CLAUDE_SKILL_DIR}/references/code-examples.md
    : Extended before/after examples for all 7 anti-patterns
  • ${CLAUDE_SKILL_DIR}/references/code-examples.md
    :所有7种反模式的扩展前后对比示例