メモログ

⛰ 塵が積もって山とならないメモのログ 👄

Cyclomatic comlexity

Cyclomatic complexity - Wikipedia, the free encyclopedia。日本語では、循環的複雑度 - Wikipediaと呼ぶみたい。

Cyclomatic complexityは、(Wikipediaに書いてありますが)コードの中で独立した処理の進み方がいくつあるかを示したもので、コードの複雑度の指標となります。Sublime Text 2 で JSHintの記事でもそういえば書いていましたが(忘れてた)、Cyclomatic complexityは10以下が妥当な範囲としています(Testable JavaScript 参照)。JSHintではmaxcomplexityで設定することができます。

計測には、M = E - N + P という計算式が使われます。詳細はCyclomatic complexity - Descriptionに書かれていますが、Javascriptのfunctionは、functionの処理が終わった後は、処理を実行した場所(entry point)に戻るので、JavascriptのfunctionのCyclomatic complexityを調べるなら、2PではなくPになる(日本語のWikipediaはそのあたりの説明が薄い)。

この式のMはcomplexityで、Eがedgeの数、Nがnodeの数で、Pがexit nodeの数になる(javascript functionの場合、常に1つだけになる)。Cyclomatic complexity - Implications for Software Testingの内容を参考にすると、

function () {
  if (c1()) {
    f1();
  } else {
    f2();
  }

  if (c2()) {
    f3();
  } else {
    f4();
  }
}

のような処理をcontrol flow graphにすると、添付の図のようになる。edge(E)は矢印の部分になる。nodeは丸の部分で、赤丸がentry point、青色がexit pointとなっている。

File:Control flow graph of function with two if else statements.svg

edget(矢印)とnode(丸)をそれぞれ数えると、9個と7個になるので、ComplexityのMは、M = 9 - 7 + 1 で、3となる。

つまり、Cyclomatic complexityは、入り口から出口までにあるコードのブロック(node)に対して、ブロック間を行き来する道がどれだけあるかを表したものであると。ブロックの数と比較して道が多くあるということは、色んな進み方ができるということであり、バグにつながる確率が高くなると。そしてCyclomatic complexityは10までに押さえるのがよしと。それ以上になる場合は、処理の方法を変えるとか(if文ではなくfuncton mapみたいなかたちにするとか)、functionを目的別に分割するとかして、コードの簡潔性を保つのが良い。

また、既存の機能に条件分岐を増やして、Cyclomatic complexityが二倍三倍になるような修正は、バグを含みやすいので、あまり良い修正方法とは言いがたいと。

というメモ。