重构是不创建新功能的、改进代码的系统过程,可以让有坏味道的代码变得清洁,具有简单的设计。

1 清洁的代码

清洁代码的特征:

  • 对其他程序员很明白。这里不讨论复杂的算法。不好的变量名、浮肿的类和方法、魔数,这些都会让代码混乱,难以理解。
  • 没有重复。在重复代码中做修改时,必须在代码每个出现的地方做同样的修改,这增加了认知负担,减慢了开发进度。
  • 含有最少数量的类和其他活动部分。更少的代码更容易装入头脑;更容易维护;更少的bug。
  • 通过了所有测试。
  • 容易理解,维护成本低。

    2 技术债务

每个人都尽力写最优秀的代码,但清洁的代码从什么时候变得不清洁的?

从银行借债可以让购物更快,但是需要额外的代价:除了本金之外,还需要偿还利息。通过借债可以满足很多需求,但债务可能会超出收入,最终无法还清。

同样的事也会发生在代码身上。不为新特性写测试可以暂时加快速度,但会逐渐减慢进度,最终需要写测试来偿还技术债务。

2.1 技术债的根源

  • 业务压力 有时候让你推出还没有完全完成的特性,代码就需要补丁来隐藏没有完成的部分。
  • 对技术债的后果缺少理解
    经理不理解,随着债务的累积,开发进度最终会降低,从而不会给时间让团队进行重构,因为看不到重构的价值。
  • 与组件间的耦合性做斗争
    项目是单个大的程序,而不是由单个模块构成的产品时会出现这种情况。对一部分的修改会影响其他部分。团队开发会更难,因为很难隔离单个人员的工作。
  • 缺少测试
  • 缺少文档
  • 团队成员间缺少交流
  • 多个分支上的长期并行开发
  • 延迟的重构
  • 缺少兼容性监测
  • 开发人员不胜任工作

    3 何时重构

    3.1 三个原则

    r1.svg

  • 第一次做某事时,直接做就是了。

  • 第二次做相同的事,留个心眼。
  • 第三次做相同的事,开始重构。

    3.2 添加特性时

    r2.svg

  • 重构会帮助你理解代码。如果需要处理脏代码,首先尝试重构。清洁的代码容易理解得多。重构不仅改进自己的工作,也让后续使用的人受益。

  • 重构让添加新特性变得容易。在清洁代码中做修改容易得多。

    3.3 修复bug时

    r3.svg
    代码中的bug与现实生活中的bug一样:生活在代码中最黑暗、最脏的地方。清理代码就会发现错误,从而不需要特别的重构工作。

3.4 代码评审时

r4.svg
在发布之前,代码评审可能是最后的清理代码的机会。最好与作者一起进行评审。

4 如何重构

重构应该由一系列小的改动构成,这些改动让程序一直能够工作,同时让现有代码慢慢变好。

4.1 代码应该变得更清洁

经常出现的问题是,偏离了使用小改动的重构,引入了大的改动。这时候很容易丢失目标,特别是在有时间限制的情况下。

面对很烂的代码时,无论你改进什么,代码整体还是很烂。这时候应该考虑完全重写部分代码。但是开始之前,应该编写测试,准备一大块时间。

4.2 重构不应该创建新功能

不要把重构和新特性的开发混到一起。

4.3 重构后所有测试必须通过

两种可能会出现重构后测试不通过的情况:

  • 重构时引入了错误。
  • 测试太底层:比如说,测试了类的私有方法。这时候可以重构测试,或者重写一组高级别的测试。