原文链接:https://ardalis.com/measuring-aggregate-complexity-in-software-applications
在开发应用程序的过程中,我们有很多衡量方法复杂度的工具。在专业版的Visual Studio中,可以使用Cyclomatic Complexity(CC)工具(圈复杂度)来计算代码的复杂度。如果你希望有一种工具能够让你更加快速、直观的的了解大型、复杂的代码库,我推荐你可以使用NDepend工具。圈复杂度主要用以计算给定方法的独立现行路径条数。简单没有分支的方法,复杂度是1.而一个大型、复杂的有很多if条件、else语句的方法,CC计算的复杂度也许会非常高。CC的一般准则是,你的代码需要复杂度尽可能小于10,而20则有一点高、如果超过30,意味着代码的已经几乎维护了。也许会有一些意外,但通常这是一个合理的经验法则,当分析代码来查找问题区域时,识别CC值是一个很好的起点。
在对有自动属性(或者一些小的方法)进行类分析时,你通常可以看到到许多变量的CC值只有1,因为每一个get和set方法都只有1的复杂度。这使得很难将圈复杂度用作类或一个基准类、命名空间、项目或者类库的启发式基准。哪个是一个类最好的数字?是不是应该看一下总值?平均值?我们该怎么来比较一个拥有20个属性的类和一个有复杂度为20的方法?通常,你并不能回答这些问题。圈复杂度体内过程只是一种衡量方法复杂度的方法,在更高级的使用过程中使用会崩溃 。
CC通常只能用于作为一个方法或功能测量有用。
聚合计算性
我找到了一种方式,让我能使用圈复杂度来计算聚合计算复杂度模型,这可以让我们能比较两个类或者两个项目。它使用了一个基点系统,低复杂度的方法得0分,因此一些大量低复杂度的方法,不会影响计算的结果。我当前版本是一个简单版本,但是看起来迄今为止实践结果是有效的。聚集复杂度是一个是将所有类(项目)中的所有的方法求和后,除以10,然后舍去小数点。在这个聚合结果中,复杂度为1-9的,累计为0;在10-19中,累计为1,20-29中,累计为2,依此类推。使用这种方法可以使总体复杂度的类或项目得分为0。实际上,它甚至可以使用大量的CC 9方法来实现。跟其他聚合计算基数一样,在过程中也许会丢失一些详细内容。然而,作为一个可以让我们进一步提高代码质量的简答粗放或者启发式的工具,这种聚合计算看起来是非常有效的。他通常能够在计算原始的CC值时能够更好的工作。作为一个提高代码质量的工具,聚合计算能够在代码重构过程中让开发者能够聚焦于他们想关注的内容。当然,有关联的简单方法也许不会影响这个指标,但是一些较大的复杂方法会影响指标。因此,开发者无需花费太大的精力来修复问题,他们已经可以直接了当的忽略那些bug太多的方法。
反对使用此启发式的一个可能的论点可能是它没有检测到具有太多属性的非常长的方法或方法。是的,这是真的,但这不是它的意图。我们已经有代码行推断,可以让我们更加简单的工作,同时也可以让从类或项目级别(当然也包括方法级别)更好的应用。我们同样也可以更加简便的使用像NDepend来发现那些超出一定数量的属性、字段、和方法等对象的类。
我创建了两个NDpend片段,可以让我们挖掘出在单个类或单个项目中的相关数值。
聚合类型复杂度
聚合类型复杂度实现了一个点系统方法复杂度的求和,在这个复杂度中,1-9级别是0,10-19级别为1,20-29为2级,依此类推。一个方法的复杂度如果小于10,那么他的聚集类型复杂度为0分。一个相对较高的得分表征类中更加合理的复杂度,而不仅仅表达方法或属性的简单路径。
下图为结果集的屏幕截图,第二项是一个超过200000代码行生成的数据集。也许看起来这个复杂度数据量非常大,但是它大部分都是属性值。这些都是生成的代码,但是它表现出的使用基于点的规则和单纯的使用CC值求和之间复杂度的区别。
聚合项目复杂度
聚合项目复杂度使用点系统来总结系统的复杂度,其中1-9为0点,10-19为1点,20-29为2点,依此类推。只有类和方法且其圈复杂度为10的项目的聚合项目复杂度为0。更高的复杂度表现了项目或者程序集中真实的复杂度,而不仅仅表征在所包含的类型中,简单路径或者属性的简单路径情况。
下图为一个例子,请注意,其中的第四行,它代表一个DTOs项目、并且生成功能非常少的数据集。
这是个围绕一个拥有上百个类库的企业项目的分析结果。他显示,大部分的复杂性,都可能是原始的复杂度造成的。例如,在进行复杂度排序时,一个项目的RawCC超过了5500,但是他的聚合项目复杂度只有2。像一个WCF引用项目的RawCC值超过了1500,但是其聚合项目复杂度确实0。避免这种错误的极端情况是一种不同聚合度的指标。
综述
在进行软件分析时,包括体系架构的审查、代码质量的审查,等等,都是我日常工作中经常处理的事情。指出一个庞大代码量、或者快速增加的代码库中存在的问题是一个低成本、高价值的活动。有时,这种分析已经在管理过程中,在进行项目重新架构或者重构时,作为一个例行工作或一个风险分析手段。有时,他也是一种在项目开发过程中作为正在进行的一种审查手段。也有时是有种收购过程中的尽职调查的一部分。无论何时,使用像NDpend在内的分析工具也是在项目过程中,在大量的代码中快速找出潜在的风险或者甚至是编译错误的一种高效的手段。在任何情况下,像NDepend这样的静态分析工具对于能够快速查询大量代码并运行可以标记警告甚至构建失败的潜在问题的规则非常有用。