如何度量程序的复杂度

2016-08-02 derekchan 更多博文 » 博客 » GitHub »

php,代码质量

原文链接 http://gitdc.com/2016/08/02/metric-code-quality.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


在 PHP 程序中,类、方法(子程序)、函数是最常见的形态,在平时的编程里开发者时常会对代码的复杂度做度量,简洁抑或复杂,都是自己凭着主观意识来评判,经验丰富的开发者可能会有自己的评判标准,但一些经验尚浅的开发者写出来的代码可能在 Code Review 阶段就得返修几次,因为他们还没有能对自己的代码进行质量评测的能力,或者说没有可以量化的标准给他们参考,那么量化的参考标准是什么呢?

《代码大全》458页中有提到一个方法可以帮助开发者度量代码的复杂度,此方法最先由 Tom McCabe 提出,通过计算子程序中“决策点”的数量来衡量复杂度,步骤如下:

  1. 从 1 开始,一直往下通过程序;
  2. 一旦遇到以下关键字,或者其同类的词,就加1;(if、while、for、foreach、and、or、&&、||)
  3. 给 case 语句中的每一种情况加 1;

举个例子:

    if ((status && done) || (notDone && (numLines >= maxLines))) {
        // code … 
    }

在这段代码中,从 1 算起,遇到 if 得 2,&& 得 3,|| 得4,&& 得 5。加起来,这段代码里总共包含了 5 个决策点。

如何处理复杂度的度量结果

计算出决策点的数量以后,你就可以用得到的数值分析你写的子程序的复杂度了:

  • 0-5 子程序还不错;
  • 6-10 得想办法简化子程序了;
  • 10+ 把子程序的某一部分拆分成另一个子程序并调用它;

把子程序的一部分提取成另一个子程序,不会降低整个程序的复杂度,只是把决策点移到其他地方,但是这样做可以降低你在同一时间必须关注的复杂度水平。由于重点是要降低你需要在头脑中同时考虑的项目的数量,所以降低一个给定子程序的复杂度是有价值的。

10 个决策点的上限并不是绝对的。应该把决策点的数量当作一个警示,该警示说明你的某个子程序可能需要重新设计了。

这个方法不是通用的标准,它是可以灵活变通的,上面也提到,决策点的数量不是绝对的,只是一个参考和警示,具体的还得看子程序的逻辑需求,不要死守这个规则。一条情况很多的 case 语句可能会包含超过 10 个的元素。如果硬拆开它可能就是很愚蠢的,这取决于该 case 语句的用途。

还没有总结出测量标准的开发者可以借鉴下McCabe 的测量方法,相信它能很好的帮助你控制好你的代码质量。

扩展

其他的度量方法:

  • 所用的数据量;
  • 控制结构中的嵌套层数;
  • 代码行数;
  • 对同一变量的先后引用之间的代码行数(跨度);
  • 变量生存的代码行数(生存期);
  • 以及输入和输出的量;