读书总结
总计花了大概两周,每天上下班各有半小时左右的时间,读完了《重构——改善既有代码的设计(第二版)》,获益良多,虽然从开始学习编程起就一直很注意代码的可读性和代码结构的维护,但是毕竟经验尚浅,无论是广度还是深度都远远不够。
读书过程中不仅有很多平时只是浑浑沌沌感受到的把代码写好的原则被作者轻而易举地点透了,同样还有很多以前自以为是认为能把代码写好实际上却增加了代码复杂度的错误被发现了。
书籍结构
书籍主要分为五大部分:
- 开篇是一个重构的具体案例,展示了对一段代码的完整重构过程;
- 接下来是对重构几个方面的解释,包括对重构的定义、重构的目的和重构的时机等;
- 第三个大部分是代码的坏味道,直白地说,就是代码里需要进行重构的具体表现,我认为这是整部书中最重要的部分;
- 测试的重要性——重构的基础是测试,要想保证重构不使程序被破坏,测试环境是必须的;
- 最后一个大部分是具体的重构手法,这里展示了大量的重构手法,每一种手法都有比较具体的使用场景,很多手法也会使用到其他的重构手法,这也是整部书中占篇幅最大的部分。
我整理了一个思维导图,帮助理解整部书的结构和为以后复习作准备:
一部形成了完整方法论的书籍
这是一本形成了完整的重构方法论的书籍,从什么是重构(What)到为什么要进行重构(Why),再到何时进行重构(When),以及**如何进行重构(How)**都一一进行了详细的展示,内容相当充实和丰富,并且结构非常合理,无论是提纲契领的思想还是具体的操作手法都流畅地进行了展现。
一部值得反复学习和实践的书籍
从厚度上来说,这本书加上序言和书末的索引也就不到四百五十页,但内容却十分充实,并不像很多书籍一样注水严重,接近六十种具体的重构手法、二十几种代码的“坏味道”、重构原则中的What、Why、When等,都不是只把书籍阅读一遍就可以完全吸收的,值得细细学习体会并在具体工作中进行实践,以提高代码质量。
一部阅读体验非常与众不同的书籍
“代码的坏味道”这个篇章紧接在重构的原则这个篇章之后。
虽然作者已经尽力把第一个案例选得简短,但是连续四十页的重构还是读起来有些累,而“重构的原则”这个篇章又显得太虚了些,终于到了“代码的坏味道”这个篇章,这部书就开始展现出与其他书籍阅读体验非常不同的特点,让我精神一振。
这个篇章里提出了二十四种“坏味道”,每一种“坏味道”里除了对“坏味道”本身的描述之外,还对具体的解决思路和解决方法进行了提炼。前面有提到,书中提供了近六十种具体的重构手法,在每一种坏味道的解决方法中,都有具体的重构手法的引用,而具体的重构手法也会经常对其他的重构手法进行引用——这仿佛是作者制作了一个解决问题的栈,形成了下面这样的阅读流程:
这种“类栈”的阅读让我想起了以前玩的分支选择互动小说,但放在技术书籍里可以说是相当少见了。
代码的坏味道
我在前面说,这是我认为整部书中最重要的一个部分,重构的原则部分显得太过虚了些,而后面具体的重构操作又跟具体的语言结合地紧密了些(虽然作者尽力在减少这种语言相关的差异),而这一部分不仅描述了坏代码的具体场景,还给出了解决方案,具有极强的实操性。
极其常见的几种坏味道
这二十四种坏味道中,有几种是极其常见的:
- 神秘命名——取名是程序员的天敌,但取个好名字又极其重要,这也是稍有自觉的程序员都会注意的地方,可惜的是,取名实在是太难了(作者给这么多重构手法和坏味道都一一取了名字真是辛苦了);
- 重复代码——大家都戏称编程只需要三个键:Ctrl、V、C,由此也可知重复代码的常见性,遗憾的是这却是代码中最刺鼻的坏味道之一,恐怕也是代码中最屎山的最大来源之一;
- 过长函数——又是一个极其常见的坏味道,“屎山”的最重要组成,没有之一,我曾经在项目中见过长达两千行的超长函数,结尾处大括号
}
套了二十几层,看得我头皮发麻;作者在这一种坏味道中提出了一个有意思的观点:就算只有一行代码,如果它需要以注释来说明,那也值得将它提炼到独立函数中去
; - 全局数据——同样是一个被滥用的代码组织方式,在带GC的语言中又显得尤其恶心,导致各种“伪内存泄漏”的元凶;
- 基本类型偏执——关于这一种坏味道,其实我在C#中见得很少,但在C++项目中见得尤其多,大概是没能成功从“带class的C语言”转换到“面向对象的C++”造成的吧;
- 过大的类——这往往跟过长函数同时出现,都是屎山上最璀璨的明珠;
带给我一些新思考的几种坏味道
有一些坏味道是我以前偶尔瞥见但没上心的,这次在书中看到,却给了我一些新的思考:
- 可变数据——如果一个变量多次被赋值,并且在不同的时候保存了多个不同的东西,那么它必然可以使用几个范围更小的临时变量进行替代,多次赋值是非常危险的,因为你需要小心地去处理每一次变化,但如果把这个数据变成只进行一次赋值,那么它的使用就变得非常安全了。
- 循环语句——给我思考的其实不是这个坏味道本身,而是作者提出来的解决办法:
以管道取代循环
;我以前一直固执地想要在一次循环中解决所有问题,并且天真的认为少循环一次可以节省一些性能,虽然确实性能要好一些,但是多数情况下,多一次循环并不会造成致命的性能问题;相反,如果多一次循环,可以把具体的操作分隔开来,可以更清楚地展现出处理问题的思路——即使真的造成了性能问题,后期再进行改造也会更加容易。 - 纯数据类——这一种味道在很多静态语言中可能并不是“坏味道”,而是用于某些具体模块的数据其类,比如masterdata的序列化、通信的数据序列化。但是我赞同作者的一点是,尽可能不要把这些数据直接使用,而还是要进行一层封装,如果直接使用了这些数据,说明结构肯定是存在问题的——处理数据的类和具体的数据之间一定要分隔开来,并且原数据要尽可能不发生改变。
结语
计划2021年再读一遍,值得再次学习。