重构——改善既有代码的设计(第2版)

《重构改善既有代码的设计第2版》

思维导图

65个例子带你看懂什么是好代码

Danger

所谓好,就是更少的坏味道

重构的时候不开发功能

开发功能的时候不重构

无论重构还是优化新能,都要先准备好测试代码,确保不改变代码行为

读书笔记

知乎

graph LR subgraph 测试 T(构筑测试体系) T->T1(撰写测试代码的最有用时机是在开始编程之前) T->T2(只要写好一点功能,就立即添加测试并执行) T->T3(多运用单元测试) T->T4("花合理时间抓出大多数bug"<br>要好过<br>"穷尽一生抓出所有bug") end subgraph 开发 D1(定义接口、参数、返回)—>D2 D2(参数校验)—>D3 D3(数据查询)—>D4 D4(数据更新)—>D5 D5(记录日志)—>D6 D6(触发事件)—>D7 D7(单元测试)—>D8 D8(集成测试) end subgraph codeReview C1(检查调用链)->C11(检查接口调用方式,get接口是否有参数过长的风险) C1->C12(检查参数列表、参数顺序、参数类型) C1->C13(检查判定逻辑 if empty isset ??) C1->C14(检查程序终止条件) C1->C15(检查临时变量名称是否一致,是否有多个用途) C2(检查业务逻辑) C3(检查重复逻辑) C4(检查注释的必要性) C5(检查换行的合理性) end subgraph 重构 R1(重复代码封装) R1(注释) end style Sky stroke:#00F,stroke-width:12; style Earth stroke:#030,stroke-width:12; style F31 stroke:#333,stroke-width:4px; style F23 stroke:#faa,stroke-width:4px; style D1 stroke:#F00,stroke-width:4px; style D2 stroke:#F00,stroke-width:4px; style D8 stroke:#F00,stroke-width:6px; style F1 stroke:#C90,stroke-width:6px; style F2 stroke:#C90,stroke-width:6px; style F3 stroke:#C00,stroke-width:6px; style F4 stroke:#C00,stroke-width:4px; style 0 fill:#2ff,fill-opacity:0.1,stroke:#F00,stroke-width:8px style A fill:#2ff,fill-opacity:0.1,stroke:#F00,stroke-width:8px style P3 stroke:#000,stroke-width:4px;

相关书籍

  • 《解析极限编程》
  • 《修改代码的艺术》
  • 《数据库重构》

    并行修改:

    数据库重构最好是分散到多次生产发布来完成,这样即便某次修改在生产数据库上造成了问题,也比较容易回滚。 确定没有bug之后,我再删除已经没人使用的旧字段。

格言

Danger

全局数据的问题在于,从代码库的任何一个角落都可以修改它,而且没有任何机制可以探测出到底哪段代码做出了修改。

  • 唯有能写出人类容易理解的代码的,才是优秀的程序员。
  • 本质上说,重构就是在代码写好之后改进它的设计。
  • 改进设计的一个重要方向就是消除重复代码
  • 事不过三,三则重构
  • 好代码的检验标准就是人们是否能轻而易举地修改它。
  • 好代码应该直截了当:有人需要修改代码时,他们应能轻易找到修改点,应该能快速做出更改,而不易引入其他错误。
  • 我比较喜欢让每个函数都只返回一个值,所以我会安排多个函数,用以返回多个值
  • 代码被阅读和被修改的次数远远多于它被编写的次数。
  • 设计模式为重构提供了目标。然而"确定目标"只是问题的一部分而已,改造程序以达到目标,是另一个难题。
  • 尽管编写测试需要花费时间,但却为我节省下可观的调试时间
  • 要将我的理解转化到代码里,得先将这块代码抽取成一个独立的函数,按它所干的事情给它命名
  • 设计耐久性假说":通过投入精力改善内部设计,我们增加了软件的耐久性,从而可以更长时间地保持开发的快速。
  • 一旦我需要思考"这段代码到底在做什么",我就会自问:能不能重构这段代码,令其一目了然?
  • 重构不是与编程割裂的行为。你不会专门安排时间重构,正如你不会专门安排时间写if语句。
  • 优秀的程序员知道,添加新功能最快的方法往往是先修改现有的代码,使新功能容易被加入
  • 自测试代码是极限编程的另一个重要组成部分,也是持续交付的关键环节。
  • 糟糕的程序结构可以慢慢理顺,把程序从一块顽石打磨成美玉。
  • 哪怕你完全了解系统,也请实际度量它的性能,不要臆测。臆测会让你学到一些东西,但十有八九你是错的。
  • 三大实践——自测试代码、持续集成、重构——彼此之间有着很强的协同效应。
  • 如果你一视同仁地优化所有代码,90%的优化工作都是白费劲的,因为被你优化的代码大多很少被执行。
  • 很多人经常不愿意给程序元素改名,觉得不值得费这个劲,但好的名字能节省未来用在猜谜上的大把时间。
  • 如果你想不出一个好名字,说明背后很可能潜藏着更深的设计问题
  • 据我们的经验,活得最长、最好的程序,其中的函数都比较短
  • 就算只有一行代码,如果它需要以注释来说明,那也值得将它提炼到独立函数中去。
  • 不必在意数据泥团只用上新对象的一部分字段,只要以新对象取代两个(或更多)字段,就值得这么做。
  • 大多数编程环境都大量使用基本类型,即整数、浮点数和字符串等
  • 一个体面的类型,至少能包含一致的显示逻辑,在用户界面上需要显示时可以使用
  • 既然不愿意支持超类的接口,就不要虚情假意地糊弄继承体系
  • 当我想好代码中应该有哪些关节时,才能使代码随着我的理解而演进。
  • 如果我发现做一件事可以有更清晰的方式,我就会用比较清晰的方式取代复杂的方式。
  • 模块化是优秀软件设计的核心所在,好的模块化能够让我在修改程序时只需理解程序的一小部分。
  • 要维护代码库的健康发展,需要遵守几条黄金守则,其中最重要的一条当属【消除重复】
  • 在我自己的编码过程中,我确实总是尽量遵循命令与查询分离的模式,因为它让我一眼就能看清代码有无副作用,而这件事情真是价值不菲。
  • 如果我从不犯错,小步前进不会节省工作量;但"从不犯错"这样的梦,我很久以前就已经不做了。
  • 「技术复审」是减少错误、提高开发速度的一条重要途径。
  • 代码前一定要先思考,先分析逻辑,整理业务,必要时画图、流程图等,总结之后,觉得逻辑没有问题,才是下一步的写代码。

重构的难题

数据库重构

  • 绝大多数的程序都和背后的数据库结构紧密的耦合在一起。
  • 数据迁移
  • 数据修复
  • 数据初始化

接口重构

  • 已经发布了的接口
  • 如何用新接口替换旧接口
  • 何时可以废弃旧接口

不适合重构的场景

  • 代码根本无法工作或者太糟糕,重构还不如重写来的简单。
  • 在项目的最后期限,应该避免重构
  • 时间不充足的时候不重构
  • 对代码理解不充分(所有调用处的逻辑)时不重构