サイクロマティックな複雑さを軽減するためのコードの構造化についての説明を求める

StackOverflow https://stackoverflow.com/questions/204369

質問

最近、当社は、コード内の関数の循環的複雑度(CC)を週単位で測定し、どの関数が改善または悪化したかを報告し始めました。そのため、関数のCCにより多くの注意を払うようになりました。

CCは、1 +関数内の決定点の数(ifステートメント、forループ、選択など)、または関数を通るパスの数として非公式に計算される可能性があることを読みました...

CCを減らす最も簡単な方法は、抽出メソッドのリファクタリングを繰り返し使用することです...

不明な点があります。次のコードフラグメントのCCは何ですか?

1)

for (int i = 0; i < 3; i++)
    Console.WriteLine("Hello");

そして

Console.WriteLine("Hello");
Console.WriteLine("Hello");
Console.WriteLine("Hello");

両者は同じことをしますが、最初のバージョンはforステートメントのために高いCCを持っていますか?

2)

if (condition1)
    if (condition2)
        if (condition 3)
            Console.WriteLine("wibble");

そして

if (condition1 && condition2 && condition3)
    Console.WriteLine("wibble");

言語がC#などの短絡評価を行うと仮定すると、これらの2つのコードフラグメントは同じ効果がありますが、3つの決定ポイント/ ifステートメントがあるため、最初のフラグメントのCCは高くなりますか?

3)

if (condition1)
{
    Console.WriteLine("one");

    if (condition2)
        Console.WriteLine("one and two");
}

そして

if (condition3)
    Console.WriteLine("fizz");

if (condition4)
    Console.WriteLine("buzz");

これらの2つのコードフラグメントは異なる動作をしますが、同じCCを持っていますか?または、最初のフラグメントのネストされたifステートメントのCCが高いですか?つまり、ネストされたifステートメントは理解するのが精神的に複雑ですが、それはCCに反映されていますか?

役に立ちましたか?

解決

  1. はい。最初の例には決定点があり、2番目の例にはありません。したがって、最初の例には高いCCがあります。
  2. はい、たぶん、最初の例には複数の決定点があるため、CCが高くなります。 (説明については以下を参照してください。)
  3. はい、多分。明らかに決定点の数は同じですが、CCを計算する方法は異なります。つまり、...

...会社が特定の方法でCCを測定している場合、その方法に精通する必要があります(できればツールを使用してこれを行う)。さまざまな状況(ケースステートメント、ブール演算子など)のCCを計算するさまざまな方法がありますが、使用する規則に関係なく、メトリックから同じ種類の情報を取得する必要があります。

より大きな問題は、他の人が言及していることであり、あなたの会社はその背後にあるコードよりもCCに重点を置いているようです。一般的に、5以下は素晴らしい、10以下は良い、20以下は大丈夫、21〜50は警告サイン、50以上は大きな警告サインであるべきですが、これらは絶対的なルールではなくガイドです。 CCが50を超えるプロシージャ内のコードを調べて、コードの巨大なヒープではないことを確認する必要があります。リファクタリングする理由の数)

ツールを使用してコードをリファクタリングしてCCを削減する場合は、ツールが何をしているかを理解し、単に1つの問題を別の場所に移しているだけではないことを確認してください。最終的には、コードに欠陥がほとんどなく、適切に動作し、比較的簡単に保守できるようにする必要があります。そのコードのCCも低い場合、それは良いことです。コードがこれらの基準を満たし、CCが10を超えている場合は、できる限りの管理策を講じてコードを守る(そしておそらくポリシーを調べるようにする)ときが来たのかもしれません。

他のヒント

ウィキペディアのエントリとThomas J. McCabeの元の論文を閲覧した後、上記の項目はメトリックの既知の問題であること。

ただし、ほとんどのメトリックには長所と短所があります。十分に大きなプログラムでは、CC値がコードの複雑な可能性がある部分を指している可能性があります。しかし、その高いCCは必ずしも複雑であることを意味しません。

すべてのソフトウェアメトリックと同様に、CCは完全ではありません。十分に大きなコードベースで使用すると、 が問題のあるゾーンになる可能性のある場所を知ることができます。

ここで心に留めておくべきことが2つあります。

  1. 十分な大きさのコードベース:些細でないプロジェクトでは、CC値が非常に高い関数があります。非常に高いので、例の1つでCCが2でも3でも構いません。300を超えるCCの関数は、間違いなく分析対象です。 CCが301か302かは関係ありません。
  2. 頭を使うことを忘れないでください。多くの決定点を必要とする方法があります。多くの場合、何らかの方法でリファクタリングしてより少なくすることができますが、できない場合もあります。 <!> quot;のようなルールを使用しないでください。すべてのメソッドをCC <!> gt; xy <!> quot;。それらを見て、あなたの脳を使って何をすべきかを決めてください。

