こんにちは、リサーチパネルの佐々木です。

今回は循環的複雑度(Cyclomatic Complexity)を使って、レガシーコードの変遷を追ってみようと思っています。というのも、リサーチパネルで動いているコードはVGの中では古い方(所謂レガシーコードってやつ)で、日々そんなコードと格闘しています。

そこで何か良いものがないかと思ったところで、循環的複雑度(Cyclomatic Complexity)って測定で計ってみようかと思い、あるプロジェクト(社内システム)の過去コードをほじくり返して、その辺を数値を今回計ってみます。(たぶん、どんどん複雑度が増しているんだろうなと思いつつ...)

ソースコードの一部の循環的複雑度は、ソースコード内の線形独立な経路の数である。実際、if文やfor文のような分岐点のないソースコードの場合、その複雑度は 1 であり、そのコードには1つの経路しかない。コードに1つのif文が含まれていれば、コードには2つの経路があることになる。つまり、一方はif文での条件が真となる場合の経路で、もう一方はそれが偽となる場合の経路である。
循環的複雑度 - Wikipedia

ちなみに対象プロジェクトは PHP で書いているので、計測にはphpmd (PHP Mess Detector)を使ってみようと思います(単に使ってみたかった...)。phpmdは、潜在的なバグになりそうなコードを洗い出してくれるツールで、巨大なメソッドや未使用な変数を指摘してくれます。

ということで、今回のその中の循環的複雑度(それ以外も出すことできますが)を出してみたいと思います。なお、数値のレベルとしては、phpmd では以下のようになっています。

循環的複雑度(CC)状態
1-4複雑度が低
5-7複雑度が中程度
8-10複雑度が高
11-複雑度がとても高い

他にも、以下のような考え方もあるので、その辺の数値も使って分類してみたいと思います。(11辺りから少しずつ気を付けた良さそうですね。)

循環的複雑度(CC)状態
1-10シンプルなプログラム。リスク小
11-20やや複雑なプログラム。リスク中
21-50複雑なプログラム。リスク大
51-テスト不可能なプログラム。リスク特大

ただ、デフォルトだと10以上を閾値として結果を出すため、問題のないレベルも出力するようにruleset.xmlを作成し、phpmdの実行結果を集計してみました。(phpmdの詳しい使い方は他に譲ります)

  • ruleset.xml
    <!--?xml version="1.0"?-->
    <ruleset xsi:nonamespaceschemalocation="
                         http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:schemalocation="http://pmd.sf.net/ruleset/1.0.0
                         http://pmd.sf.net/ruleset_xml_schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://pmd.sf.net/ruleset/1.0.0" name="sample PHPMD rule set">
        <rule ref="rulesets/codesize.xml/CyclomaticComplexity">
            <properties>
                <property value="1" name="reportLevel">
            </property></properties>
        </rule>
    </ruleset>
  • 実行コマンド
    phpmd <対象プロジェクトディレクトリ> text ruleset.xml
結果は...

循環的複雑度(Cyclomatic Complexity)の推移

徐々に複雑度の高いプログラムが増えてきているようですね。あと、複雑なものはそのまま残り続けているようです。自分が対象プロジェクトの改修を進めようとする際、どうしても複雑なプログラムは触りたくないし、修正する時も継ぎ接ぎ的な改修になっていた気がします。

こういった複雑なコードは、意識的にリファクタリングをかけていかないと、恐らく残り続けてしまうので、その辺りを改善するには、
  • テストコードを書く
    • 複雑なコードの場合は経路が増えテスト自体が書きづらくなるので、テストをしやすくしようとするとシンプルになっていく。
  • 定常的にチェックする仕組みを作る
    • 「リリース前のコードレビューする」や「CIなどで日々計測・警告をする」といった仕組み作ることで、早めに複雑なコードを除いていく。
といったところでしょうか。これらの対応が良いか検証まではできてないのですが、VG全体としてはこういった流れは強くなっていると感じています(きっと)。

今回phpmdを使って計りましたが、これはコードのある一側面を計測したものですし、全てのプロジェクトで同じ状態になるわけではないでしょうが、コードの質を保つ一指標として見ても良いのかと思っています。

今後もレガシーコードと戯れつつ、モダンなコードへの変遷をどこかで報告できればと思っています!