读《重构——改善既有代码的设计》

Tips

重构后即运行测试。小步修改,每次修改后就运行测试,每次成功的重构后就提交代码,可以轻松地回滚到上一个可工作的状态。
好代码的检验标准就是人们能否能轻易的修改它。
软件的性能通常至于代码的一小部分相关,改变其他的部分往往对总体性能贡献甚微。对于重构过程中产生的性能问题,大多数情况下可以忽略它,先完成重构,再做性能优化。
编写软件是一个累加的过程,添加新功能最快的方法往往是先修改现有的代码,使新功能容易被加入。
当你感觉需要撰写注释时,请先尝试重构,试着让所有的注释都变得多余。
编写优良的测试程序,可以极大地提高编程速度,即使不进行重构也是如此。
类应该包含它们自己的测试代码。

什么是重构

重构不应指代任何形式的代码清理,而应是运用大量微小且保持软件行为的步骤,一步步达成大规模的修改。期间代码应很少进入不可工作的状态。
重构与性能优化相比,两者都需要修改代码,都不会改变程序的整体功能。差别在于目的,重构是为了让代码“更容易理解,更容易修改”,这可能是程序更快,或者更慢。而性能优化则是为了使程序运行更快。

为什么重构

改进软件的设计
使软件容易理解
帮助找到bug
提高编程速度

何时重构

事不过三,三则重构

见机行事的重构——并不安排一段专门的时间进行重构,而是添加新功能或者修复bug时顺便重构。
预备性重构:最佳时机在添加新功能前。经常发现:如果对现有代码结构做一点微调,工作会变得容易的多。
帮助理解的重构:搞不懂这段代码在干什么,为了能清晰地理解。
捡垃圾式重构:我已经懂了这段代码在干什么,但他实在写的太烂了。眼下有空顺手重构了,眼下没空小本本记下来,后面再来清理。

有计划的重构——某个区域的问题逐渐积累长大,需要专门找一段时间处理肮脏的代码。但大部分重构应该是见机行事的。

何时不应该重构

丑陋的代码被隐藏在一个API下,而我不需要理解其运行原理。
如果重写比重构还容易,就别重构了!

重构的挑战

重构是耗费时间的,它可能延缓新功能的开发。有时候是这样的,功能小而重构多。这需要做出取舍和权衡。但长远来看,重构应该还是能够创造更大的价值的。
重构不仅会影响参与重构的人,而且会影响整个团队的其他协同开发着,甚至是不同团队的开发者,关联方的影响会妨碍重构。
工作流的科学合理性很重要,代码的分支合并操作会带来很多问题。CI和重构能够良好配合,是有最佳实践的。
不改变程序可观察的行为,是重构的一个重要特征。要做到这一点关键在于如何快速的发现错误并修正。

重构与架构、自测试代码、持续集成

增量式设计(YAGNI, you aren’t going to need it),架构应该是能在不断重构中优化的
自测试代码是重构的基石
自测试代码、持续集成、重构——彼此之间有着很强的协同效应。

代码的坏味道

  1. 神秘命名
  2. 重复代码
  3. 过长函数
  4. 过长参数列表
  5. 全局数据
  6. 可变数据(要约束对数据的更新)
  7. 发散式变化(每次应只关心一个上下文,不同逻辑应分属不同模块)
  8. 霰弹式修改(遇到某种变化需要在许多不同的类内做出许多小修改,难找且容易遗漏)
  9. 依恋情节(一个函数与另一个模块的某个函数数据交流格外频繁,甚至超过自己所处模块的内部)
  10. 数据泥潭(???)
  11. 基本类型偏执(为了显示电话号码,用字符串代表电话号码数据,“类字符串类型变量”,是如此常见的臭味)
  12. 重复的switch
  13. 循环语句(以管道?取代循环)
  14. 冗赘的元素(简化,瘦身)
  15. 夸夸其谈通用性(hook、钩子)
  16. 临时字段
  17. 过长消息链
  18. 中间人
  19. 内幕交易(把数据交换放在明面上)
  20. 过大的类
  21. 异曲同工的类
  22. 纯数据类
  23. 被拒绝的遗赠(子类复用了超类的行为,却不愿意支持超类的接口)
  24. 注释(长长的注释之所以存在往往是因为代码很糟糕,重构后会发现,注释变的多余了)

