当前位置: 首页 > 科技观察

臭代码到底有多糟糕?—Measuringtheimpactofcodesmells

时间:2023-03-18 22:21:33 科技观察

一项科学实验,用于衡量哪些代码气味最难维护。如何处理臭代码?我们的前辈曾经教导我们,作为开发人员,我们的主要责任不是写出糟糕的代码。除非你是一个单打独斗的人,只是写几行即将被弃用的Perl脚本,否则最重要的一点是你写的代码必须易于阅读和理解。在软件产品的整个生命周期中,可维护的代码通常可以使您和您的同事免于坐在计算机前的许多小时的痛苦和绝望。然而,导致代码可读性差的原因并不总是很清楚,这也是存在编码标准、指南、代码模式和编程语言咒语等内容的原因之一。一个著名的指南是MartinFowler[1]写的《重构》一书,它描述了一系列代码异味和重构策略以消除它们。尽管有这些宝贵的资源,我们仍然面临着挑战——除了学习许多重构策略外,我们还需要决定应该优先考虑哪些重构策略。显然,它们不可能同等重要!我们怎么知道我们现在所做的代码重构工作会产生长期的积极效益呢?问题是MartinFowler的重构书没有提到哪些代码味道是关键的,哪些不是。福勒自己提到,没有任何标准或指标能与人类的直觉相匹敌。我们作为开发者只能依靠直觉和经验来决定是否需要重构。这可能是一场噩梦。面对一个有成千上万种代码味道的系统,你应该从哪里开始呢?此外,对代码的任何更改都可能产生意想不到的副作用。即使使用高质量的自动化测试,更改代码通常也是有风险且代价高昂的。如果您知道哪种代码味道最具破坏性,请先摆脱它们。另外,我们要向管理层表明,我们不是为了写漂亮的代码而浪费时间去写漂亮的代码,而是我们现在的努力会在未来为项目带来长期的收益。[补充]:在软件开发领域,代码中任何可能导致深层次问题的症状都可以称为代码气味。通常,在对代码进行简短的反馈迭代时,代码气味会揭示深层次的问题,其中反馈迭代是指以一种小的、受控的方式重构代码。基于这些暴露的问题,人们会进一步检查设计和代码中是否存在其他代码味道,然后再做进一步的重构。从负责重构的开发人员的角度来看,代码气味可以告知何时以及如何进行重构。因此,可以说代码气味驱动重构。(来自维基百科)收集有关代码气味的事实2009年,挪威Simula研究所需要将内部系统改造为新的内容管理系统。该项目外包给了6名Java开发人员。这个项目被认为是一个深入研究代码异味对可维护性影响的机会。在项目持续的三个月中,他们使用工具来测量代码气味,每天采访开发人员,并在每个开发人员的EclipseIDE上安装一个日志记录工具。这个日志记录工具不仅记录了修改每个文件所花费的时间,还记录了搜索、浏览和翻阅代码所花费的时间。在项目过程中,他们使用问题跟踪工具来记录开发人员面临的问题,然后回溯到导致问题的源代码文件。此外,还会采访所有开发人员。这个过程收集到的数据远远超过了传统的只分析代码仓库的方法。以下是所做的观察:观察1:***类实际上非常糟糕!来源:https://simula.no/publications/Simula.simula.1460《人尽皆知》***不好,但到底有多坏?如下图所示:Y轴代表项目维护期间读取和修改文件所花费的时间;X轴表示文件的大小。请注意,读取和修改最大文件(1844行代码)花费的时间是大多数文件(少于600行代码)的10倍以上。这个文件是一个***类。另请注意,20000秒几乎是5小时的工作(对于一个文件来说太长了!)。我们还可以看到编辑另一个大文件(大约1400行代码)并没有花费太多时间。这个大文件包含许多没有任何逻辑的访问器和修饰符(与包罗万象的类相比)。这就解释了为什么开发人员没有花太多时间在这上面。包含复杂逻辑(即包罗万象的类)的大文件会显着影响可维护性。建议:您应该将包含复杂逻辑的大文件拆分成较小的文件。建议的阈值是将文件大小保持在1000行代码以下。观察2:数据团并没有你想象的那么糟糕……来源:https://simula.no/publications/Simula.simula.1456“数据团”是语义上不相关的方法和变量的集合。通常,包含数据blob的文件包含不同类型的变量,后跟一系列访问器和修饰符。比如下图中的Person类,包含的信息与一个人没有直接关系,所以可以分为两个类。Simula的研究人员创建了一个统计模型来解释代码异味的存在是否会增加开发人员在维护期间遇到问题的可能性(他们记录维护期间遇到的所有问题以及导致问题的文件)。他们发现包含数据块的文件实际上不太可能导致维护问题!建议:不要管这些数据块,除非它们包含其他代码味道。观察3:坚持接口分离原则RobertC.Martin(Bob大叔)介绍了接口分离原则(ISP)作为SOLID原则的一部分[2]。接口分离原则指出,任何软件库的调用者都不应被迫依赖于它不调用的方法。接口分离原则将一个非常大的接口分成更小更具体的接口,这样调用者只需要知道他们关心的方法。软件工程研究人员[3]提出了如何使用代码量化标准来识别某些代码气味。一些商业工具实现了这些量化标准,但您也可以提出自己的探测策略并在Java中的SonarQube或.Net中的NDepend等工具中实现它们。下图显示了Simula使用的检测策略,该策略基于研究员RaduMarinescu[4]的工作。该类的类“接口宽度”(即公共方法和属性的数量)为10,该类的“调用者”数量为8,“平均接口成本”(即调用者的数量)调用者使用的方法或属性除以调用者数量)是0.375。根据这种探测策略,这个类可能违反了接口分离原则。对datablob的分析也涵盖了违反接口分离原则,发现当一个文件违反了接口分离原则时,其出现问题的概率会增加。如下图所示,违反接口分离原则的文件比不违反界面分离原则的文件出现问题的概率更高(30%左右),这也印证了上述观点。建议:隔离过于广泛和多用途的接口可以降低维护问题的风险。#p#观察结果4:代码异味倾向于成群出现来源:https://simula.no/publications/Simula.simula.1508在同一个实验中,一些代码异味在同一个文件中呈现出共同出现的趋势。如下图所示,识别出的代码味道往往出现在同一个文件中。“气味囤积者”本质上是试图囤积所有系统功能的文件。“混淆因素”是那些导致文件混淆的代码味道。另外两组“广泛的接口”和“数据容器”的含义是不言自明的。建议:如果你在一个文件中发现某种代码味道,你可能想检查它是否有其他“气味伙伴”。在同一个文件中组合代码异味会增加风险并降低可维护性!长文略读就像Fowler所说的,我们必须根据我们的直觉、经验和判断来决定需要重构的内容,但是以下基于科学研究的指南可以帮助您确定优先级:分离那些包含太多逻辑的大文件(更多than1000linescode)关键是不要重构数据blob将那些宽泛通用的接口根据用途拆分成不同的接口包含某些代码味道的文件往往同时有更多“不受影响”欢迎朋友,关注识别它们!重构快乐!引文:【1】《重构:改善既有代码的设计》【2】《敏捷软件开发(原则模式与实践)》【3】http://sewiki.iai.uni-bonn.de/research/cultivate/tutorial_exploring_smells_and_metrics【4】http://loose.upt.ro./download/thesis/thesis.zip补充:CommoncodesmellDuplicatecode:相同或相似的代码存在于多个地方LongMethod:很长的方法、函数或过程Megaclass:一个非常大类。参数太多:函数的冗长参数列表ns或程序使代码的可读性和质量很差。属性附件:一个类过度使用另一个类的方法。亲和性:一个类依赖于另一个类的实现细节。拒绝继承:子类以'拒绝'的态度覆盖基类中的方法。也就是说,子类不想继承父类中的方法。参考里氏代换原则。冗余类/寄生虫:功能太少的类。人为的复杂性:当简单的设计已经足够时,强制使用极其复杂的设计模式。长标识符:特别是在软件工程中,应该毫无保留地使用命名约定,以消除歧义。超短标识符:除非显而易见,否则变量名应反映其功能。过度使用文字:为了提高可读性并避免编码错误,应该使用命名常量。此外,字面量值可以而且应该在可能的情况下独立存储在资源文件或脚本中,以便在软件部署到不同区域时可以轻松实现本地化。(摘自维基百科)原文链接:http://fagblogg.mesan.no/how-bad-is-smelly-code/翻译链接:http://blog.jobbole.com/48521/