Blog

Blog

PHODAL

【代码范式集】:使用 “IDE 重构” 改善代码质量

IDE vs Editor

重构,指对软件代码做任何更动,以增加可读性或者简化结构,而不影响输出结果。可是我们要如何才能不影响输出结果呢???答案是:测试。测试的意义在于对输出结果进行测试,用于保障现有代码的功能是正常的。一旦我们修改了代码,导致测试失败了,那我们就知道哪里改错了。

因此重构依赖于单元测试和可测试的代码(即短小、可 mock 的代码)。在重构之前,对应的代码拥有测试是信心的保证。可由于种种情况,我们的代码中不存在测试,我们就放弃代码重构吗?

所以,这篇文章讲述地是,如何在不包含测试的情况下,来对代码进行重构——IDE 重构。需要注意的是,IDE 重构在大部分的情况下是不会影响输出结果的,但是在极少数的情况下可能会影响结果——比如 IDE 出 bug 了。hiahiahiahia~

范式:IDE 重构

IDE 重构,即借助于 IDE 来对代码进行重构,其通常是由快捷键来触发。它将重构的主要工作交给 IDE,而不是由开发人员痛苦的修改代码来完成。多数时候,我们只需要按下快速键,再输入一些必要的名称、参数,重构就完成了。因此,它是每天我们的开发中,不可获缺的一部分。可以随时随地进行,而不需要预留一个专用的重构时间。

自然而然发生

那些,我们视为腐烂的代码,并不是在第一天就如此。在最初设计的时候,它们往往有着好的代码结构,良好的设计规范。只是随着时间的推移,业务不断地增加,代码量便不断地增加,缺乏有效的代码改善机制,便会使得代码腐烂。但是,我们也不能提前对代码进行重构,那样的话就是过度设计。

重构,有时在编写代码的过程中,自然而然发生的。而 IDE 重构则是,编写代码的过程中,看到可以重构的地方,按下IDE 的快速键,迅速地完成战斗。

因此,就这种角度来看,IDE 重构是自然而然发生的,它应该作为日常开发的一部分,而不是额外的花费时间进行重构。在这一点上,也普通的代码重构是不同的。普通的代码重构,是我们看到之前的代码写得不符合规范、设计,便进一步地想去改善质量。往往,我们也会将这处重构,放置在完成功能之后进行。

值得注意的是IDE 重构所能做的内容有限,远不及常规重构的范围来得广泛。

如下是微前端 Mooa 框架中,最初某个函数的代码的一部分:

customEvent('mooa.routing.change', {
  url: eventArguments.url,
  app: activeApp['appConfig']
})

而随着业务的演进,代码便进一步便得复杂:

if (activeApp.mode === 'iframe') {
  ...
  if (iframeEl && iframeEl.contentWindow) {
    ...
    contentWindow.dispatchEvent(customEvent(MOOA_EVENT.ROUTING_CHANGE, eventArgs))
  }
} else {
  customEvent(MOOA_EVENT.ROUTING_CHANGE, eventArgs)
}

一旦,我们添加了一个新的条件,我们的代码会进一步复杂化。而在那之前,对于 if 语句而言,我的做法是什么也不做,因为无法预料它的演变。一来,这样的 if 语句没有多少演进的方式,提供重构成多态则进一步复杂代码。二来,当遇到新的需求变更时,原先的重构可能等于白做,甚至于会影响我们下一步的编程。

不过,在上述的过程中,我做了两件事:

  • 提取了公有的变量
  • 提取了公有的参数

而这些都可以通过 IDE 的提取变量的快捷键来完成。

从容不迫应对

由于 IDE 重构,更多的是依赖于工具,而不是依赖于编程经验。它可以为年轻(编程经验少)的程序员,带来一定的信心,使得他/她们开始敢去重构代码。你可能也会担心,它带好一个不好的习惯,即在不编写测试的时候,进行代码重构。所以,它看上去像是一把双刃剑。但是,在我的想法来看,只要能开始去改变,那就是一个好的开始。每个老年(资深)程序员,都是从一个坑过去的,要不就不是资深的程序员。

换句话来说,当你遇到一个棘手的问题,而有一个资深的程序员,快速地帮你解决了问题,说明他/她也走过这个坑。比如,你应对一个 git 冲突的时候,可能会束手无策,哪怕你对 SVN 再熟悉,你也要面对这种变化。这样的问题解决多了,也就有经验了。这种方式和 IDE 重构一样,都只是使用工具而已。

