重构的原则(一)

什么是重构

重构这个词很常见,大家都在谈重构,但有很多人对“重构存在”误解,认为重构是个很繁重,很麻烦的工作,认为要把已有的软件重写,整体架构都发生了变化才叫重构,但并非如此。

《重构》这本书里对重构的定义如下:

“重构”这个词既可以用作名词也可以用作动词。

  • 名词:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
  • 动词:使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

所以,我可能会花一两个小时进行重构(动词),其间我会使用几十个不同的重构(名词)。

书里强调了:

如果有人说他们的代码在重构过程中有一两天时间不可用,基本上可以确定,他们在做的事不是重构。

总结书里的内容并结合我自己的理解,我认为重构有下面几个要素:

  1. 重构并非大张旗鼓、大刀阔斧的对现有软件进行调整,而是用很多个微小的修改组成一个大的修改,每个重构要么很小,要么由很多个小的步骤组成;
  2. 重构不会影响现有软件的功能,任何时候开始或者停止重构,当前软件的功能都是完整的、没有变化的,函数调用顺序、执行效率等可以变化,但对软件的功能无影响;
  3. 重构时,不需要或者几乎不需要重新对现有功能进行测试;

另外,书里说了重构和性能优化的区别:

重构与性能优化有很多相似之处:两者都需要修改代码,并且两者都不会改变程序的整体功能。两者的差别在于其目的:重构是为了让代码“更容易理解,更易于修改”。这可能使程序运行得更快,也可能使程序运行得更慢。在性能优化时,我只关心让程序运行得更快,最终得到的代码有可能更难理解和维护,对此我有心理准备。

两顶帽子

这里说的两顶帽子,可以理解为两个角色,或者两种行为:添加新功能和重构。

添加新功能和重构。添加新功能时,我不应该修改既有代码,只管添加新功能。通过添加测试并让测试正常运行,我可以衡量自己的工作进度。
 
重构时我就不能再添加功能,只管调整代码的结构。此时我不应该添加任何测试(除非发现有先前遗漏的东西),只在绝对必要(用以处理接口变化)时才修改测试。

为什么要提一下这“两顶帽子呢”?因为我们在软件开发过程中,经常需要在这两种行为中进行切换,当我们添加新功能的时候,发现原有的代码不容易扩展,如果修改一下的话会更好的写新功能,于是我们从“添加新功能”的角色切换为“重构”的角色,当重构完,又会切换回来“添加新功能”的角色。新功能做好后,又发现新写的代码难以扩展,于是又会切换为“重构”的角色…以此往复。无论何时,我们都应该知道现在是哪个角色,并且知道不同角色对编程状态提出的不同要求。

这里书中并没有说明编程时两个角色的要求有什么不同,我的理解是:

  • 当你添加新功能时,关注点应该在在现有代码基础上,不修改原来的代码就能实现新功能;
  • 当重构时,不能影响现有的功能。

这两件事要区分开,你可以花了半小时写新功能,写完后又花了半小时重构,但不能边写功能边修改之前的代码,前半小时和后半小时的工作是不一样的,混在一起会提高出BUG的概率。

为什么要重构

为啥要重构?当然是因为重构有诸多的好处:

重构改进软件的设计

不重构的话,软件会变得越来越糟,因为随着时间的推移,我们需要经常增加新的功能或者修改之前的功能,慢慢后面新加进来的程序员会看不懂前面的代码,也会导致新功能开发时很困难、修改之前的代码很困难。

如果没有重构,程序的内部设计(或者叫架构)会逐渐腐败变质。当人们只为短期目的而修改代码时,他们经常没有完全理解架构的整体设计,于是代码逐渐失去了自己的结构。程序员越来越难通过阅读源码来理解原来的设计。代码结构的流失有累积效应。越难看出代码所代表的设计意图,就越难保护其设计,于是设计就腐败得越快。经常性的重构有助于代码维持自己该有的形态。

重构使软件更容易理解

