Private
Public Access
1
0
Files
u-desk/docs/anti-over-engineering-report.md

7.1 KiB
Raw Blame History

避免过度封装 - 代码清理报告

执行日期

2026-01-27

背景

在代码优化过程中,需要警惕过度封装Over-engineering问题。 避免为了"优雅"而创建不必要的抽象层。


🔍 检查发现的问题

问题 1: WrapError/WrapErrorf 过度封装

原始实现

// 创建了两个新函数,但代码中没有任何使用
func WrapError(operation string, err error) error {
    if err == nil {
        return nil
    }
    return fmt.Errorf("%s失败: %v", operation, err)
}

问题分析

  1. 实际代码中零使用
  2. 只是把 fmt.Errorf 包装了一层
  3. 反而增加了学习成本和依赖
  4. 违背了 YAGNI 原则You Aren't Gonna Need It

正确做法

// 直接使用标准库
if err != nil {
    return fmt.Errorf("操作失败: %v", err)
}

结论 删除 - 过度封装,未被使用


问题 2: 文档注释过于冗长

原始实现

  • timeout.go: 70+ 行注释
  • utils.go: 40+ 行注释
  • errors.go: 60+ 行注释

问题

  1. 注释比代码还长
  2. 包含大量"显而易见"的说明
  3. 维护成本高
  4. 违背了"代码即文档"原则

优化后

// 数据库操作超时配置
const (
    TimeoutPing      = 2 * time.Second  // 连接测试超时
    TimeoutConnect   = 5 * time.Second  // 初始连接超时
    TimeoutFastQuery = 10 * time.Second // 元数据查询超时
    TimeoutQuery     = 30 * time.Second // 普通查询超时
    TimeoutLongOp    = 60 * time.Second // 长时间操作超时
)

结论 简化 - 保持适度注释


问题 3: timeout 配置 - 合理封装

使用情况

sql_exec_service.go: 5处使用
pool.go:            2处使用
redis.go:           2处使用
mongo.go:           3处使用

价值

  1. 消除14处硬编码
  2. 统一配置管理
  3. 便于修改调整
  4. 有实际使用价值

结论 保留 - 合理封装,有实际价值


问题 4: FormatBytes - 合理封装

使用情况

system.go: GetMemoryInfo() 中使用
system.go: GetDiskInfo() 中使用

价值

  1. 消除了重复代码
  2. 逻辑有一定复杂度(不是简单包装)
  3. 有多个调用点

结论 保留 - DRY 原则应用


执行的清理操作

1. 删除过度封装的文件

rm internal/common/errors.go  # WrapError/WrapErrorf 未使用

理由

  • 零使用
  • 只是对 fmt.Errorf 的简单包装
  • 增加不必要的抽象层

2. 简化文档注释

修改文件

  • internal/common/timeout.go - 从 70 行注释减少到 12 行
  • internal/common/utils.go - 从 40 行注释减少到 8 行

原则

  • 保留必要的注释(为什么这样做)
  • 删除显而易见的注释(做了什么)
  • 删除冗长的示例和说明

3. 保留有价值的封装

保留文件

  • internal/common/utils.go - FormatBytes消除重复
  • internal/common/timeout.go - 超时常量(统一配置)

📊 清理效果

项目 清理前 清理后 说明
common 包文件 3个 2个 删除 errors.go
timeout.go 注释 70行 12行 -83%
utils.go 注释 40行 8行 -80%
实际使用的函数 3个 2个 -1个

🎯 封装原则总结

应该封装的情况

  1. 消除重复代码 (DRY)

    // ✅ 好FormatBytes 被3个地方使用
    common.FormatBytes(size)
    
  2. 复杂逻辑

    // ✅ 好:逻辑复杂,值得封装
    func parseComplexConfig(data []byte) (*Config, error) {
        // 50行复杂逻辑
    }
    
  3. 统一配置

    // ✅ 好14处使用的配置常量
    const TimeoutQuery = 30 * time.Second
    

不应该封装的情况

  1. 简单包装标准库

    // ❌ 差:只是包装 fmt.Errorf
    func WrapError(op string, err error) error {
        return fmt.Errorf("%s失败: %v", op, err)
    }
    
  2. 未被使用的抽象

    // ❌ 差:定义了但没用
    type TimeoutConfig struct { ... }
    var DefaultTimeouts = TimeoutConfig{...}
    // 实际代码中没人用 TimeoutConfig
    
  3. 过度注释

    // ❌ 差:注释比代码长
    // FormatBytes 格式化字节大小...
    //
    // 参数:
    //   bytes - 字节数...
    //
    // 返回:
    //   格式化后的字符串...
    //
    // 示例:
    //   fmt.Println(FormatBytes(1024))...
    //
    // 注意:
    //   - 使用1024进制...
    //   - 支持PB级别...
    func FormatBytes(bytes uint64) string { ... }
    

📋 封装决策清单

在创建新函数/常量前,先问自己:

1. 是否消除重复?

  • 是否有2个以上使用点
  • 代码是否真的重复?
  • 如果否 → 不要封装

2. 是否增加价值?

  • 是否简化了调用?
  • 是否提高了可读性?
  • 是否便于维护?
  • 如果否 → 不要封装

3. 是否过度抽象?

  • 是否只是简单包装标准库?
  • 是否可以被2-3行代码替代
  • 如果是 → 不要封装

4. 是否会被使用?

  • 是否有明确的调用者?
  • 是否解决了实际问题?
  • 如果否 → 不要封装

验证状态

$ go build -v
go-desk/internal/common
go-desk/internal/system
go-desk/internal/dbclient
go-desk/internal/storage
go-desk/internal/service
go-desk/internal/api
go-desk
✅ 编译成功
  • 删除未使用的封装
  • 简化冗长的注释
  • 保留有价值的抽象
  • 代码更简洁

🎓 经验教训

YAGNI 原则You Aren't Gonna Need It

不要为未来可能需要的功能编写代码。 只写当前确实需要的功能。

应用

  • 不要"以防万一"创建工具函数
  • 等真正需要时再提取
  • 重复出现3次以上再考虑封装

KISS 原则Keep It Simple, Stupid

保持简单,愚蠢。

应用

  • 不要过度设计
  • 不要为了"优雅"而封装
  • 简单直接往往更好

注释原则

代码是最好的文档。注释说明"为什么",而不是"是什么"。

应用

  • 注释解释为什么这样做
  • 不要注释显而易见的代码
  • 不要写比代码还长的注释

🎯 最终状态

internal/common 包(简化后)

internal/common/
├── utils.go    # FormatBytes合理封装消除重复
└── timeout.go  # 超时常量(合理封装,统一配置)

特点

  • 每个函数/常量都有实际使用
  • 代码简洁,注释适度
  • 避免了过度封装
  • 符合 YAGNI 和 KISS 原则

📚 参考资源

软件工程原则

  1. YAGNI - You Aren't Gonna Need It
  2. KISS - Keep It Simple, Stupid
  3. DRY - Don't Repeat Yourself但不要过度

Go 语言哲学

  • "Clear is better than clever"
  • "Avoid over-engineering"
  • "Readability counts"

报告生成时间2026-01-27 清理阶段:避免过度封装 状态 已完成