循環的複雑度が単一のメソッドで重要なのはなぜですか?


10

最近からSonarLint for Eclipseを使用していますが、それは非常に役立ちました。しかし、それは私に循環的複雑さについての疑問を投げかけました。

SonarLintは許容できるCCを10と見なし、私がそれを超えている場合があります(約5または6ユニット)。これらの部分は、値がさまざまな変数に依存するマッパーに関連しています。次に例を示します。

  • フィールドAは文字列sAに依存しています。
  • フィールドBは文字列sBに依存しています。
  • フィールドCはString sCに依存しています。
  • など...

if各フィールドに置くこと以外に選択肢はありません。これは(幸いにも)私の選択ではありませんが、自分で変更できない既存の複雑なシステムです。


私の質問の核心は、次のとおりです。単一の方法で CCが高すぎないことがなぜ重要なのですか。いくつかの条件を1つまたは複数のサブメソッドで移動して複雑さを軽減しても、全体的な機能のコストは削減されず、問題が別の場所に移動するだけだと思いますか?

(もしあれば、小さな間違いのため申し訳ありません)。


編集

私の質問は、グローバルな循環的複雑度についてではなく、単一のメソッドの複雑度とメソッドの分割についてのみです(申し訳ありませんが、私が正確に何を意味するかを説明するのに大雑把な時間を費やしています)。すべてのサブメソッドを実行するだけの「スーパーメソッド」にまだ属しているのに、条件を小さなメソッドに分割して、アルゴリズムに複雑さを加えることが許されるのはなぜですか。

ただし、2番目のリンク(アンチパターンについて)は非常に役立ちます。




^^^「矢じり」の質問は、コードを改善する方法を説明するという意味で、おそらくより適切な複製ですが、循環的複雑度に関する質問の一部に答える詳細な説明のため、最初の質問を選びました
gnat

メソッドを小さな部分に分割しても、実行されるコードの総量は減りませんが、発生している個々のタスクがわかりやすくなります。それらはすべて、より大きな全体に絡まっているときよりもはるかに簡単に個別に理解できます。少なくとも、より大きなスコープから使い捨ての中間変数の多くを削除します。
Doval

1
あなたが説明した特定のケースでは、「A = extractAFrom(sA);」のような主要なメソッドで何かをします。各フィールド。実際のフィールドとその使用法を知っているので、おそらくもっと良い名前を思い付くでしょう。
Tin Man、

回答:


32

ここで重要なのは、「脳の能力」です。

コードの主な機能の1つは... 読むことです。また、コードは読みやすく、理解しやすい場合があります。または難しい。

また、CC が高いということは、1つのメソッド内に多くの「レベル」があることを意味します。そして、それは意味します:あなたは、人間の読者としてその方法を理解するのに苦労するでしょう。

あなたがソースコードを読むとき、あなたの脳は自動的に物事を見通しに入れようとします:言い換えれば、それは何らかの形の「コンテキスト」を作成しようとします。

また、数行のみで構成され、CCが非常に小さい(良い名前の)小さなメソッドがある場合、そうすれば、あなたの脳はこの「ブロック」を簡単に受け入れることができます。あなたはそれを読み、あなたはそれを理解します。できました。

一方、コードのCCが高い場合、何が起こっているかを差し引くために、脳はさらに多くの「サイクル」を費やします。

別の言い方をすると、常に、複雑なものの単純なネットワークよりも、単純なものの複雑なネットワークを優先することに傾倒する必要があります。あなたの脳は小さなことを理解するのに優れているからです。


9
つまり、基本的には技術的な問題ではなく、人間の問題なのでしょうか。これは確かに、ちょっと賢いように聞こえます。これまで私がそれをどのように考えていなかったかはわかりません。よろしくお願いします!
Yassine Badache 16

4
その場合は、Robert Martinの「クリーンコード」を入手することを強くお勧めします(ネットで無料でPDFを見つけることができます)。読みやすいコードを作成することは、最も重要なことの1つですが、優れたプログラマーのおかげで無視されることがよくあります。
GhostCatがモニカCに敬意を表します。

@YassineBadache CCはまた、隅々までテストすることを困難にします(完全なカバレッジ)。
TulainsCórdova16年


私の経験では、ほとんどの場合、CCが高いメソッドにバグがあり、CCが低いメソッドにバグがある場合、それらは通常は完全に明らかであり、コードの最初の実行を隠すことができません。また、低CCメソッドを変更する必要がほとんどないことがわかります。
Loren Pechtel 16

6

CCは、コードの臭いに関する他のすべての経験則と同様に、ヒューリスティックです。絶対的な真実を伝えるのは、フェイルセーフの基準ではありません。もしそうなら、そのような方法をその言語で違法にし、人々に別の方法で彼らの目的を達成させることは、合理的なことです。

