私は SonarLint for Eclipse を最近使用しているので、とても役に立ちました。しかし、それは私に循環的複雑さについての疑問を投げかけました。
SonarLintは許容できるC.Cを10と見なし、私がそれを超えている場合があります(約5または6ユニット)。これらの部分は、値がさまざまな変数に依存するマッパーに関連しています。次に例を示します。
各フィールドにif
を置くこと以外に選択肢はありません。これは(幸い)私の選択ではありませんが、自分で変更できない既存の複雑なシステムです。
私の質問の核心は次のとおりです:理由単一のメソッドで高すぎるCCを持たないことが非常に重要である?いくつかの条件を1つまたは複数のサブメソッドで移動して複雑さを軽減しても、全体的な機能のコストは削減されません。問題が別の場所に移動するだけだと思いますか?
(もしあれば、小さな間違いのため申し訳ありません)。
[〜#〜]編集[〜#〜]
私の質問は、グローバルな循環的複雑度に言及するのではなく、単一のメソッドの複雑度とメソッドの分割にのみ言及します(申し訳ありませんが、私が正確に何を意味するかを説明するのに大雑把な時間があります)。条件が「スーパーメソッド」に属している場合に、条件を小さなメソッドに分割して、すべてのサブメソッドを実行するだけで、アルゴリズムが複雑になるのはなぜですか。
ただし、2番目のリンク( アンチパターンについて )は非常に役立ちます。
ここで重要なのは、「脳の能力」です。
コードのmain関数の1つは...(readになる)です。また、コードは読みやすく、理解しやすい場合があります。または難しい。
そしてhigh CCを持つことは、1つのメソッド内に多くの「レベル」があることを意味します。そして、それは意味します:あなたは、人間の読者がhard時間をもってその方法を理解するでしょう。
あなたがソースコードを読むとき、あなたの脳は自動的に物事を見通しに入れようとします:言い換えれば、それは何らかの形の「コンテキスト」を作成しようとします。
そして、ほんの数行で構成され、非常に低いCCである(良い名前の)小さなメソッドがある場合。そうすれば、脳はこの「ブロック」を簡単に受け入れることができます。あなたはそれを読み、あなたはそれを理解します。できました。
一方、コードのCCが高い場合、何が起こっているかを差し引くために、脳はさらに多くの「サイクル」を費やします。
別の言い方をすると、常に、複雑なものの単純なネットワークよりも、単純なもののネットワークcomplexを優先することに傾倒する必要があります。あなたの脳は小さなことを理解するのに優れているからです。
C.Cは、コードの臭いに関する他のすべての経験則と同様に、ヒューリスティックです。絶対的な真実を伝えるのは、フェイルセーフの基準ではありません。もしそうなら、そのような方法を単に言語で違法にし、人々に別の方法で彼らの目的を達成させることは、合理的なことです。
しかし、それは指標が機能する方法ではありません。ほとんどの場合、彼らの機能は人々に彼らが知らないに気づいていることを警告することです。あなたの場合、あなたはロジックが複雑であり、代替ソリューションがそれをさらに複雑にすることを知っています。したがって、その主な目的が、問題があることをしていないである人々に警告を出すことである場合、基本的な経験則を満たそうとしても意味がありません。
つまり、コードの可読性、つまり保守性がすべてです。
多数の(ネストされた)if
を含む長くて複雑なメソッドがある場合、実際に何をしているのかがわかりにくくなります。いくつかのプライベートメソッドを抽出して、意味のある方法で名前を付けると、はるかに簡単になります。
メソッドの循環的複雑度は、メソッドに必要なテストケースの数に関連しています。具体的には、循環的複雑度が10であるということは、テストケースがメソッドの合計ブランチカバレッジを持つ上限が10であることを意味します。また、テストが必要なパスの数から、不可能なパスを差し引いた数にも関係します。
それを超えて、私は他の考慮事項について他の回答に同意します- 開発者の精神的能力 または 潜在的な問題またはリファクタリングの指標 または 読みやすさの尺度およびコードの保守性 。
CCは単なる発見的手法であり、特定のスコアがどの程度「悪い」かは、多くの要因に依存します。
とは言っても、高いCCは常に、リファクタリングできる/すべきコードを強調するものと見なすべきです。 if
ステートメントを別のメソッドに移動すると問題が隠れると言いますが、コピーをn回貼り付ける代わりに抽象化できるパターンはありますか?長い場合if-else
チェーン、それをswitchステートメントに変えることができますか、それとも多態性などを使用できますか?深い入れ子がある場合、条件句の一部を結合できますか、それとも、異なるクラスに分割する必要がある個別の責任を示していますか?
サイクロマティックな複雑さは警告です。あなたがコードを読むことができ、理解するのに複雑すぎないなら、私はそれについてあまり心配しません、おそらくもっと重要なことについて心配することは間違っています。
あなたが言及するCCの種類を減らす1つの方法は、質問にJavaタグでタグ付けしたので、ポリモーフィズムを使用することです。そのため、コードパスの代わりに stringly typed 適切に名前が付けられたクラスを使用できます。これは役立ちますが、やり過ぎであり、コードをさらに理解しにくくすることがあります。
ただし、保守が難しいコードの兆候である可能性があります。メソッドを読んでいるときに、それぞれのケースでどのコードパスをたどるかは簡単にわかりますか?コードベースがよくわからず、関連するものをコード内でさらに探していた場合は、このメソッドをスキップできますか?メソッドを説明的な名前の付いた1/2行のメソッドに分割することを主張する人もいますが、置き換えるつもりのコードよりも読みにくい場合もあります。
最終的に保守性は難しい問題であり、どちらを読みやすくするかはあなた次第です。これについてまったく考えているということは、正しい方向に進んでいることを意味します。覚えておいてください、このコードを数年で解読しようとするメンテナはあなたかもしれません。ですから、できるだけ簡単にしてください。
それは、コードを見て(脳のサイクル)、コードが何をしているかを理解するのに費やされた時間にかかっています。
また、メソッドが大きいほど、テストが困難になり、発生する可能性のある動作の種類を予測することが難しくなります。
循環的複雑度は尺度です。この場合、高い値は潜在的な問題の指標です。複雑なコードは、理解するのに時間がかかり、おそらくそれほど複雑でないメソッドほど徹底的にテストされていません。したがって、リファクタリングとメンテナンスの目的で、コードのどの領域がこの測定と複雑であるかに注意することが重要です。
考慮すべきもう1つのことは、複雑なコードの更新です。分析を行う際、開発者はコードの複雑さを調べることにより、コードの変更が多かれ少なかれリスクがあると報告することができます。
したがって、意思決定の目的で活用および使用できる複雑さの測定には多くの価値があります。