(Refactoring) 重构-改善既有代码的设计

重构是在不改变软件可观察行为的前提下改善其内部结构。

用绝对安全的手法从焦油坑中整理出可测试的接口,给它添加测试,以此作为继续重构的立足点。

前言

所谓重构是这样的一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。

  • 第一章:重构样例
  • 第二章:重构的一般性原则、定义以及重构的原因
  • 第三章:如何嗅出代码中的“坏味道”,以及如何运用重构清除这些坏味道,测试在重构中扮演着非常重要的角色。
  • 第四章:如何运用一个简单且开源的java测试框架,在代码中构筑测试环境
  • 核心 第五章~第十二章:重构列表
  • 第十三章:Bill Opdyke在将重构技术应用于商业开发过程中遇到的一些问题
  • 第十四章:重构技术的未来——自动化工具
  • 第十五章:重构技术的顶尖大师 Kent Beck压轴

重构 第一个案例

  • 如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
  • 重构的第一步:为即将修改的代码建立一组可靠的测试环境。
  • 重构之前,首先检查自己是否有一套可靠的测试机制。这些测试必须有自我检验能力。
  • 重构技术就是以微小的步伐修改程序。如果你犯下错误,很容易便可发现它。
  • 利用重构工具,标识出需要重构的代码,在Refactor菜单中选择Extract Method,输入新函数名称,一切自动搞定。
  • 任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。
  • 重构的节奏:测试、小修改、测试、小修改、测试、小修改……

重构原则

  • 重构(名词) 对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
  • 重构(动词) 使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。
  • 两顶帽子 使用重构技术开发软件时,你把自己的时间分配给两种截然不同的行为:添加新功能,以及重构。添加新功能时,不应该修改既有代码,只管添加新功能与测试代码,并让测试正常运行;重构时,你就不能再添加功能,只管改进程序结构,此时你不应该添加任何测试,只在绝对必要时才修改测试。
  • 重构的目的:
    • 改进软件设计:消除重复
    • 使软件更容易理解
    • 帮助找到bug
    • 提高编程速度
  • 何时重构
    • 重构应该随时随地进行。你不应该为重构而重构,你之所以重构,是因为你想做别的什么事,而重构可以帮助你把这些事做好。
    • 事不过三,三则重构 三次法则:第一次做某件事时只管去做;第二次做类似的事会产生反感,但无论如何还是可以去做;第三次再做类似的事,你就应该重构。
    • 添加功能时重构:“如果用某种方式来设计,添加特性会简单得多。这种情况下我不会因为自己过去的错误而懊悔——我用重构来弥补它。”
    • 修补错误时重构:代码还不足以清晰到让你能一眼看出bug。
    • 复审代码时重构:结对编程

难以阅读的程序,难以修改;
逻辑重复的程序,难以修改;
添加新行为时需要修改已有代码的程序,难以修改;
带复杂条件逻辑的程序,难以修改。

  • 我们希望程序:(1)容易阅读;(2)所有逻辑都只在唯一地点指定;(3)新的改动不会危及现有行为;(4)尽可能简单表达条件逻辑。
  • 怎么对经理说:受进度驱动的经理要我尽可能快速完事,至于怎么完成,那就是我的事了。我认为最快的方式就是重构,所以我就重构。

计算机科学是这样一门科学:它相信所有问题都可以通过增加一个间接层来解决。

  • 间接层与重构:

    • 间接层的价值:
      • 允许逻辑共享
      • 分开解释意图和实现
      • 隔离变化
      • 封装条件逻辑:多态消息可以灵活而清晰地表达条件逻辑。将条件逻辑转化为消息形式,往往能降低代码的重复、增加清晰度并提高弹性。
  • 重构的难题:注意寻找重构可能引入的问题

    • 数据库:非常小心的将系统分层,将数据库结构和对象模型间的依赖降至最低

    • 修改接口:published interface 比 public interface 更进一步,接口一旦发布,你就再也无法仅仅修改调用者而能够安全地修改接口了。尽量的让旧接口调用新接口。千万不要复制函数实现。应该使用java提供的deprecation(不建议使用)。

      不要过早发布接口。请修改你的代码所有权政策,使重构更顺畅。

    • 难以通过重构手法完成的设计改动

    • 何时不该重构:如果项目已经接近最后期限,你不应该再分心于重构。

  • 重构与设计:

    • 重构肩负一项特殊使命:它与设计彼此互补。

      有了设计,我可以思考的更快,但是其中充满小漏洞。

    • 极限编程提倡:重构可以取代预先设计。

哪怕你完全了解系统,也请实际度量它的性能,不要臆测。臆测会让你学到一些东西,但十有八九你是错的。

  • 重构与性能:
    • 编写快速软件的方法:
      • 时间预算法:通常只用于性能要求极高的实时系统。分解你的设计,给每个组件预先分配一定资源——包括时间与执行轨迹。

      • 持续关注法:要求任何程序员在任何时间做任何事时,都要设法保持系统的高性能。很常见,但通常不会起太大作用。

        如果你对大多数程序进行分析,就会发现它把大半时间都耗费在一小半代码身上。如果你一视同仁地优化所有代码,90%的优化工作都是白费劲的,因为被你优化的代码大多很少被执行。

      • 利用上述的90%统计数据:在性能优化阶段,首先应该用一个度量工具来监控程序的运行,让它告诉你程序中哪些地方大量消耗时间和空间。