重构是不创建新功能的、改进代码的系统过程,可以让有坏味道的代码变得清洁,具有简单的设计。
1 清洁的代码
清洁代码的特征:
- 对其他程序员很明白。这里不讨论复杂的算法。不好的变量名、浮肿的类和方法、魔数,这些都会让代码混乱,难以理解。
- 没有重复。在重复代码中做修改时,必须在代码每个出现的地方做同样的修改,这增加了认知负担,减慢了开发进度。
- 含有最少数量的类和其他活动部分。更少的代码更容易装入头脑;更容易维护;更少的bug。
- 通过了所有测试。
- 容易理解,维护成本低。
2 技术债务
每个人都尽力写最优秀的代码,但清洁的代码从什么时候变得不清洁的?
从银行借债可以让购物更快,但是需要额外的代价:除了本金之外,还需要偿还利息。通过借债可以满足很多需求,但债务可能会超出收入,最终无法还清。
同样的事也会发生在代码身上。不为新特性写测试可以暂时加快速度,但会逐渐减慢进度,最终需要写测试来偿还技术债务。
2.1 技术债的根源
- 业务压力 有时候让你推出还没有完全完成的特性,代码就需要补丁来隐藏没有完成的部分。
- 对技术债的后果缺少理解
经理不理解,随着债务的累积,开发进度最终会降低,从而不会给时间让团队进行重构,因为看不到重构的价值。 - 与组件间的耦合性做斗争
项目是单个大的程序,而不是由单个模块构成的产品时会出现这种情况。对一部分的修改会影响其他部分。团队开发会更难,因为很难隔离单个人员的工作。 - 缺少测试
- 缺少文档
- 团队成员间缺少交流
- 多个分支上的长期并行开发
- 延迟的重构
- 缺少兼容性监测
-
3 何时重构
3.1 三个原则
第一次做某事时,直接做就是了。
- 第二次做相同的事,留个心眼。
-
3.2 添加特性时
重构会帮助你理解代码。如果需要处理脏代码,首先尝试重构。清洁的代码容易理解得多。重构不仅改进自己的工作,也让后续使用的人受益。
- 重构让添加新特性变得容易。在清洁代码中做修改容易得多。
3.3 修复bug时
代码中的bug与现实生活中的bug一样:生活在代码中最黑暗、最脏的地方。清理代码就会发现错误,从而不需要特别的重构工作。
3.4 代码评审时
在发布之前,代码评审可能是最后的清理代码的机会。最好与作者一起进行评审。
4 如何重构
重构应该由一系列小的改动构成,这些改动让程序一直能够工作,同时让现有代码慢慢变好。
4.1 代码应该变得更清洁
经常出现的问题是,偏离了使用小改动的重构,引入了大的改动。这时候很容易丢失目标,特别是在有时间限制的情况下。
面对很烂的代码时,无论你改进什么,代码整体还是很烂。这时候应该考虑完全重写部分代码。但是开始之前,应该编写测试,准备一大块时间。
4.2 重构不应该创建新功能
4.3 重构后所有测试必须通过
两种可能会出现重构后测试不通过的情况:
- 重构时引入了错误。
- 测试太底层:比如说,测试了类的私有方法。这时候可以重构测试,或者重写一组高级别的测试。