コードの「循環的複雑さ」とはどういう意味ですか?


42

コードの静的分析は初めてです。私のアプリケーションの巡回的複雑度は17,754です。アプリケーション自体はわずか37,672行のコードです。コードの行に基づいて複雑さが高いと言うのは妥当ですか?サイクロマティックの複雑さは何を言っているのですか?


それはあなたが何をしているかに完全に依存します。単純なことをしようとしている場合、それは非常に高いです。たとえば、「hello world」ではその比率を使用しないでください。
cwallenpoole

回答:


48

サイクロマティックの複雑さは何を言っているのですか?

循環的な複雑さはコード行の尺度ではなく、モジュールを通る独立したパスの数です。17,754の循環的な複雑さは、アプリケーションに17,754の一意のパスがあることを意味します。これには、通常、アプリケーションの理解とテストがどれほど難しいかという点で、いくつかの意味があります。たとえば、循環的複雑度は、十分に記述されたテストを想定して、100%の分岐カバレッジを達成するために必要なテストケースの数です。

良い出発点は、サイクロマティックな複雑性に関するウィキペディアの記事でしょう。いくつかの擬似コードの断片と、循環的複雑さのすべてを示すいくつかのグラフがあります。さらに詳しく知りたい場合は、McCabeの論文を読んで、循環的複雑度を定義することできます。

私のアプリケーションには、17,754行のコードの循環的な複雑さがあります。アプリケーション自体はわずか37,672行のコードです。コードの行に基づいて複雑さが高いと言うのは妥当ですか?

どういたしまして。数行のコードとループ内にネストされた多数の条件を持つアプリケーションは、非常に高いサイクロマティックな複雑さを持つ可能性があります。一方、条件の少ないアプリケーションでは、循環的複雑度が低くなる可能性があります。それはそれを大きく単純化しすぎていますが、私はそれがアイデアを広めると思います。

あなたのアプリケーションが何をするのかをもっと知らなくても、より高い循環的複雑さを持つのは普通のことかもしれません。ただし、アプリケーションレベルだけでなく、クラスレベルまたはメソッドレベルで循環的複雑度を測定することをお勧めします。これは概念的にもう少し管理しやすいと思います-大規模なアプリケーションを通るパスよりも、メソッドを通るパスを視覚化または概念化する方が簡単です。


36

循環的複雑度は、コードをリファクタリングする必要があるかどうかを判断する方法です。コードが分析され、複雑さの数値が決定されます。複雑さは、分岐(ifステートメントなど)によって決定されます。複雑さは、ループなどの入れ子や、使用されるアルゴリズムに応じて他の要因を考慮する場合もあります。

数値はメソッドレベルで役立ちます。より高いレベルでは、それは単なる数字です。

17,754という数字は、プロジェクトレベルの複雑さ(合計コード)を示しており、それほど意味がありません。

クラスおよびメソッドレベルの複雑さを掘り下げることで、より小さなメソッドにリファクタリングするか、複雑さを解消するために再設計する必要があるコードの領域を決定します。

CASE1つのメソッドに50のケースがあるステートメントを考えます。たぶん、各州には異なるビジネスロジックがあります。これにより、50の循環的複雑度が生成されます。50の決定ポイントがあります。CASEステートメントは、分岐ロジックを取り除くために、ファクトリパターンを使用して再設計する必要がある場合があります。場合によってはリファクタリング(メソッドをより小さな部分に分割)でき、場合によっては再設計のみで複雑さが軽減されます。

一般に、メソッドレベルの複雑さの場合:

  • <10メンテナンスが簡単
  • 11-20メンテナンスが難しい
  • 21以上のリファクタリング/再設計の候補

また、複雑さが増すとコードの単体テストが難しくなることも考慮してください。

単一のメソッドで見た中で最も高い複雑度は560でした。1つのメソッドで約2000行のifステートメントがありました。基本的にメンテナンス不能、テスト不能、潜在的なバグがいっぱい。その分岐ロジックに必要なすべてのユニットテストケースを想像してください!良くない。

すべてのメソッドを20未満に保ち、メソッドをリファクタリングして複雑さを軽減するにはコストがかかることを認識してください。


これはより良い答えです。
パセリエ

2
@Pacerierその場合、答えを単に投票してください;)。
-Zero3

>「一般的に、メソッドレベルの複雑さのために」引用?
ベニーボッテマ

McCabeの最初のアプリケーションの1つは、プログラム開発中のルーチンの複雑さを制限することでした。彼は、プログラマは、彼らが開発しているモジュールの複雑さをカウントし、モジュールの循環的複雑度が10を超えたときに小さなモジュールにそれらを分割する必要があることをお勧め
ジョンRaynor

「CASEステートメントは、分岐ロジックを取り除くために、ファクトリパターンを使用して再設計する必要がある場合があります。」どうして?これは、ロジックの複雑さを排除するものではありません。それは単にそれを隠し、それをより目立たなくし、したがって、維持するのをより難しくします。
メイソンウィーラー

1

これは、アプリケーション内の個別のパスの数です。CCに関するこのIBMの記事をご覧ください

高いように見えますが、あなたの場合は、すべてのクラスとメソッドのすべてのメソッドのCCの追加です。あなたのコードがどのように構成されているのかわからないので、私の例はかなり広がっていますが、37672行のコードを持つ1つのモンスターメソッドまたは約10行のコードを持つ3767メソッドがあるかもしれません。つまり、アプリケーションレベルでは、このインジケーターはあまり意味がありませんが、メソッドレベルでは、コードをより小さなメソッドに最適化/書き換えして、エラーが発生しにくいようにすることができます。

個人的に何度も読んだことがあるのは、CCが10を超えるメソッドには欠陥のリスクが高いということです。

Sonarを使用してアプリケーションのコード品質をテストします。デフォルトでは、+ 10 CCのメソッドがある場合、警告が発生すると思います。それでも、それは何の意味もありません。具体的な例:Eclipseを使用しequalsてBeanのプロパティに基づいてメソッドを生成すると、CCはすぐに屋根の上に移動します...


1
PMDのデフォルト設定では、10の循環的複雑度も警告します。メソッドごとのレベルで複雑さを調べると、生成されたequalsメソッドなど、CCが高くなるのに十分な理由があるメソッドを無視することもできます。
トーマスオーエンズ

確信が持てなかったので確認しましたが、Sonarは内部的にPMDを使用してこの測定値を取得しています。だからそれはすべて理にかなっている:
ジャレイン

-1

どのツールを使用したかによって異なります。そこにあるオープンソースツールのいくつかは、クラスをモジュールとして、または他のレベルの構造をモジュールとして取ります。したがって、プロジェクトが大きくなればなるほど、サイクルの複雑度は高くなります。しかし、私の個人的な理解のために、それは機能ベースにあるべきです。プロジェクトが大きくなればなるほど、プロジェクトが持つ機能が増えます。

Lizardというツールを使用することをお勧めします。リソースコードを見つけて、githubでzipファイルをダウンロードできます。コードに機密情報があまりない場合は、オンラインバージョンもあります。

気にする必要のある有意義なCCNは、他の機能ベース以外のものです。さらに、各関数のCCNを15未満に保つことが理想的な範囲になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.