Cyclomatic Complexity は関数(メソッド)の複雑さを測る指標で、この値が大きければ大きい程関数が複雑だと言えます。
Wikipediaなどの定義を見ると、有向性グラフを描いてエッジの数だとかノードの数だとかを足したり引いたりするとか書いてあって、訳が分かりません。
しかし実際にはそんなに小難しいものではなく、ごく大雑把に言うと、 1 + (ループの数) + (if文の数) と考えることができます。要は関数の中に分岐がどれだけあるかを示すものです。なので、全く分岐の無いストレートな関数では1になります。ね、簡単でしょ?
因みに"cyclomatic"を辞書で引いても出てきません。出てきてもこのcyclomatic complexityに辿りついてしまいます。多分このためだけに作った造語なのでしょう。あまり単純な言葉を使うと安っぽく見られるとでも思ったのでしょうか。実態を考えると、単にbranch number (分岐数)とでも呼べば済むような気がします。
この cyclomatic complexity は測定ツールによって多少の方言があります。例えば以下の単純なJavaコードを考えます。
int foo(int a, int b) { if (a > 17 && b < 42 && a + b < 55) { return 1; } return 2; }
このコードを各ツールで測定すると、Eclipse Metrics Plugin では2、 GMetrics では4、SonarQube では5となります。これはif文全体を一つの分岐と考えるか、if文の中の条件をそれぞれ別の分岐と捉えるかによります。ツールの実装によって多少値が異なります。
このcyclomatic complexity値は大きくなる程、コードが読みにくく、メンテナンス性も悪くなる、と考えるのが一般的です。しかし以下のコードを見て下さい。
String getMonthName (int month) { switch (month) { case 0: return "January"; case 1: return "February"; case 2: return "March"; case 3: return "April"; case 4: return "May"; case 5: return "June"; case 6: return "July"; case 7: return "August"; case 8: return "September"; case 9: return "October"; case 10: return "November"; case 11: return "December"; default: throw new IllegalArgumentException(); } }
case文一つが一分岐になるので、この関数のcyclomatic complexity値は14になります。一般的にはちょっと複雑過ぎる値ですが、決して読みにくくはありません。一目見ただけで意図は充分に分かります。しかし実際にはこんなコードはまず書きません。Mapを使えば分岐などゼロにできます。なのでやはり、メトリックス値が大きい場合は何らかの対策を考えた方が良いのかも知れません。
またcyclomatic complexity値は一般には関数の複雑さを示す指標ですが、テストケースでカバーすべきパターンの最大数と考えることもできます。値が大きくなる程、テストケースでカバーするのが困難になります。
で、このcyclomatic complexity値はどの程度を目指せばいいのでしょうか?人それぞれだと思いますが、大体10以下であればかなり健全なコードであると言えます。Android Studio/IntellJ IDEAでもデフォルトで10を越えると警告が出るようになっています。(勿論閾値は調整可能です。)
0 件のコメント :
コメントを投稿