毎週の分析のアイデアが好きです。品質管理では、傾向分析は問題を特定するための非常に効果的なツールです。作成中。これは、大きくなるまで待つ必要がないよりもはるかに優れています( SPC を参照)いくつかの詳細について)。

CCは、品質を測定する万能薬ではありません。明らかに、繰り返される文は<!> quot; better <!> quotではありません。ループのCCが大きい場合でも、ループよりもループのCCが大きくなるのは、実行される場合と実行されない場合があり、2つの異なる<!> quot; cases <!> quot;両方をテストする必要があります。あなたの場合、定数を使用しているため、ループは常に3回実行されますが、CCはこれを検出するのに十分ではありません。

例2のチェーンifと同じ-この構造により、condition1とcondition2のみが真の場合に実行されるステートメントを使用できます。これは、<!> amp; <!> amp;を使用する場合には不可能な特殊なケースです。そのため、コードでこれを利用しない場合でも、if-chainは特別な場合に大きな可能性を持っています。

これは、 any メトリックを盲目的に適用する危険です。 CCメトリックには確かに多くのメリットがありますが、コードを改善する他の手法と同様に、コンテキストから離して評価することはできません。経営陣に、コードの測定に関するキャスパージョーンの議論を指してください(リンクを見つけてほしい)。彼は、Lines of Codeが生産性の良い尺度である場合、アセンブラー言語の開発者は地球上で最も生産性の高い開発者であると指摘します。もちろん、他の開発者ほど生産的ではありません。少ないソースコードで高レベルの言語が行うことを実現するために、より多くのコードが必要になります。私が言うように、私はこれに言及しますので、メトリックがあなたに言っていることをインテリジェントにレビューすることなく、盲目的にメトリックを適用することがどれほど愚かであるかをマネージャーに示すことができます。

そうでない場合は、コードの潜在的なホットスポットを見つける方法としてCCメジャーを使用して、さらにレビューする必要があることを経営者が賢明に勧めます。コードの保守性やその他の優れたコーディング手段を一切参照せずに、CCの低下という目標を盲目的に目指すのは愚かです。

サイクロマティックの複雑さは温度に類似しています。これらは両方とも測定値であり、ほとんどの場合、コンテキストがなければ意味がありません。外の温度が72度だと言ったら<!>#8217; tはあまり意味がありません。しかし、私が北極にいたという事実を追加すると、72という数字が重要になります。メソッドの循環的複雑度が10であると誰かが私に言った場合、そのコンテキストなしではそれが良いか悪いかを判断することはできません。

既存のアプリケーションをコードレビューするとき、循環的複雑度が便利な<!>#8220;開始点<!>#8221;メトリック。私が最初にチェックするのは、CC <!> gt;のメソッドです。 10.これらの<!>#8220; <!> gt; 10 <!>#8221;メソッドは必ずしも悪いわけではありません。コードをレビューするための出発点を提供してくれます。

CC番号を考慮する際の一般的な規則:

  • CC#とテスト数の関係は、CC#<!> lt; = #tests
  • でなければなりません
  • CC#が増加した場合にのみリファクタリングする 保守性
  • 10を超えるCCは多くの場合、1つ以上のコードの匂い
  • を示します

[トピック外]メトリックの良いスコアよりも読みやすさを優先する場合(J.Spolskyが言ったように、<!> quot;何が測定されたのか、完了しました<!> quot;?-メトリックがより頻繁に乱用されることを意味します私が推測するよりも)、複雑な条件ステートメントを置き換えるには、よく知られたブール値を使用する方が良い場合がよくあります。

then

if (condition1 && condition2 && condition3)
    Console.WriteLine("wibble");

なる

bool/boolean theWeatherIsFine =  condition1 && condition2 && condition3;

if (theWeatherIsFine)
    Console.WriteLine("wibble");

私はこのテーマの専門家ではありませんが、2セントを与えると思いました。そして多分それだけの価値があります。

Cyclomatic Complexityは、潜在的に(しかし間違いなく)問題のあるコードスニペットを見つけるための特定の自動化されたショートカットのようです。しかし、実際の問題を解決するのはテストではありませんか?コードにはいくつのテストケースが必要ですか? CCが高いが、テストケースの数が同じでコードがクリーンな場合、CCについて心配する必要はありません。

1。)決定点はありません。プログラムには1つだけのパスがあり、2つのバージョンのいずれかで可能な結果は1つだけです。 1つ目は、より簡潔で優れたものであり、循環的複雑性はdam落します。

両方の1つのテストケース

2。)どちらの場合も、<!> quot; wibble <!> quot;と書くか、またはあなたはしません。

両方の2つのテストケース

3。)最初の結果は、<!> quot; one <!> quot ;、または<!> quot; one <!> quot;および<!> quot; 1つおよび2つの<!> quot;。 3つのパス。 2つ目は、2つのうちのいずれか、または両方とも、何も生じない可能性があります。 4つのパス。

最初の3つのテストケース 2つ目のテストケース4つ

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top