Refactor Ruby Edition
初识
重构的第一步是构建可靠的测试.
好的代码能展示自身意图.
移除不必要的临时变量, 减少来来回回传参带来的困扰; 将效率问题后置.
重构的节奏: 测试=>小改=>测试=>小改=>…
重构的基本原理
对软件内部结构的一种修改 , 在不改变软件外观行为的条件下, 使之更易于理解和修改.
WHY:
- 改进软件的设计
- 变得易于理解复杂系统
- 易于发现bug
- 利于总体的效率
BAD:
- 难读的程序很难改
- 有冗余逻辑的程序很难改
- 添加新功能时需要修改现有代码的程序很难改
- 有复杂逻辑的程序很难改
抽象和重构:
- 共享逻辑
- 分离意图和实现
- 隔离变化
- 条件判断=>多态
代码里的坏味道
重构的警告信号:
-
重复代码
方式上移
替换算法
提炼包围
模板方法
etc -
方法过长
小函数带来了抽象的好处: 解释/共享/选择 .
方法名可以取代注释. 当你想写注释的时候, 就抽象一个小方法出来.
对于临时变量过多的问题, 可以采用查询替换临时变量/链式调用替换临时变量.
对于参数过多的问题, 可以采用参数对象/保留完整对象.
条件/循环 提炼方法.
-
类太大
提炼类/提炼模块
-
参数列表太长
传递对象而不是参数, 使用方法而不是参数.
-
发散型变化
使用多态
-
霰弹型修改
-
特性依赖
谁的数据就该归谁管, 一起变化的东西放在一起.
etc..
构建测试
单元测试是给程序员用的, 主要用来提高生产力.
当收到QA的Bug时, 应该先写一个测试来重现此bug, 再debug.
重构花名册
组织方法
提炼方法
当方法过长, 或者复杂到需要添加注释来解释的时候, 就可能需要提炼方法了.
应该倾向于使用短小, 名称有意义的方法:
- 容易写, 复杂度低
- 方法名即注释
- 细小的颗粒度适于重用
方法名应该说明做了什么, 而不是怎么做; 多用名次, 少用动词.
内联化方法
简单的说就是把方法调用合并回主方法里.
当这个变量名已经很清晰, 不需要单独使用方法时. 好像很少遇到这种情况, 更多的是不需要提前优化. 在不清楚更进一步的需求的时候, 就不需要用方法把实例变量包装起来.
当优化一个巨大方法前, 可以先使用内联方法把散落的方法收集回来, 再重新组织和提炼.
注意内联的方法是否是多态的.
使用查询方法替换临时变量
将抽象出来的查询方法标记为私有方法.
形式上是将一段动作抽取出来, 形成一个查询, 将一系列计算动作转化为一个名词的查询.
方法要说明做了什么, 而不是怎么做的.
链式调用替换临时变量
链式调用要具体区分, 如果他们之间传递了不同类型的对象, 那么这绝对是一个怀味道, 应该让最邻近的对象来处理而不是跨越对象. 另一种情况是在连续调用之间传递相同类型的对象, 这样有利于消除临时变量并且带来流畅的操作.
要点是方法返回 self
.