读《重构》两年后,我终于敢说"我懂了"
读《重构》两年后,我终于敢说"我懂了"
大三了,回头翻 Martin Fowler 的《重构:改善既有代码的设计》,才发现当年只是"看完了",离"看懂了"还差十万八千里。
一本书,两种读法
大二暑假第一次翻这本书,感觉挺简单的——不就是"提取方法""重命名变量"嘛,IDE 快捷键都能一键搞定。当时觉得 Fowler 写了本工具说明书。
后来在几个项目里写了上万行代码,再回来看这本书,感受完全不同。
重构不是「写完代码之后做的事」,而是写代码本身就是持续重构的过程。
最让我受益的三个技巧
1. Extract Method(提炼函数)—— 被低估的利器
书里花了大量篇幅讲这个,最初觉得太基础。直到维护一个 200 行的 Express 路由处理函数时,才体会到痛苦。
// 重构前:一个函数干了三件事
router.post('/api/orders', async (req, res) => {
// 20 行参数校验
// 60 行业务逻辑(库存检查 + 价格计算 + 状态流转)
// 30 行飞书通知
});
看起来"也能工作",但三个月后需求变了,改这段代码时我花了半小时才定位到要改的 5 行。团队其他人根本不敢碰这个文件。
提炼后:
router.post('/api/orders', async (req, res) => {
const errors = validateOrderParams(req.body);
if (errors.length) return res.status(400).json({ errors });
const order = await createOrder(req.body);
await notifyFeishu(order);
res.json({ id: order.id });
});
Fowler 说了一个金句:"每当感觉需要注释来解释一段代码在做什么时,就该把它提炼成函数。" 深以为然。好代码本身就是最好的文档。
2. Replace Temp with Query(以查询取代临时变量)
这个技巧初看反直觉——多写一行查询函数不是更麻烦吗?实际上它在两个场景下价值巨大:
- 减少作用域污染:一个 80 行的函数里飘着七八个
let临时变量,改代码时根本不敢挪位置 - 方便提取类:当临时变量太复杂需要独立成类时,查询函数可以直接搬
// 重构前
double basePrice = quantity * itemPrice;
double discountFactor;
if (basePrice > 1000) discountFactor = 0.95;
else discountFactor = 0.98;
return basePrice * discountFactor;
// 重构后
return basePrice() * discountFactor();
private double basePrice() { return quantity * itemPrice; }
private double discountFactor() {
return basePrice() > 1000 ? 0.95 : 0.98;
}
代码行数反而多了几行,但可读性提升明显。可读性比行数重要得多。
3. Rename Variable —— 最小的改动,最大的效果
这个技巧太简单,以至于很多人不当回事。但在团队协作中,命名糟糕的变量是沟通成本最高的东西。
在 ERP 项目中见过这样的代码:
List<Map<String, Object>> list1 = dao.getData();
for (Map<String, Object> m : list1) {
if ((int)m.get("s") == 1) {
m.put("p", calc((double)m.get("a")));
}
}
就问你能看懂吗?改成:
List<Map<String, Object>> pendingOrders = orderDao.getPendingOrders();
for (Map<String, Object> order : pendingOrders) {
if ((int) order.get("status") == ORDER_APPROVED) {
order.put("finalPrice", calcFinalPrice((double) order.get("baseAmount")));
}
}
没改逻辑,只改名,但维护成本降了一半不止。
我现在怎么用重构
-
写新功能时,先堆代码再重构。一开始想写出完美代码反而会卡住。快速跑通逻辑,然后花 15 分钟专门重构——这时候思路最清晰。
-
每次提交前,自问三个问题:
- 有没有超过 30 行的函数?(有 → 拆)
- 有没有超过 3 层的嵌套?(有 → 提)
-
变量名会不会让一周后的自己困惑?(会 → 改)
-
不"大重构"。Fowler 反复强调小步快跑:每次只改一个东西,跑测试,提交。尝试过大刀阔斧重构一个模块,结果引入三个 bug,花了两天修。血的教训。
-
测试是重构的安全网。没有测试的重构就是在赌博。哪怕只写集成测试,也能兜底。
这本书不够的地方
公允地说,《重构》第一版基于 Java 为例,有些例子现在看来略显啰嗦。JavaScript/TypeScript 生态里的函数式风格、React 的组件拆分思路,本质上也是重构思想,但书中没有覆盖。
另外,书里对"何时不该重构"着墨较少。实际工作中,有些代码虽然丑陋但稳定运行多年,重构的收益可能抵不过引入新 bug 的风险。"如果没坏,别急着修"这句话在某些场景下是对的。
一句话总结
重构不是一次性的"清理行动",而是写代码时的呼吸节奏——吸一口气把功能写通,呼一口气把结构理顺。
推荐所有写了半年以上代码的同学读一遍。如果已经读过了,写够一万行之后再读一遍——你会看到完全不同的东西。
大三,写于又一次"重构一时爽,一直重构一直爽"之后

浙公网安备 33010602011771号