追求代码质量 – 驯服巨大的冗长代码
副标题#e#
我绝不忸怩地认可,在看到巨大的代码块时,我也会感想惊骇和心里发毛。事实上,我敢说您在碰着大量要领和参差不齐四处伸张的类时,也会 有些心里 发毛的。不能说在这些环境下寻求退路的人不是完人,这只是优秀开拓人员的一 种本能。过于巨大的代码难以测试和维护,这凡是还意味着更高的堕落率。
我在 本系列前面的文章 中已经表明白圈巨大性,它是令人讨厌的代码的一 种先兆。具有高圈巨大度值的测试要领险些老是把工作弄得一团糟,无法等闲收 场。上一个月,我向您展示了如何利用 Extract Method 模式重构您的代码,从 而将您带出迷宫。低落要领的巨大度可以使代码更易于测试和维护,如图 1 所 示:
图 1. 低落巨大度可以使代码更易于维护和测试
不外,圈巨大性并不是确定高风险代码的惟一巨大性怀抱。您还可以操作类 长度、要领长度和内部类耦合。这些怀抱之间存在着错综巨大的关联,可是很容 易发明这些关联。这个月,我将表明它们为什么那么重要,以及如何利用 PMD 和 JavaNCSS 跟踪它们。
代码太多了!
相识简朴代码和流通代码之间的区别很是重要。简朴代码不必过度简朴或易 于编写,只需易于领略 即可。您可以利用 C++ 编写简朴代码,就像利用 Visual Basic 编写它们那样。不外,用任何语言反简化 代码的最快方法都是一 次编写大量的代码。
思量一下如何将此法则应用于要领和类。大大都人对记着信用卡号感想头疼 的一个简朴原因是,我们一次只能打点 7(±2) 片数据。相识了这一点,就会明 白过多的条件会赐与后带来贫苦,使测试和维护变得很坚苦。沟通的道理也可以 应用于逻辑块。
所有给定代码主体凡是包括已分组的语句,它们拥有配合的方针,好比建设 一个荟萃,将数据项添加到该荟萃中。可是,在一个长要领(long method)中 分组数量浩瀚的逻辑块大概会让人很快健忘该要领的总体意图,因为很少有人可 以有效处理惩罚这样一个大的数据集。恰恰是这个缺点带来了代码基中的维护问题。冗长的要领是缺陷的避风港,因为很少有人可以有效地阐明它们。长要领不只完 成太多的事情,也需要人们费很大的劲去领略!
就像长要了解让开拓人 员讨厌一样,长类(long class)也会令开拓人员讨厌。沟通的接头也可以应用 于总体代码,冗长的类大概会做太多的事情,并包袱太多的责任。
什么 样才算太长?
虽然了,长要领或类的分别有点主观。有一个很有辅佐的 履历法例,您可以说非代码注释行高出 100 行的要领是长要领。不外,实际的 数值是按照谈论的人而变革的。就我而言,截至点(cutoff point)约莫是 50 行代码,但有些开拓人员会说,假如某一要领需要您向下转动整整一天才气看完 ,那么该要领太长了。截至点的界说取决于您本身。
雷同地,您必需有 本身简直定正确类巨细的精采判定。很多人所倡导的一条履历法例是,类的代码 行高出 1,000 行就可以说该类太长了。而另一些人则认为最好不要高出 500 行 代码。
内部类耦合
对付一工具与其他工具之间的干系,巨大模式 会不绝反复其自身。对付导入很多外部依赖项可能拥有很多 public 要领的类, 不单领略起来有些坚苦,并且所带来的责任重担的增加也会导致某种懦弱。
我将从依赖项开始。假如某一工具导入的外部类高出 80 个(不包罗普 通的 Java™ 系统库),那么就可以说该类具有高度输出耦合,这意味着 变动导入的类大概会影响该类自己。在最糟糕的环境下,假如导入的是详细的类 ,而且它们的行为产生变动,那么执行导入的类大概会间断!
调查工具导入的数量就很容易预测懦弱性,但假如利用 .* 标记(譬喻 com.acme.user.*)导入整个包,则很大概发生误导。为了更准确起见,大概需 要留意工具所拥有的惟一范例 的数量(该数量可通过理会代码得到 —— 不是 import 语句)。假如应用措施的包布局大抵上以某种在少数包中包括很多类的 方法设计,则惟一范例怀抱(types metric)大概很有辅佐。
包括很多 public 要领的类也有很多导入。这些类凡是会成为代码基的中心 ,就像 Facades 或东西类那样。因为存在这种责任(通过大量 public 要教育 出),所以它们具有高度的输入耦合,也会导致反向的懦弱性。假如这些类中的 任何一个产生变动,各类外貌上不相关的应用措施部门大概 产生间断。
#p#副标题#e#
巨大性是如何发生关联的
#p#分页标题#e#
到今朝为止,所给出的模式都在体现臃肿的代码(长要领、太多的 public 要领、过多的条件和导入,等等)将影响可读性、可测试性和可维护性。因为该 模式用各类怀抱来反复本身,所以所有这些因素城市导致彼此关联。譬喻,长方 法凡是得容忍高圈巨大度值,如图 2 所示:
图 2. 长要领与圈巨大性彼此关联
不外,相关性并不止于此。具有过多导入的类会有很多惟一范例。这些类通 常很是大。而大型的类凡是拥有长要领,长要领又经常有很高的圈巨大度值。图 3 展示了巨大性怀抱是如何相关的:
图 3. 巨大性怀抱是如何相关的
PMD 和 JavaNCSS
少量的繁琐代码可用 PMD 和(更小范畴的)JavaNCSS 轻松处理惩罚,很容易结 合利用这两种东西,以构建诸如 Ant 和 Maven 之类的平台。
可以将 PMD 看作是基于法则的引擎,它阐明源代码并陈诉正被违反的某一规 则的所有实例。PMD 今朝界说了约莫 200 个法则,个中一些特定法则是针对方 法长度、类长度和惟一范例的,尚有一些用于计较 public 要领。您还可以界说 定制法则和修改现有法则(譬喻,为了反应域的需求)。
定制 PMD
譬喻,我将利用 PMD 的颠末得当定名的 ExcessiveMethodLength 法则来发 现长要领。此法则的默认长度阈值是 100(这意味着假如某个所扫描要领的长度 高出 100 行,则 PMD 会陈诉呈现一个违规),可是假如您喜欢的话,可以低落 该阈值。
PMD 法则可以界说属性,通过站在 PMD 开拓团队的角度很好地举办预见,您 可以通过利用法则集文件在运行的时候包围这些属性。要将 ExcessiveMethodLength 法则的默认值从 100 低落到 50,可以将 properties 元素添加到 rule 界说中并引用属性的名称。在清单 1 中,我将一个名为 minimum 的属性添加到了 PMD rule 界说中:
清单 1. 定制 ExcessiveMethodLength 法则
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength">
<properties>
<property name="minimum" value="50"/>
</properties>
</rule>
用 Ant 东西挪用带有定制法则集文件的 PMD 需要通过 PMD 任务的 rulesetfiles 属性提供一条到该定制文件的路径,如清单 2 中所示:
清单 2. 引用定制法则集文件
<pmd rulesetfiles="./tools/pmd/rules-pmd.xml">
<formatter type="xml" toFile="${defaulttargetdir}/pmd_report.xml"/>
<formatter type="html" toFile="${defaulttargetdir}/pmd_report.html"/>
<fileset dir="./src/java">
<include name="**/*.java"/>
</fileset>
</pmd>
PMD 陈诉由源文件导致的违规,正如您在图 4 中可以看到的,在本例中,只 有少数几个要领的源代码行高出了 50 行:
图 4. PMD Ant 陈诉的示例
对付长类,PMD 有 ExcessiveClassLength 法则,长类的默认值为 1,000 行 代码。对付 ExcessiveMethodLength 法则,很容易利用更适合的值包围默认值 。另外,PMD 尚有一个用来计较惟一范例的法则,即 CouplingBetweenObjects 法则。要计较导入,请拜见 ExcessiveImports 法则。这两个法则都是可设置的 。
利用 JavaNCSS 丈量代码是否冗长
PMD 界说了用来阐明源代码的特定法则,与 PMD 相对,JavaNCSS 阐明代码 基并陈诉所有一切 与代码长度相关的事项,包罗类巨细、要领巨细和类中找到 的要领数量。对付 JavaNCSS,阈值无关紧急,它计较所找到的每个文件并陈诉 值,而不管 巨细如何。尽量与 PMD 对较量而言,这类数据看起来好像有些机械 (而且大概有点罗嗦!),但它有它存在的原理。
通过陈诉所有文件巨细,JavaNCSS 使领略相关值成为大概,而 PMD 经常难 以做到这一点。譬喻,PMD 只陈诉违规的文件,这意味着只领略部门代码基的数 据,而 JavaNCSS 在上下文中提供了代码长度数据,如图 5 所示:
图 5. JavaNCSS Ant 陈诉的示例
竣事语
绿地开拓(greenfield development)是指开拓团队首先开拓一个空缺的 IDE 节制台,并用大度、简捷的代码填充它,这只是软件应用措施保留期中一个 很是小 的片断。如今,许多跨国企业仍然在运行基于 COBOL 的应用措施,从开 发人员的角度看,这意味着要与您不认识的人在好久以前编写的代码作斗争。
#p#分页标题#e#
在碰着这样的困难时,凡是会令人感想很是厌恶,您只能在持续几天的时间 里声称本身生病了举办逃避。随后的某一时刻,您必需面临大量代码块并将它们 搞定。利用针对类长度、要领长度和内部类耦合的巨大性怀抱(即工具导入和惟 一范例)是领略您所面对的坚苦的第一步。从一些与类巨细和要领巨细有关的经 验法例开始,然后利用诸如 PMD 和 JavaNCSS 之类的东西具体先容。
当第一次在遗留代码基上利用巨大性怀抱时,您将相识到一个复杂的数量, 但不要就此愣住脚步。通过继承监督巨大性怀抱,您可以作出更明智的抉择,并 在不绝扩展和维护代码时低落风险。