【H30春AP午後】「サイクロマティック複雑度」の計測方法が全くわからなかったので調べてみたら超簡単だった件

Pocket


どーもウホーイ(@the_uhooi)です。

ナイトの順歴問題に続き、先日の応用情報技術者試験に関する投稿です。

問8の情報システム開発では「プログラムの品質評価」がテーマであり、「サイクロマティック複雑度」という指標を中心に出題されました。

ちょうど「知識ゼロから学ぶソフトウェアテスト【改訂版】」という本を読んでいて「サイクロマチック数」という単語は知っていたので、「見覚えがある!これはいける」と思って臨んだら見事に撃沈しました。

悔しいし、何より仕事にも活かせそうな内容なので、勉強してやりました。
そしたら意外と簡単だということがわかったので、勉強した範囲で「サイクロマティック複雑度」について紹介します。

注意

公式の問題冊子 がすでに公表されているので、問題を読んでから本記事を読むことをおすすめします。
H30 春 AP 午後 p.40 問8

「サイクロマティック複雑度」とは?

「サイクロマティック複雑度(Cyclomatic complexity)」とは、McCabeによって提唱されたプログラムの複雑さを示す指標です。
「サイクロマチック数」や「循環的複雑度」などとも呼ばれています。

メソッド単位で計測し、高いほどプログラムが複雑ということを示します。
簡単にいえば、ifやfor, switchなどの分岐が多いほど値が高くなります。

CCN(Cyclomatic Complexity Number)と略すことが多いので、本記事でもそのように略すことにします。

CCNが高いとどうなる?

①テストケース数が増える

分岐が多いのでその分テストケース数が増え、作成にも実施にも時間がかかるようになります。

②保守しにくい

分岐が多いと可読性が下がり、可読性が下がると修正時の影響範囲がわかりづらくなって保守がしにくくなります。

CCNの計算方法

APの問題には以下のように記述されていました。

プログラムの制御構造を有向グラフで表したときの、グラフ中のノードの数Nとリンク(辺)の数Lを用いて次の式で算出する。
サイクロマティック複雑度C = L – N + 2
プログラムの制御構造を有向グラフで表した例を図1に示す。プログラムの開始位置と終了位置、反復や条件分岐が開始する位置と終了する位置をノードとし、ノード間をつなぐ順次処理の部分をリンクとしてグラフにする。ノードとの間に含まれる順次処理のプログラムの行数は考慮せず、一つのリンクとして記述する。また、図1のリンク1やリンク4のように、処理がない場合も一つのリンクとして記述する。

複雑度の求め方がすでに複雑 です。

案の上、試験時には正しく計測できませんでした。
図1の例が単純過ぎて、if文のelseがない場合やfor文のような繰り返しがある場合の数え方が全くわかりませんでした。

家に帰って調べようと思ったときに、知識ゼロから学ぶソフトウェアテスト【改訂版】に「Microsoftがソースコードのメトリクス(指標)に使っている」と書かれていたのを思い出しました。
そこでまず「マイクロソフト サイクロマティック複雑度」でググってみると、以下のページがヒットしました。
https://msdn.microsoft.com/ja-jp/library/ms182212.aspx

読み進めていくと、衝撃の事実に辿り着きました。

サイクロマティック複雑度の算出方法

サイクロマティック複雑度は、以下のものに 1 を加算して算出されます。

  • 分岐 ( ifwhile 、および do など) の数
  • switch 内の case ステートメントの数。

…ん?
要は 分岐の数に+1するだけで求められる ということでしょうか?

試しにこの方法でAPの問題のCCNを計測してみます。

図1
分岐:if×1のみ
→CCN:1 + 1 = 2

図2
分岐:if×9, for×1
→CCN:(9 + 1) + 1 = 11

図3
分岐:if×3, for×1
→CCN:(3 + 1) + 1 = 5

全て合っています。
CCNは単純に分岐の数を表している と考えてよさそうです。
elseの有無や入れ子になっているかどうかは関係ないようです。

ただ、使用例のサイクロマティック複雑度3にあるように、分岐がif×1のみでも、判定条件が複数ある場合はその分プラスするようです。
このあたりは勉強中なのでまだわかりません。

CCNの適正値は?

