虽然代码还是可以跑,但是各种规则越来越复杂、核心继承体系越来越凌乱、系统的维护工作越来越重……
1999 年,Martin Fowler 作为技术顾问造访了一个项目,他建议项目经理好好整理这些乱糟糟的代码。然而,项目经理表示:🙏算了吧🙏
六个月后,这个项目宣告失败,因为代码太复杂难以调试,性能也达不到要求。
这件事给 Martin 留下很深的印象,随后,他写下了《重构:改善既有代码的设计》。
《重构》出版 22 年后,已成为软件开发领域不可替代的经典。这本书解释了重构的原理和最佳实践方式,并给出了修改代码的动机和具体案例,值得反复消化咀嚼。
这本书还凝聚了多位软件开发领域专家的宝贵经验:摩根大通架构师 Bill Opdyke 在第 13 章记述他将重构技术应用到商业开发过程中的一些问题;软件开发方法学泰斗 Kent Beck 和 Don Roberts 合写了第 14 章,展望重构技术的未来——自动化工具;Kent Beck 还写了最后一章,总结如何学习重构。
你将从这本书中获得:
无论你是软件工程师还是产品经理,都需要翻一翻这本经典;而系统设计师和架构师则更有必要了解重构原理,根据需要在自己的项目中运用重构技术、优化系统性能。
💡 小编提醒,这本书中第一版的案例语言使用 Java,第二版的语言使用 JavaScript。总体而言,作者展示的重构手法在各种主流的面向对象语言中基本上都可以通用。
为何重构?
第二章中,作者详细介绍了重构的价值。重构不仅可以改进软件设计本身的缺陷、帮助找到 bug、提升开发速度,还可以使软件更容易被理解——这是因为,程序设计很大程度上是人与计算机、人与人的沟通。
Martin Fowler 曾提及,任何一个傻瓜都能写出计算机可以理解的代码,唯有能写出人类容易理解的代码的,才是优秀的程序员。
所谓程序设计,便是与计算机交谈。你编写代码告诉计算机做什么事情,它的响应则是按照你的指示行动。你得及时填补「想要它做什么」和「告诉它做什么」之间的缝隙。这种编程模式的核心就是「准确说出我想要的」。除了计算机之外,你的源码还有其他读者。计算机是否多花了几个小时来编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才要命呢——如果他理解了你的代码,这个修改原本只需一小时。……而很多时候,那个未来的程序员就是我自己。
《重构(第2版)》译者熊节也曾谈到,「编程其实是个社会活动」。
一方面,程序员要把自然语言说出来的需求翻译成机器能运行的机器语言;另一方面,翻译出来的结果(也就是代码)还要支撑团队(包括技术和非技术的团队)不断地在它基础上协作和交流。……编程的大挑战不是把代码写出来,而是要在代码的基础上建立有效的多方沟通。
那么,我们何时需要重构?书中第三章列举了一些「代码的坏气味」。「坏气味」指的是代码中某些不完美之处,开发人员可以通过这些细节上的征兆在代码中追捕到更大问题。小编不禁联想到了《Clean Code》中的「好气味」和「坏气味」。
一个重构案例
众所周知,重构有风险,挖坑需谨慎。如果重构方式不恰当,风险反而更大。
试想一下这样的情况:你挖掘自己的代码,很快就发现了一些可以修改的地方,于是你挖得更深。挖得愈深,可以修改的地方就愈多……最后,你给自己挖了一个大坑,再也爬不出去了。
为了避免掉进坑里,重构必须按照一定的原则和方法进行。
作者在第 5 - 12 章给出了一个重构列表,每一个重构案例都写明了重构适用的情景、动机、重构方法。让我们来看一个案例吧:
Extract Method(提炼函数)
你有一段代码可以被组织在一起并独立出来:
void printOwing(double amount) {
printBanner();
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + amount);
}
将这段代码放进一个独立函数中,并让函数名称解释该函数的用途:
void printOwing(double amount) {
printBanner();
printDetails(amount);
}
void printDetails (double amount) {
System.out.println ("name:" + _name);
System.out.println ("amount" + amount);
}
这样做的动机:
函数应该简短而有的良好命名。原因如下:
重构方法
随后,作者给出了无局部变量、有局部变量、对局部变量再赋值三种范例,手把手解释如何提炼函数。