有些代码读上去不仅一言难尽,甚至会让人觉得恶臭,引起生理上的不适……这个时候你该怎么办?
其实,大部分人都能分辨得出哪些是“臭不可闻”的代码,但是对于如何重构它却无从下手——我们缺少的是一种了解“坏代码”如何重构的可靠方式。
在《重构》(Refactoring)一书中,肯特·贝克(Kent Beck)和马丁·福勒(Martin Fowler)将代码中的“难闻气味”与重构模式的识别联系起来,这一理论十分著名。
他们发现,仅仅知道如何重构并不意味着知道什么时候做最好。所以福勒写了一本书,其中详细介绍了常见的反码模式以及如何最好地重构它们。
篇首提到,大家都读过很臭的代码,甚至自己也编写过很臭的代码。经过了这种难以忍受的过程,会更善于识别这些气味,并在发出它们臭味前努力避免。对于遗留代码,可以将这些趋势用作提示,便于知道何时进行重构。
以下任何一种反模式的存在都意味着你的代码尚未达到其最终形式,并且可以使用一点TLC-R(温柔、爱心、关心和重构)来达到完美。在编码时应该将此列表谨记于心。
异味目录
· 代码重复
· 过大的类
· 过长函数
· 过长的参数列
· 发散式变化/霾弹式修改
· 依恋情结
· 数据泥团
· Switch惊悚现身
· 中间人
· 过多的注释
代码重复
任何时候在两个不同的地方存在相同的代码,那么廉价的气味就会在它的周围徘徊。如果设法找到加入它们的函数,代码无疑会变得更好。
如果在同一个类中的多个位置使用相同的表达式,请将其拉出到自己的函数中!两个类需要相同的函数吗?把它推入到超类当中!没有超类?那就做一个!
如果在系统中非常不连贯的部分中使用相同的代码,请考虑将其拉出到其自己的模块或类中。因为目标是确定每个代码应该存在的位置,并确保它不会隐藏在其他任何地方。
过大的类
类的第一条规则就是它们应该很小。第二条规则是它们应该更短。
罗伯特·C·马丁《代码整洁之道》
类应该只做一件事并将其做好。有了难闻的气味,一般就是你很难为类找到一个名字。如果想不到,那这个类可能过长或承担过多责任。
类包括带有‘weasel’字样的处理器、管理器或Super,这些类通常会带来气味,以表明它们承担了过多的责任。总的来讲,一个类应该只有一个改变的理由——这被称为单一责任原则。遵循此原则,类就不会出现任何异味。过长函数
与类相似,好的函数通常很短,最好的函数甚至更短。新手开发人员倾向于将大量功能推入单一函数中,留下一些注释将又长又丑的函数打破成逻辑块。函数越长就越复杂和混乱。
一个函数应该只做一件事并做好这件事,而且应该有一个明确的名称,以清楚地表明其目的。任何额外功能都应提取到自己的函数之中。
这种异味主要是对函数的分解具有攻击性。不要畏惧大量的函数——要畏惧大型的函数。
过长的参数列
在面向对象编程之前,在参数方面有两种选择:将它们都用于同一种函数或者使它们全局化。无论你如何解决问题,最终结果都会有难闻的异味。
长长的参数列表会导致混乱,主要是因为开发人员在变量命名方面非常粗心。要解决这个问题,有以下几个选择:
对象
与其将一堆相关变量传递给同一种函数,不如编写存储所有这些变量的对象,并将它们传递给不同的函数中。这些被称为数据传输对象(DTOs)或数据团,它们的受欢迎程度不同。正确封装的对象是存储相关数据块的好地方。
对一般数据应用询问函数
思考这个函数标题:
这有很多参数,没有一个弹出可以轻松删除。但是,通过应用帮助获取或查询某些数据的函数,大大减少了传递所需的信息量:
遵循这种结构可以减少重复,得到更整洁的代码和更短的参数列表——一切都闻起来很新鲜。
发散式变化/散弹式修改
构建软件的目标是支持简单的改变,毕竟它是“软”件。如果对类的更新/更改证明是困难的,那么通常会有一种潜伏在阴影中的刺鼻气味。
对于这些模式,假设需要对代码库进行常规的常见更新,无论是添加新数据库、新客户端还是新产品。
如果每个新升级需要更改类的多个部分,则称为发散式变化,这是应该避免的。请记住,一个类应该只有一个改变的理由。识别类中应该在一起的片段,并将它们提取到自己的类中。
在异味的另一面,如果一个新的变化需要对许多不同类进行很多小更新,这被称为“散弹式修改”,而且其气味可以说是更糟。当需要进行许多小的更改时,开发人员很可能会忘记一个,导致错误并放慢开发时间。这里的解决函数是收集所有小块并将它们放入自己的类中。同样,类应该至少有一项单一的责任。
依恋情结
我们还经常遇到的一种异味是,一种函数似乎对一个类以外的特性更感兴趣。最常见的违规行为包括使用外国数据。大家都看到过这样一种情况:一种函数在一些其他对象上调用了几十个子程序用来计算它自己的一个值——一种腐臭的异味。
这里的修复很简单:这个问题函数显然希望成为另一个类的一部分,所以放弃它的愿望并将其移动到那里。在类中保留最依赖的函数。将剩余的碎片提取到最有意义的地方。
数据泥团
一个较小但仍然很重要的问题是,大家经常看到一组参数或变量集中在一起。 例如,firstName几乎总是出现在lastName和email之前。嗅到这一点时应该问自己:
“如果删除其中一个数据变量,其余部分是否有意义?”
如果不是,它们最好一起作为单个数据对象。
Switch惊悚现身
一般来说,switch语句很臭。它们倾向于繁殖代码重复,将代码从存储库的一个部分复制到另一个部分。通常看到单个switch语句时,无论何时需要特定的逻辑,它都会出现在整个代码中的其他几个位置。
对于switch语句的最佳解决方案就是避免使用。相对次之的解决方案是将多态作为switch语句的结果应用,因此类可以接管以应用所有相关逻辑——无论哪里需要它。这样就可以避免大的switch块——最难闻的味道。
中间人
作为软件开发人员,会散布抽象和封装——有时还是自费。
当一个类中的大多数函数只是将它们的工作委托给其他人时,你就创建了一个中间人。这种类就是浪费,特别难以阅读。实现后开始阅读时会发现有一半的时间需要跳到其他API以了解整体情况。
解决方案就是切断那个中间人,谁需要他啊?!
过多的注释
过多的注释是所有代码库中最腐败的气味,但是,它们有可能闻到最甜蜜的味道。如果使用得当,注释可能是筛选代码时遇到的最令人愉悦的香气。
一个奇怪的业务逻辑线的愉快解释;一行注释详细说明日期变量中使用的日期模式;或者正在寻找复杂的正则表达式的细分,这些都是适当注释的例子,以及真正应该使用它们的时间。
当你觉得有必要写注释时,首先要尝试重构代码,以便任何注释都变得多余。 马丁·福勒《重构》气味清新的代码,谁不喜欢?
习惯成自然
就像我们每天早起后需要一个洗漱流程以保证清新一天的开始一样,编写代码也是类似的:通过记住以上提到的模式并在编码时嗅闻气味,最终的结果一定是干净无味的。
如果你将这些技术应用到自己的工作中并时刻关注模式,你的代码也可以清新自然!
留言 点赞 发个朋友圈
我们一起分享AI学习与发展的干货
编译组:胡昕彤、蒋馨怡
相关链接:
https://medium.com/better-programming/your-code-really-stinks-this-is-how-to-improve-it-3cfbb6b7785
如需转载,请后台留言,遵守转载规范
推荐文章阅读
ACL2018论文集50篇解读
EMNLP2017论文集28篇论文解读
2018年AI三大顶会中国学术成果全链接
ACL2017 论文集:34篇解读干货全在这里
10篇AAAI2017经典论文回顾
长按识别二维码可添加关注
读芯君爱你