CCNの適正値はいくつなのでしょうか?
低ければ低いほどよさそうですが、全メソッドのCCNが1や2だとメソッド数が増え過ぎてかえって保守しづらそうです。

先ほどのMicrosoftのページには次のように記載されています。

サイクロマティック複雑度が 25 を超えると、この規則違反がレポートされます。

どうやらMicrosoftの規則では、サイクロマティック複雑度は25以下にするよう定められているようです。
下限については特に記載されていませんでした。

さらにググってみると、以下のページに非常に興味深いことが書いてあります。
https://www.infoq.com/jp/news/2008/04/cyclomaticcomplexity

Enerjyが発見したのは、CCNが1から25のルーチンは、CCNが大きくなるとエラーになる可能性が高くなるという予想される結果にはならないこと である。もっと正確に言うならば、CCNが1から11までについては、CCNが大きくなればなるほど、バグの可能性は低くなるということである。CCNが 25に到達してはじめて、CCNが1のルーチンのエラーの可能性までエラーの可能性が上昇した。

まとめると、 CCNが11のときに不具合の潜在率が最も少なく、25と1が同等で、25を超えるとそれに比例して不具合の潜在率が上がる ということです。

CCN計測ツールの紹介

CCNの計測方法と適正値がわかったのはいいのですが、手動で全メソッドのCCNを計測するのは手間がかかります。

そこで、私が知っている2つのCCN計測ツールを簡単に紹介します。

lizard

フリーの計測ツール。コマンドライン。
https://github.com/terryyin/lizard

こちらのツールについては別記事で紹介しているので、そちらをご参照ください。

Understand

有償の計測ツール。おそらくGUI。
https://www.techmatrix.co.jp/product/understand/index.html

サーモグラフィー的な感じで、CCNの高いクラスの色を濃くする図を生成することができます。
CCNの計測以外にも様々なソースコードの解析が行えます。

ただ、私は使ったことがありません。
もし使ったことがある方がいらっしゃいましたら、使い勝手などを教えていただけると嬉しいです。

CCNを下げるには?

CCNを下げる ≒ 分岐を減らす ことだと思うので、パッと2つの方法が思いつきました。

  • ①メソッドを分割し、1メソッドあたりの分岐を少なくする
  • ②早期リターンしてその後の分岐を減らす

おわりに

CCNについていろいろ知ることができました。

まずは開発しているソフトウェアのCCNを計測するところから始め、今後新しくメソッドを実装する際は分岐を増やし過ぎないように心掛けようと思います。

参考リンク

Pocket







-プログラミング
-,

関連記事

XcodeとVisual Studio 2010のショートカットキー比較

どーもウホーイ(@the_uhooi)です。 Xcodeでよく使うショートカットキーについて、Visual Studio 2010のショートカットキーと比較した一覧を作成しました。 ショートカットキー …

iTunesの曲をiOSの着信音(アラーム音)に変換するスクリプトを作った

どーもウホーイ(@the_uhooi)です。 私は毎朝iPhoneのアラーム機能を使って起きています⏰ そこで長年思っているのですが、 用意されている音が弱すぎて全然起きれません 。 デフォルトの「レ …

20代の若手SEが概要設計のコツを書いてみる

どーもウホーイ(@the_uhooi)です。 こちらの記事に触発されたので、私も設計時に心がけていることを書いてみます。 2年ほど設計をメインで仕事しており、そのときに学んだことです。 今は設計から実 …

AWSのCUIクライアント「AWS CLI」のセットアップ方法

どーもウホーイ(@the_uhooi)です。 AWS CLIのセットアップ方法を紹介します。 目次1 「AWS CLI」とは?2 AWS CLIを使うきっかけ3 環境4 セットアップ4.1 Pytho …

テキストベースでUMLを生成するツール「PlantUML」のセットアップ&操作方法(Mac)

どーもウホーイ(@the_uhooi)です。 今回は「PlantUML」というツールの概要とセットアップ方法、操作方法を説明します。 目次1 「PlantUML」とは?2 テキストでUMLを生成するメ …





ウホーイ

20代、都内在勤SE。プログラミングを中心に、ウホーイな情報を発信していく。
[趣味] テニス、カメラ、食べ歩き