
管理技术债务:实现可持续发展的策略
技术债务是选择现在简单的解决方案而非正确解决方案的成本。
技术债务的类型
有意的:“我们知道这很乱,以后会修复”
- 为赶截止日期而故意走捷径
- 应记录并安排修复计划
意外的:“我们不知道这会引发问题”
- 过时的依赖
- 当时合理但现在不合理的架构
代码腐烂:原本良好的代码随时间退化
- 代码曾经可用,但周围的世界变了

识别债务
// 表明债务的代码坏味道:
// 1. 长函数(超过30行就值得怀疑)
function processEverything(data: any) {
// 200行混合关注点
}
// 2. 高圈复杂度
function calculatePrice(order: any) {
if (order.type === 'a') {
if (order.customer === 'premium') {
if (order.items.length > 10) {
// 深度嵌套...
}
}
}
}
// 3. 重复代码(复制粘贴债务)
// 相同的验证逻辑出现在5个不同文件中
// 4. 过时的注释
// TODO: 修复此问题(来自2019年)
// HACK: 绕过库X v1.2的bug(现在已是v5.0)
衡量债务
# 使用plato进行复杂度分析(JavaScript)
npx plato -r -d reports src/
# 代码重复检测
npx jscpd src/ --min-lines 10 --min-tokens 50
# 死代码检测
npx ts-prune
# 依赖版本检查
npx npm-check -u
# 代码覆盖率(低覆盖率=隐藏的债务)
npm run test -- --coverage
债务积压

## 技术债务积压
### 高优先级(阻碍开发速度)
- [ ] DEBT-001: 将基于回调的数据库层替换为async/await
- 工作量: 大, 影响: 高
- 影响: 23个文件,导致70%的异步bug
### 中优先级(造成困扰)
- [ ] DEBT-002: 拆分UserManager上帝类
- 工作量: 中, 影响: 中
- 测试覆盖率: 12%

### 低优先级(小烦恼)
- [ ] DEBT-003: 升级已弃用的webpack插件
- 工作量: 小, 影响: 低
偿还债务的策略
1. 童子军规则:让代码比你发现时更好
- 修改文件时,顺手清理小问题
- 小修复无需单独的“清理PR”
2. 绞杀者模式用于大型重写:
- 不要一次性重写所有内容
- 在新代码旁构建,逐步路由流量
3. 专门的债务冲刺(20%容量):
- 预留冲刺容量用于债务减少
- 让债务在规划中可见
4. 债务墙:
- 物理或数字看板,列出所有已知债务
- 团队投票决定处理哪些
提供商业理由
“这个功能需要3周,因为我们必须在旧支付代码上绕行”
对比
“如果我们花1周清理支付代码,这个功能只需1周,
并且接下来的10个支付功能每个节省1周 = 10倍回报”
将债务表述为:
- 功能开发速度成本:“每个功能多花X周”
- 可靠性成本:“上个月3次事故追溯到模块Y”
- 入职成本:“新开发人员需要2周理解模块Z”
可持续的团队将技术债务视为一等关注点,而不是等到危机才处理。