重构前的准备:代码坏味道识别与技术债务评估
说实话,我见过太多团队一上来就撸袖子改代码。结果呢?改到一半发现牵一发动全身,最后不得不回滚。嗯,重构前的准备工作,其实比重构本身更重要。
这一章,我们就聊聊怎么在动手之前,先把「病」诊断清楚。
代码坏味道:你闻到了吗?
「坏味道」这个词,最早是 Martin Fowler 在《重构》里提出的。说白了,就是代码里那些「虽然能跑,但让人不舒服」的地方。我个人的习惯是,每次接手一个老项目,第一件事不是看业务逻辑,而是先扫一遍代码结构——闻味道。
常见的坏味道有三种,我一个个说。
1. 过长函数
一个函数超过 20 行,你就该警惕了。超过 50 行,基本可以断定它做了太多事。我在项目中遇到过最夸张的一个函数,足足 800 行——从参数校验、业务计算、日志打印到数据库写入,全塞在一起。
怎么判断?看缩进。如果一个函数里出现了三层以上的缩进嵌套,那就是警报。
// 坏味道示例:过长函数
public void processOrder(Order order) {
// 参数校验
if (order == null || order.getItems() == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("订单无效");
}
// 计算总价
double total = 0;
for (OrderItem item : order.getItems()) {
if (item.getPrice() < 0) {
throw new IllegalArgumentException("价格不能为负");
}
total += item.getPrice() * item.getQuantity();
}
// 应用折扣
if (order.getCoupon() != null) {
total = total * (1 - order.getCoupon().getDiscountRate());
}
// 保存订单
order.setTotal(total);
orderDao.save(order);
// 发送通知
notificationService.send(order);
}
你看,一个函数干了五件事。拆成五个小函数,每个只做一件事,可读性会好很多。
2. 过大的类
类太大,通常意味着它承担了太多职责。我见过一个叫 OrderService 的类,里面塞了订单创建、支付、退款、物流、评价……几乎覆盖了整个电商流程。你想想看,这样的类改起来多痛苦?
判断标准很简单:一个类超过 300 行,或者包含了超过 10 个方法,就该考虑拆分了。更直观的指标是——你能不能在一分钟内说清楚这个类「到底负责什么」?
| 指标 | 健康 | 警告 | 危险 |
|---|---|---|---|
| 类行数 | < 200 | 200 - 500 | > 500 |
| 方法数 | < 10 | 10 - 20 | > 20 |
| 字段数 | < 5 | 5 - 10 | > 10 |
| 职责数 | 1 | 2 - 3 | > 3 |
3. 重复代码
重复代码是技术债务的「万恶之源」。你想想看,同样的逻辑散落在三个地方,改需求的时候漏了一个,线上就出 bug。我曾经在一个项目里,发现同一个金额计算逻辑被复制粘贴了七次——每次还都改了一点点,导致维护成本翻了好几倍。
重复代码有三种常见形态:
- 完全重复: 一模一样的代码块,直接提取成方法
- 结构重复: 逻辑相似,只有参数不同,用模板方法或策略模式解决
- 语义重复: 实现方式不同但功能相同,比如手动计算和调用工具类算同一个东西
技术债务评估:到底欠了多少?
坏味道是「症状」,技术债务是「病因」。评估技术债务,不能光靠感觉。我习惯用四个维度来量化:
- 影响范围: 这段代码被多少模块依赖?改它会影响多少人?
- 修复成本: 重构需要多少工时?风险有多大?
- 维护成本: 不改的话,每次迭代要多花多少时间?
- 业务价值: 重构后能带来什么收益?性能提升?可扩展性?
每个维度打分 1-5 分,然后算加权总分。我一般用这个公式:
债务优先级 = 影响范围 × 0.3 + 维护成本 × 0.3 + 修复成本 × 0.2 + 业务价值 × 0.2
分数越高,越该优先处理。
重构优先级矩阵:先动哪里?
有了评估分数,就可以画矩阵了。横轴是「修复成本」,纵轴是「业务价值」。四个象限:
- 第一象限(高价值 + 低成本): 立刻动手。比如抽一个重复的常量、拆一个过长函数。
- 第二象限(高价值 + 高成本): 规划好再动手。比如重构核心模块的架构。
- 第三象限(低价值 + 低成本): 顺手做。比如改个变量名、删个无用 import。
- 第四象限(低价值 + 高成本): 先放着。比如重写一个很少改动的遗留模块。
下面这张图,是我自己一直在用的评估框架:
有了这个矩阵,你就能清楚地知道:哪些代码今天就要改,哪些可以放到下个迭代,哪些干脆别碰。
好了,诊断工具准备好了。下一件事就是——怎么动手重构?别急,我们先把「坏味道」的清单列清楚,再谈具体手法。