しかし、それは指標が機能する方法ではありません。ほとんどの場合、彼らの機能は人々が知らなかったことを人々に警告することです。あなたの場合、あなたはロジックが複雑であり、代替ソリューションがそれをさらに複雑にすることを知っています。したがって、問題の存在を知らない人に警告を出すことが主な目的である場合、基本的な経験則を満たそうとしても意味がありません。


2
OPが「FieldAがString sAに依存している」と述べている場合、これをCalculateFieldA(String sA)に移動すると、コードがより複雑になることに確信が持てません。
Taemyr

2

つまり、コードの可読性、つまり保守性がすべてです。

多数の(ネストされた)を含む長くて複雑なメソッドがあるif場合、実際に何をしているのかわかりにくくなります。いくつかのプライベートメソッドを抽出して、意味のある方法で名前を付けると、はるかに簡単になります。


これは良い答えですが、少し短いです。あなたが言っていることの例を提供できて、OPによって尋ねられた質問についてより具体的にできれば素晴らしいでしょう:「単一の方法で高すぎるCCを持たないことがなぜなぜ重要なのですか?」。
マチャド

2

メソッドの循環的複雑度は、メソッドに必要なテストケースの数に関連しています。具体的には、循環的複雑度が10の場合、テストケースがメソッドの合計分岐カバレッジを持つ上限は10です。また、テストする必要のあるパスの数から、不可能なパスを差し引いた数にも関係します。

-私は、他の考慮事項については、他の回答に同意し、それを超えて精神的な開発者の能力潜在的な問題やリファクタリングの指標、コードの可読性と保守性の尺度


0

CCは単なる発見的手法であり、特定のスコアがどの程度「悪い」かは、多くの要因に依存します。

とは言っても、高いCCは常に、リファクタリングできる/すべきコードを強調するものと見なすべきです。ifステートメントを別のメソッドに移動すると問題が隠れると言いますが、n回コピー貼り付けする代わりに抽象化できるパターンはありますか?それが長いif-elseチェーンである場合、それをswitchステートメントに変えることができますか、あるいは多態性などを使用できますか?ネストが深い場合、条件句の一部を結合できますか、それとも、異なるクラスに分割する必要がある個別の責任を示していますか?


0

サイクロマティックな複雑さを警告として見ています。あなたがコードを読むことができ、理解するのに複雑すぎない場合、私はそれについてあまり心配しません、おそらくもっと重要なことについて心配することは間違っています。

言及するCCの種類を減らす1つの方法は、Javaタグで質問にタグを付けたので、ポリモーフィズムを使用することです。したがって、文字列で型指定されるコードパスの代わりに、適切な名前のクラスを使用できます。これは役立ちますが、やり過ぎであり、コードをさらに理解しにくくする可能性があります。

ただし、保守が難しいコードの兆候である可能性があります。メソッドを読んでいるときに、それぞれのケースでどのコードパスをたどるかは簡単にわかりますか?コードベースがよくわからず、関連するものをコードでさらに探していた場合は、この方法をスキップできますか?メソッドを説明的な名前の付いた1/2行のメソッドに分割することを主張する人もいますが、置換するつもりのコードよりも読みにくい場合があります。

結局のところ、保守性は難しい問題であり、どちらを読みやすくするかはあなた次第です。これについてまったく考えているということは、正しい方向に進んでいることを意味します。覚えておいてください、このコードを数年で解読しようとするメンテナーはあなたかもしれません。ですから、できるだけ簡単にしてください。


0

それは、コードを見て(脳のサイクル)、コードが何をしているかを理解するのに費やされた時間にかかっています。

  • 10行の方法を検討してください-何が行われているかを理解するには、おそらく数分かかります。
  • 100行の方法を検討してください-何が行われているかを理解するには、おそらく1時間以上かかります。
  • 1000行の方法を検討してください-何が行われているかを理解するには、おそらく1日以上かかります。

また、メソッドが大きくなると、テストが困難になり、発生する可能性のある動作の種類を予測することが難しくなります。

循環的複雑度は尺度です。この場合、高い値は潜在的な問題の指標です。複雑なコードは理解に時間がかかるため、それほど複雑ではないメソッドほど徹底的にテストされていません。したがって、リファクタリングとメンテナンスの目的で、コードのどの領域がこの測定と複雑であるかを確認することが重要です。

考慮すべきもう1つのことは、複雑なコードの更新です。分析を行うとき、開発者はコードの複雑さを調べることにより、コードを変更することは多かれ少なかれリスクがあると報告することができます。

したがって、意思決定の目的で活用および使用できる複雑さの測定には多くの価値があります。


1
申し訳ありませんが、ゴーストキャットの回答は非常によく似ています。
Jon Raynor
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.