重构 读书笔记

引言

大家好,今天想聊聊我最近读的一本书——Martin Fowler 的《重构:改善既有代码的设计》。这本书在技术圈真的是经典中的经典,估计很多同学早就看过了。我之前一直拖拖拉拉,最近才终于把它读完,读完后的感觉就是:相见恨晚

说实话,之前我对“重构”这两个字是有一些误解的。刚开始工作的时候,我觉得重构就是“没事找事”,代码能跑就行了,改来改去干嘛?直到后来接手了一个历史遗留项目,面对着一团乱麻的代码,加一个功能要改七八个文件,我才意识到——原来好的代码和坏的代码,差别真的太大了。今天就把读书的一些收获和体会分享给大家,希望能给还没读过的朋友一点参考。

什么是重构

首先咱们得搞清楚一个问题:到底什么是重构?

按照书里的定义,重构是在不改变代码外在行为的前提下,对代码内部结构进行修改。这句话听起来有点绕,简单来说就是:让代码变得更好,但功能不能变。

举个例子,你有个函数写了 500 行,嵌套七八层if-else,看得人头皮发麻。你把它拆成几个小函数,每个函数只做一件事,逻辑更清晰了,但最终的功能输出是一模一样的——这就是重构。

书里特别强调了一点:重构的目的是让代码更容易理解和修改。不是为了重构而重构,也不是为了炫技。如果你的代码已经很好用了,改了反而可能引入bug,那就没必要动它。

那些让人难受的“代码味道”

读这本书让我最大的收获之一,就是学会了识别“代码味道”(Code Smell)。这个词真的特别形象——有些代码你一看就感觉不对,但又说不上来哪里不对,这就是有“味道”了。

书里列举了很多种代码味道,我挑几个印象最深的来说:

重复代码:同一个逻辑在多个地方出现,改一处要改好几处。这是是最常见的“味道”,也是最容易修复的。 过长的函数:一个函数做了太多事情,几百行代码堆在一起。书里的建议是,一旦超过十几行,就应该考虑拆分了。 过大的类:一个类里属性和方法太多,职责不单一。想想看,如果你要修改一个功能,得去一个几千行的类里找来找去,那得多痛苦。 参数过多:一个函数参数列表老长,调用的时候根本记不住顺序。书里建议超过三四个参数就要考虑是不是该封装成对象了。 发散式变化:一种变化需要修改多个方法,说明这些方法耦合在一起。霰弹式修改:一个变化需要修改多个类,说明职责没有划分清楚。

这些“味道”就像代码的预警信号,闻到了就知道——嗯,这块代码可能需要重构一下了。

常用的重构手法

书里介绍了几十种具体的重构手法,我挑几个平时最常用的聊聊。

提取函数(Extract Function):这是我用得最多的。当一个函数太长,或者里面有一段逻辑可以独立出来,就把它拆成新函数。命名很重要,新函数的名字要能说明它做什么。
// 之前

function printOwing(invoice) {

let outstanding = 0;

console.log("======");

console.log(" owed: " + outstanding);

// 打印详情...

}

// 重构后

function printOwing(invoice) {

const outstanding = calculateOutstanding(invoice);

printBanner();

printDetails(outstanding);

}

内联函数(Inline Function):和提取函数相反,如果一个函数做的事情太简单,或者它的名字和函数体差不多,那就把它内联回去。 重命名变量:这个看起来是小事情,但其实非常重要。一个好的名字能省掉很多注释。 以函数对象取代函数:如果一个函数里用了很多局部变量,很难提取,可以把它变成一个类,局部变量变成类的属性。

书里对每种手法都讲得很细,包括为什么要这么做、怎么一步步做、可能会遇到什么问题。我觉得最贴心的是,书中给出的例子都是一小步一小步来的,不会让你一次性改太多,这样可以降低出错的风险。

重构和测试的关系

这一点我觉得特别重要,单独拿出来说。

书里反复强调:在进行重构之前,最好先有一套可靠的测试。没有测试的重构,就像在没有安全绳的情况下高空作业——胆子大是挺大的,但万一出问题就完蛋了。

我自己在这方面是有教训的。之前有次重构一段代码,自信满满,觉得逻辑很简单,结果改完上线后发现有个边界情况没考虑到,害得全组人一起加班修bug。从那以后,我重构之前一定会先补测试,确保现有行为被覆盖。

书里推荐的做法是:先写好测试,然后小步重构,每改一步就跑一次测试。这样即使出了问题,也能很快定位到是哪一步引入的。

如果项目本身没有测试怎么办?书里的建议是:先补测试,再重构。或者,至少在重构的关键节点手动验证一下功能是否正常。

我的实践体会

读完这本书后,我在工作中试着应用了一些原则,感受还挺深的。

首先,我开始有意识地控制函数长度。现在写代码的时候,如果一个函数超过四五十行,我就会想能不能拆一拆。拆完之后发现,确实好读很多。

其次,我变得更愿意改名字了。以前觉得变量名、函数名随便取取得了,反正自己能看懂。现在我会花点时间想一个更准确的名字,毕竟代码是写给人看的,多花几秒钟想名字,后续可能节省几分钟甚至几小时的理解时间。

还有就是,我学会了小步迭代。以前总觉得重构要大动干戈,把整个模块推倒重来。其实更好的方式是点点滴滴地改,每次只改一点点,积少成多。这样风险可控,也不会影响正常工作。

当然,有些时候重构的时机也很重要。如果是线上紧急bug要修,那就先别折腾了,先把问题解决再说。重构应该是在日常开发中持续进行的事情,而不是专门抽一段时间“搞重构”。

总结

总的来说,《重构》这本书真的值得一读。它不仅告诉我们什么是重构、怎么重构,更重要的是,它改变了我对代码的态度——代码不是写完就完事了,它是需要持续维护和打磨的

好的代码是对未来的自己和他人的善意。花了点时间把代码写得更清晰,后续维护的人(包括未来的自己)会感谢你的。

如果你还没读过这本书,强烈推荐找来看看。即使你已经有一定经验,相信也会有新的收获。好啦,今天的分享就到这里,咱们下次再见!