JetBrains製のC# IDEであるRiderには、様々なプラグインが提供されています。 その中から、コードの複雑度を計測するプラグインを2つ紹介します。
サイクロマティック複雑度
サイクロマティック複雑度(cyclomatic complexity)は循環的複雑度とも呼ばれ、コードの複雑さを測る指標としてよく使われます。 メソッド単位に分岐によるパスの最大数を算出した数値で、一般に、32以上でバグ混入率が高い、50以上でテスト困難と言われています。
これをRiderのインスペクションに組み込むプラグインがCyclomaticComplexityです。
CyclomaticComplexityプラグインは、一般のプラグインと同様、Preferences... > Plugins からインストール・有効化できます。 有効化すると、エディタのメソッド定義の上にサイクロマティック複雑度が表示されるようになります。
上図では、サイクロマティック複雑度が29、Wariningとなるしきい値20(デフォルト値)に対して145%であると表示されています。
しきい値は、Preferences > Languages & Frameworks > Cyclomatic Complexity で変更できます。 既存プロジェクトで数値の高いメソッドが多い場合は、しきい値を緩めの値にして目立つものから少しづつリファクタリングを進めていくことをおすすめします。
コグニティブ複雑度
コグニティブ複雑度(cognitive complexity)とは、2016年からSonarSource社*1が提唱している比較的新しい複雑度の指標です。循環的複雑度にならって日本語化するのであれば「認知的複雑度」でしょうか。
Cognitive Complexity - A new way of measuring understandability
SonarSource社は、サイクロマティック複雑度では保守性を正しく数値化できておらず、その点を改善したものがコグニティブ複雑度であると書いています。
例えば、サイクロマティック複雑度ではネストしたループとswitch-caseは同じスコアになりますが、後者のほうが理解しやすいコードのはずです。 また、異常系の処理をif文で深くネストした中に書くよりも、メソッドの先頭でエラーチェックしてreturnしてしまうほうが読みやすくなります。
そのため、分岐ではなく処理の流れを阻害する個所を加点することで保守性・可読性の評価につなげようというものがコグニティブ複雑度です。
このコグニティブ複雑度をRiderのインスペクションに組み込むプラグインがCognitiveComplexityです。
CognitiveComplexityプラグインは、一般のプラグインと同様、Preferences... > Plugins からインストール・有効化できます。 有効化すると、エディタのメソッド定義の上にコグニティブ複雑度が表示されるようになります。
上図では、コグニティブ複雑度が23、Wariningとなるしきい値10(デフォルト値)に対して230%であると表示されています。またクリックすることでコード内の加点された個所(上図ではif文の横にある"+1")を表示できます。
しきい値は、Preferences > Languages & Frameworks > Cognitive Complexity で変更できます*2。 既存プロジェクトで数値の高いメソッドが多い場合は、しきい値を緩めの値にして少しづつリファクタリングを進めていくことをおすすめします。
プロジェクト単位のインスペクション実行
いずれのプラグインもRiderのインスペクション機能に組み込まれていますので、Code > Inspect Code... でスコープを指定して実行できます。
実行結果は"Inspection Results"ウィンドウに表示されます。
上図のように、WARNING > Potential Code Quality Issues の下に、サイクロマティック複雑度とコグニティブ複雑度それぞれ別に表示されます。
- Element exceeds cyclomatic complexity
- Element exceeds Cognitive Complexity threshold
なお、両方のしきい値を超えているメソッドは、コグニティブ複雑度にのみ表示されます。
まとめ
同じ目的を持つ2つのプラグインを紹介しましたが、いくつかのプロジェクトで見比べた感じ、コグニティブ複雑度のみ適用しておけばよさそうです。
複雑度の高いメソッドは、条件の組み合わせも多くなりテストすることが難しく、バグも作り込まれやすくなります。 プラグインを入れて数値を気にすることで、適切にメソッドを分割して保守性の高い状態をキープできるようになるでしょう。
なお、CyclomaticComplexityプラグインの存在はUnityゲーム開発者ギルドのSlackで知りました。色々と役立つ情報を交換ができるコミュニティですので、Unityでゲームを開発している方は入ってみてはいかがでしょうか。