即使都是使用工具,就只是工具的熟悉程度与否。练习,多加练习,然后掌握 IDE 重构,迈出了第一步。再向前,你就开始走向真正的重构了。

最小犯错成本

虽然说是使用 IDE 进行重构,但是在复杂的情况下,它可能还是会出错。因此,进行任何的重构之前,我们都需要打造一个安全的环境——至少,将要重构的代码应该在本地进行提交,又或者提交到服务端。它相当于我们在完成了业务功能之后,进行一系列小的修改。

即它意味着,我们可以在一个安全的时间里提交代码,又意味着哪怕是重构失败,我们也可以回退。诸如 Git 这种支持本地提交的代码版本管理工具,大概是我见过最好的减少犯错成本的工具。不论,我对本地的代码库做怎样的修改,都可以从远程获取原来的代码。

事实上,不止于还需要提供一个安全的团队环境(政治环境),即让程序员能花时间去改善代码。但是,这种重构需要存在时间的限制。

  • 如果你花关天、一天、两天的时间,要对之前一个月的代码重构,那么并不存在问题——业务在不断叠加,每隔一段时间都会出现代码、架构上的问题。这个时候的抢救,能及时把设计正确的方式。再往后推移,可能会影响整个系统的架构,成功地实现了 “千里之堤,溃于蚁穴”。
  • 如果一处代码的重构,需要花费四五天的时间,那么就需要正视这个问题。它不是一个小问题,可能存在多个问题。对它的重构和改善,往往需要和团队里的资深程序员一起讨论。

对于重构来说,新手程序员更加需要适当地鼓励,辅以合适的技术培训,或者进行手把手的结对编程。

缺点:有限的代码质量改善

让我们再强迫一遍:

  • IDE 重构是一种有限的代码质量改善
  • IDE 重构是一种有限的代码质量改善
  • IDE 重构是一种有限的代码质量改善

它只是一种快速的重构方式,对于复杂的代码结构来说,往往是无能无力的。

function openFile(willLoadFile: string, isTempFile: boolean = false) {
  let imageRegex = /\.(jpe?g|png|gif|bmp|ico)$/i;
  let htmlRegex = /\.(html)$/i;
  let wordRegex = /\.(doc?x)$/i;

  if (imageRegex.test(willLoadFile)) {
    return mainWindow.previewFile(willLoadFile);
  } else if (htmlRegex.test(willLoadFile)) {
    return openHtmlPage(BrowserWindow, willLoadFile);
  } else if (wordRegex.test(willLoadFile)) {
    return shell.openItem(willLoadFile);
  }
}

不过,要对于这一种类似的 if 语句来说,换成 switch 语句并没有改善多少可读性。

这个时候,我们可能会考虑换成多态,这样便需要依赖于手动进行重构——需要依赖于测试。但是多态,又可能进一步复杂化代码——行数和类变得更多了。

工具

既然,本文的标题是 IDE 重构,但是它应该是叫工具重构。主要是笔者,懒,懒得配置编辑器,所以就习惯使用了 IDE。要怪就怪我司,给程序员配了 IDE。

IDE

大量的 IDE 支持重构功能,打开你最常使用的工具,你也会发现:咦,我的 IDE 也有这样的功能。如 Jetbrians 家的 Intellij IDEA 对于静态类型语言,如 Java 的支持就更好了。

如上图所示,其拥有大量地可用的重构功能。反正都是交了信仰费的人,不掌握好工具,对不起自己的辛辛苦苦的码字。

Editor + 重构插件

现在的,普通的编辑器,也拥有这样的重构功能,如 Visual Studio Code 便自带了一些。哪怕是诸如 Vim 这种原始的 IDE,加上对应的重构插件,也可以完成相应功能。如在 Visual Studio Code 中提供了一些对应的重构功能。其中比较常用的有:

  • 提取变量
  • 提取方法
  • 重命名

诸如 JavaScript 这一类的动态语言,则会应了那句话:“动态类型一时爽,代码重构火葬场”。因为各式的智能提示,都依赖于对语言的静态类型检查,但是动态类型往往很难实现这一点。使用 TypeScript 对于可维护的代码是一个可好的选择。

示例

相关的内容,可以看我之前录的视频:https://v.youku.com/v_show/id_XMTI2NjQ0NDAxMg==.html

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Engineer, Consultant, Writer, Designer

ThoughtWorks 技术专家

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 最新技术分享

标签