如何重构

最常用

  1. 提炼函数(Extract Function)
  2. 内联函数(Inline Function)
  3. 提炼变量(Extract Variable)
  4. 内联变量(Inline Variable)
  5. 改变函数声明(Change Function Declaration)
  6. 封装变量(Encapsulate Variable)
  7. 变量改名(Rename Variable)
  8. 引入参数对象(Introduce Parameter Object)
  9. 函数组合成类(Combine Functions into Class)
  10. 函数组合成变换(Combine Functions into Transform)
  11. 拆分阶段(Split Phase)

封装

  1. 封装记录(Encapsulate Record)
  2. 封装集合(Encapsulate Collection)
  3. 以对象取代基本类型(Replace Primitive with Object)
  4. 以查询取代临时变量(Replace Temp with Query)
  5. 提炼类(Extract Class)
  6. 内联类(Inline Class)
  7. 隐藏委托关系(Hide Delegate)
  8. 移除中间人(Remove Middle Man)
  9. 替换算法(Substitute Algorithm)

搬移特性

  1. 搬移函数(Move Function)
  2. 搬移字段(Move Field)
  3. 搬移语句到函数(Move Statements into Function)
  4. 搬移语句到调用者(Move Statements to Callers)
  5. 以函数调用取代内联代码(Replace Inline Code with Function Call)
  6. 移动语句(Slide Statements)
  7. 拆分循环(Split Loop)
  8. 以管道取代循环(Replace Loop with Pipeline)

重新组织数据

  1. 拆分变量(Split Variable)
  2. 字段改名(Rename Field)
  3. 以查询取代派生变量(Replace Derived Variable with Query)
  4. 将引用对象改为值对象(Change Reference to Value)
  5. 将值对象改为引用对象(Change Value to Reference)

简化条件逻辑

  1. 分解条件表达式(Decompose Conditional)
  2. 合并条件表达式(Consolidate Conditional Expression)
  3. 以卫语句取代嵌套条件表达式(Replace Nested Conditional with Guard Clauses)
  4. 以多态取代条件表达式(Replace Conditional with Polymorphism)
  5. 引入特例(Introduce Special Case)
  6. 引入断言(Introduce Assertion)

重构API

  1. 将查询函数和修改函数分离(Separate Query from Modifier)
  2. 函数参数化(Parameterize Function)
  3. 移除标记参数(Remove Flag Argument)
  4. 保持对象完整(Preserve Whole Object)
  5. 以查询取代参数(Replace Parameter with Query)
  6. 以参数取代查询(Replace Query with Parameter)
  7. 移除设值函数(Remove Setting Method)
  8. 以工厂函数取代构造函数(Replace Constructor with Factory Function)
  9. 以命令取代函数(Replace Function with Command)
  10. 以函数取代命令(Replace Command with Function)

处理继承关系

  1. 函数上移(Pull Up Method)
  2. 字段上移(Pull Up Field)
  3. 构造函数本体上移(Pull Up Constructor Body)
  4. 函数下移(Push Down Method)
  5. 字段下移(Push Down Field)
  6. 以子类取代类型码(Replace Type Code with Subclasses)
  7. 移除子类(Remove Subclass)
  8. 提炼超类(Extract Superclass)
  9. 折叠继承体系(Collapse Hierarchy)
  10. 以委托取代子类(Replace Subclass with Delegate)
  11. 以委托取代超类(Replace Superclass with Delegate)
文章作者: ゴウサク
文章链接: http://dapaner.top/2021/07/02/读《重构——改善既有代码的设计》/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Corner&Coder
微信赞赏码
支付宝赞赏码