重构读书笔记
一、什么是重构?(读第一章)
重构:refactoring,是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。
本质上:就是在代码写好之后改进它的设计。
-
重构过程的精髓:小步修改,每次修改后运行测试。
如果每次改动了太多内容,犯错时就可能陷入麻烦的调试,浪费大量的时间。
通过小步修改、以及它带来的频繁反馈,是防止混乱的关键。
-
测试通过后,提交每次重构的代码到版本控制系统。
方便回退到上一个代码可工作的状态。
-
编码风格:
- 永远将函数的返回值命名为
result,这样一眼就知道它的作用。 - 为参数取名时都默认带上其类型名。
- 变量命名是代码清晰的关键。只要改名能提升代码的可读性,就应该改名。
- 把复杂的代码块分解为更小的单元。
- 永远将函数的返回值命名为
-
编程时需要遵循营地法则:
保证你离开时的代码库一定比来时更健康。
-
按类型重组计算过程
以多态取代条件表达式。
- 这里将戏剧的价格计算函数和观众量积分计算函数提取到单独的类里,为使用多态做准备。
- 以工厂函数取代构造函数。
-
好代码的检验标准就是人们能否轻而易举的修改它。
二、为什么重构?(读前两章)
-
什么是重构?
-
名词:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高可理解性,降低其修改成本。
重构的手法,如:提炼函数;以多态取代条件表达式。
-
动词:使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。
-
-
重构的关键:
- 运用大量微小且保持软件行为的步骤,一步步达成大规模的修改。
-
为什么重构?
- 改进软件的设计。消除重复代码。
- 使软件更容易理解。降低其他开发者的修改成本。
- 帮助找到bug。还是强调代码更容易理解。
- 提高编程速度。对代码的理解更容易,减少bug的引入。
-
何时重构?
事不过三,三则重构。
- 预备性重构:让添加新功能更容易。
- 帮助理解的重构:使代码更易懂。变量命名、拆分函数...
- 捡垃圾式重构:对遇到的写的有问题的代码,待完成主任务之后,可以完成主任务之后再重构问题代码。
- 添加功能、修改bug时,顺便进行重构。
- 在编程的过程中持续不断地进行代码复审,在复审代码时进行重构。
-
重构的挑战
-
会认为延缓新功能开发。我们重构的目的是由经济利益驱动的,是为了让代码添加功能更快、修复bug更快。
-
代码所有权的边界会妨碍重构,推荐团队代码所有制。
在“强代码所有制”和“混乱修改”两个极端之间,折中。
-
特性分支生命周期太长时,重构需要和CI结合,降低分支合并的难度。
-
重构要想快速发现错误,得先有可以自测试的代码。
-
三、在什么地方重构?(读第三章)
本书讲解如何以一种可控且高效的方式进行重构。
重构从哪些方面入手?
代码的坏味道分布在以下方面
3.1 神秘命名
命名:函数、模块、变量、类命名,能清晰的表明自己的功能、用法。
常用重构手法:
- 改变函数声明:
- 函数命名:表明函数的用途。
- 命名依据:先用一句话描述函数的用途,再把这句注释改成函数的名字。
- 如何重构:查看变更的范围,能否一步到位的修改函数声明及其所有调用者。
- 可以一步到位:简单做法,直接修改函数声明。
- 不可以一步到位:迁移式做法
- 首先,对函数体内部进行重构。
- 然后将函数体提炼成一个新函数。
- 测试。
- 对旧函数使用内敛联函数(旧函数内部实际调用新函数)。
- 测试。
- 如果不确定旧函数是否有外部api在使用,可以把旧函数标记为@Deprecated。
- 变量改名:
- 如果变量被广泛使用,考虑运用封装变量将其封装起来。
- 字段改名:
3.2 重复代码
重复代码增加理解难度、修改难度(容易忽略)。
重构手法:
- 提炼函数:使用场景【两个函数拥有相同的表达式】,提炼出重复代码,两个地点分别调用新函数。
- 何时应该把代码放进独立的函数:最合理的观点是“将意图与实现分开”。
- 小函数 + 好名字。
- 移动语句:使用场景【两个函数只是相似而不是完全相同】,移动语句重组代码顺序,把相似的代码部分放在一起方便提炼。
- 动机:让存在关联的东西一起出现,可以使代码更容易理解。
- 最常见的情况:变量的声明、使用放在一起。
- 函数上移:使用场景【重复代码位于同一个超类的不同子类中】,使用函数上移避免在两个子类中互相调用。
3.3 过长函数
函数越长,越难理解。小函数 + 好名字,易于理解。
- 方法:积极的分解函数。
- 提炼函数(106)
- 以查询取代临时变量(178):消除临时元素
- 引入参数对象(140)、保持对象完整(319)、以命令取代函数(337):简化过长的参数列表
- 提炼函数(106)
- 在何处下手?
- 寻找注释:注释通常能指出代码用途和实现手法之间的语义距离。
- 条件表达式:
- 分解条件表达式(260)
- 多态取代条件表达式(272)
- 循环:拆分循环(227)