编程是人用编程语言和计算机交流,告诉计算机要做哪些事情,怎么做,无论怎么写,只要计算机理解了你写的代码,并按预期执行,那对于你跟计算机来说就没问题。但通常情况下,一个程序员写的代码并不是只有他自己看,还有其他程序员需要理解他的代码,要不然没法修改和拓展,所以程序的易读性很重要。

问题在于,当我努力让程序运转的时候,我不会想到未来出现的那个开发者。是的,我们应该改变一下开发节奏,让代码变得更易于理解。重构可以帮我让代码更易读。开始进行重构前,代码可以正常运行,但结构不够理想。在重构上花一点点时间,就可以让代码更好地表达自己的意图——更清晰地说出我想要做的。

而且,当过了很久(也许不用很久)后,可能连自己也会看不懂曾经写的代码。也许你对那块的业务很熟悉,因为是自己写的,所以逻辑啥的也很清楚,可能短时间就能看懂之前的代码,但那不是最好的,我们不应该把精力放在记住之前的代码逻辑上,应该是想办法让他更易读,我们无须记住当时写代码时的逻辑,任何时候看都能看懂。

我是一个很懒惰的程序员,我的懒惰表现形式之一就是:总是记不住自己写过的代码。事实上,对于任何能够立刻查阅的东西,我都故意不去记它,因为我怕把自己的脑袋塞爆。我总是尽量把该记住的东西写进代码里,这样我就不必记住它了。这么一来,下班后我还可以喝上两杯Maudite啤酒,不必太担心它杀光我的脑细胞。

重构帮助找到BUG

这很好理解,如果代码是易读的、代码逻辑是清晰的,那我们读代码时就能相对轻易的发现有没有什么隐藏BUG,当出现BUG时,也会相对容易的能找到问题所在。这就是重构带来的好处。

对代码的理解,可以帮我找到bug。我承认我不太擅长找bug。有些人只要盯着一大段代码就可以找出里面的bug,我不行。但我发现,如果对代码进行重构,我就可以深入理解代码的所作所为,并立即把新的理解反映在代码当中。搞清楚程序结构的同时,我也验证了自己所做的一些假设,于是想不把bug揪出来都难。
 
这让我想起了Kent Beck经常形容自己的一句话:“我不是一个特别好的程序员,我只是一个有着一些特别好的习惯的还不错的程序员。”重构能够帮助我更有效地写出健壮的代码。

提高编程速度

是的,这不是错觉,可能有人会觉得,重构不是要花时间吗,为什么还会提高编程速度?原因在于如果不重构,一个简单的软件从最初的版本逐渐修改、增加功能的过程中会变得很复杂,变得难以维护、难以拓展,这个难度的提升几乎是呈指数增长的。而重构让我们拥有更易读、逻辑更清晰、执行效率更高、更容易拓展的代码,新增和修改功能的时候花的时间会更少,花在重构的时间就微不足道了。

当我跟那些在一个系统上工作较长时间的软件开发者交谈时,经常会听到这样的故事:一开始他们进展很快,但如今想要添加一个新功能需要的时间就要长得多。他们需要花越来越多的时间去考虑如何把新功能塞进现有的代码库,不断蹦出来的bug修复起来也越来越慢。代码库看起来就像补丁摞补丁,需要细致的考古工作才能弄明白整个系统是如何工作的。这份负担不断拖慢新增功能的速度,到最后程序员恨不得从头开始重写整个系统。
 
通过投入精力改善内部设计,我们增加了软件的耐久性,从而可以更长时间地保持开发的快速。我还无法科学地证明这个理论,所以我说它是一个“假说”。但我的经验,以及我在职业生涯中认识的上百名优秀程序员的经验,都支持这个假说。
 
20年前,行业的陈规认为:良好的设计必须在开始编程之前完成,因为一旦开始编写代码,设计就只会逐渐腐败。重构改变了这个图景。现在我们可以改善已有代码的设计,因此我们可以先做一个设计,然后不断改善它,哪怕程序本身的功能也在不断发生着变化。由于预先做出良好的设计非常困难,想要既体面又快速地开发功能,重构必不可少。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值