技术债务不是坏事

Ward Cunningham 发明这个词时,并不是在批评。

债务是工具:

  • 快速上线验证想法
  • 抢占市场窗口
  • 获得用户反馈

问题在于:借了不还,利息越滚越高。

识别技术债务

代码级别的信号

明显的坏味道

// 神秘的魔法数字
if (status === 3 && type === 7) {
  // ...
}

// 函数过长,职责混乱
function handleUserAction() {
  // 500行代码,做了验证、数据库操作、发送邮件、更新缓存...
}

隐性的结构问题

  • 循环依赖
  • 重复代码散落在各处
  • 测试难以编写(代码耦合度高)

系统级别的信号

开发效率下降

  • 新功能开发时间越来越长
  • Bug 修复引入新 Bug
  • 新人上手时间从1周延长到1个月

运行时问题

  • 性能持续恶化
  • 故障频率增加
  • 难以扩展容量

技术债务分类

1. 有意为之的债务

  • MVP 阶段的时间压力
  • 已知后果,计划偿还

2. 无意的债务

  • 设计决策失误
  • 技术栈选型错误

3. 腐败的债务

  • 代码逐渐腐烂
  • 无人维护的老系统

不同类别,处理策略不同。

量化技术债务

债务清单

维护技术债务 backlog:

## 债务项 #1:用户模块重构
- **影响范围**:用户注册、登录、权限
- **债务类型**:结构债务
- **利息**:每新增功能多2天开发时间
- **估算成本**:5人天
- **建议偿还时间**:下个 Q1
- **风险**:不偿还将阻塞多租户功能

指标追踪

代码质量指标

  • 圈复杂度
  • 重复代码率
  • 测试覆盖率变化趋势

开发效率指标

  • 交付速度(每周完成的故事点)
  • Bug 逃逸率
  • 回归测试通过率

偿还策略

1. 分期付款:20% 原则

不要在 sprint 里全做重构

  • 产品经理:“一个迭代不做业务需求?不可能!”
  • 团队:“压力山大,质量难保证”

更好的方式: 每个 sprint 预留 20% 时间:

  • 重构接触到的代码
  • 补充关键测试
  • 偿还高利息债务

2. 边做边还:童子军规则

Leave the campground cleaner than you found it

每次修改代码时:

// 修改功能前,先重构这段代码
// 1. 提取函数
// 2. 重命名变量
// 3. 添加测试
// 然后再实现新功能

小步快跑,持续改进。

3. 专项重构:债务冲刺

适用场景

  • 债务积累太多,影响核心业务
  • 需要大规模架构调整

执行方式

  • 明确范围和时间(如:2个 sprint)
  • 获得管理层支持
  • 冻结业务需求(除紧急 bug)
  • 定义成功标准

风险

  • 容易被业务压力中断
  • 团队疲惫
  • 可能引入新问题

谨慎使用,做好 rollback 计划。

4. 绞杀者模式

渐进式替换: 老系统不停机,新系统逐步接管。

示例

第1阶段:新模块旁路运行,对比输出
第2阶段:逐步切量,5% → 20% → 50% → 100%
第3阶段:老系统下线

优势:风险可控,随时回滚。

与业务方的沟通

翻译技术语言

不要说: “我们需要重构用户模块,因为现在的代码耦合度太高,违反了单一职责原则。”

要说: “当前用户系统每新增功能需要2周,重构后可以缩短到3天。这样 Q2 我们能多上3个高优先级需求。”

用业务语言讲技术价值。

可视化债务影响

债务雷达图

         开发速度

           /|\
  稳定性 ◄──┼──► Bug 率
           \|/

        新人上手

每个维度1-10分,定期评估,让趋势可见。

预防债务累积

1. 代码审查(Code Review)

审查清单

  • 是否有测试覆盖?
  • 是否引入了新的重复代码?
  • 是否符合架构设计原则?
  • 是否考虑了边界情况?

工具支持

  • SonarQube 自动检测
  • GitHub PR template 强制检查

2. 测试自动化

测试金字塔

  • 70% 单元测试(快速、低成本)
  • 20% 集成测试
  • 10% E2E 测试(慢但覆盖用户场景)

有了测试,重构才有底气。

3. 架构守护

架构决策记录(ADR)

# ADR 1: 采用微服务架构

## 背景
单体应用难以扩展...

## 决策
拆分为用户、订单、支付三个服务

## 后果
- 正向:独立部署、技术异构
- 负向:分布式复杂度、运维成本

防止架构腐化。

总结

技术债务管理的关键:

识别:建立清单,定期 review 量化:用数据说话,而非感觉 计划:20% 持续偿还 + 专项处理大债务 预防:代码审查、测试、架构守护 沟通:用业务价值语言获得支持

完全零债务是不现实的,目标是:可控的债务,持续的偿还