《重构-改善既有代码的设计》系列读书笔记(一、从第一个案例说起)

读完了martin老师的《代码XX之道》系列后,颇有收获,代码质量也有比较明显的提高,渐渐对代码也有了自己的一些理解。但是学习的脚步不能停,《重构》这本书也是提高代码质量方面的经典书籍,当然不能错过了。

从第一个案例说起–影片租赁系统

发现问题-编写测试用例(测试用例的重构的根本)- 步步为营的修改

重构的本质:尽可能小的修改,这样任何可能出现的错误都会很容易发现。

如何拆分一个臃肿的函数

  • 处理函数内部的参数和变量,不变的变量以参数形式传入,可变的变量可以抽出为一个函数已返回值的形式赋值
  • 先分再治:先将函数拆分为尽可能小的函数,然后再对每个函数进行修改
  • 好的代码应该清晰的表达出自己的功能,变量名称就是代码清晰的关键
  • 任何一个傻瓜都是写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员
  • 绝大多数情况下,函数应该放在他所使用的数据的所属对象内。
  • 去掉多余的临时变量,临时变量会引发问题,导致大量没有必要的参数传递,并且很容易被跟丢,尤其是在很长的函数中。
  • 尽量使用查询函数替代可能的局部变量。

重构原则

  • 重构的名词解释:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本

  • 重构的动词解释:使用一些列重构手法,在不改变软件可观察行为的前提下,调整其结构

两顶帽子理论

  • 添加新功能时,你不应该修改既有代码,只管添加新代码。
  • 重构时你不能再添加功能,只管改进程序结构。
  • 编码过程中我们会经常变换帽子。

重构的目的

  • 重构改进软件设计,如果没有重构,程序的设计会逐渐腐败变质。消除重复是重构的重要手段之一。
  • 重构使软件更容易理解,始终提醒自己一点,代码是写给人看的。
  • 重构帮助找到BUG
  • 重构提高编程速度,因为良好的设计是快速开发的根本。

何时重构

不应该专门抽时间来重构,而应该随时重构,只要你发现代码有重构的必要时,就着手重构。重构的原因是你需要做别的事情,而重构能帮助你把事情做得更好。

三次法则:第一次做这件事情时尽管去做,第二次做相似的事情时不情愿的去做,第三次再遇到这种事情时,坚决的重构。

  • 添加功能时重构
  • 修补错误时重构
  • 复审代码时重构

好的代码应该具备以下特性:

  • 容易阅读
  • 所有逻辑都只在唯一地点指定
  • 新的改动不会危及现有行为
  • 尽可能简单表达条件逻辑

当代码不能正常工作时,应该选择重写而不是重构。重构之前的代码,至少大部分情况下是能正常运行的。

项目接近最后期限时,应该避免重构。未完成的重构工作可以比作技术债务,而维护和扩展代码所花费的额外成本就是利息。一定程度的利息是可以接受的,但是如果利息太高,就会被压垮。把债务管理好很重要,应该随时通过重构来偿还一部分债务。

重构的难点

  • 数据库的重构,需要加上中间层和做好数据迁移
  • 接口的重构,添加新接口,让老接口去调用新接口,不要复制函数,并将旧接口标记为deprecated

坏代码的味道

  • 坏代码没有一个统一的评判标准,你必须培养出自己的判断力,学会判断一个类内有多少实例变量算是太大,一个函数内有多少行代码算太长。

坏代码条款

  • 重复代码
  • 过长函数
  • 过大的类
  • 过长的参数
  • 发散式变化(拆分)
  • 霰(xian)弹式修改(合并)
  • 依恋情结(类中方法应该只对该类感兴趣,而不应该依恋其他类)
  • 数据泥团(一些需要同时出现的数据,合并为一个新的对象)
  • 基本类型偏执(比如结合数值和币种的money类等)
  • switch惊悚现身(使用多态替换)
  • 平行继承体系
  • 冗赘类(删除无用类)
  • 夸夸其谈未来性(不要企图使用钩子或者特殊判断处理并未发生的事情)
  • 令人迷惑的暂时字段
  • 过度耦合的消息链
  • 过度滥用的中间人
  • 狎昵关系
  • 异曲同工的类
  • 不完美的库类
  • 纯粹的数据类(需要良好的封装,只读取少修改)
  • 被拒绝的遗赠(使用代理替带方法集成)
  • 过多的注释(不要过度依赖注释,如果一段代码需要注释,则应该将它们提炼为一个新的方法)