20

最近、私たちの会社は、コード内の関数の循環的複雑度 (CC) を毎週測定し、どの関数が改善または悪化したかを報告し始めました。そのため、関数の CC にもっと注意を払うようになりました。

CC は、1 + 関数内の決定点の数 (if ステートメント、for ループ、select など)、または関数を通るパスの数として非公式に計算できることを読みました...

CC を減らす最も簡単な方法は、Extract Method リファクタリングを繰り返し使用することだと理解しています...

不明な点があります。たとえば、次のコード フラグメントの 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 に反映されていますか?

4

8 に答える 8

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

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

より大きな問題は、あなたの会社がその背後にあるコードよりも CC に重点を置いているように見えることです。一般的に、確かに、5 未満は素晴らしい、10 未満は良好、20 未満は問題ありません。21 から 50 は警告サインであり、50 を超えると重大な警告サインです。ただし、これらはガイドであり、絶対的なルールではありません。おそらく、CC が 50 を超えるプロシージャのコードを調べて、コードの巨大なヒープではないことを確認する必要がありますが、プロシージャがそのように記述されている特定の理由がある可能性があり、実行可能ではありません (任意のいくつかの理由) をリファクタリングします。

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

于 2008-10-15T14:22:31.610 に答える
6

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

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

于 2008-10-15T11:26:09.360 に答える
5

すべてのソフトウェア指標と同様に、CC は完璧ではありません。十分に大きなコード ベースで使用すると、問題のあるゾーンがどこにあるかがわかります。

ここで注意すべき点が 2 つあります。

  1. 十分な大きさのコード ベース: 重要なプロジェクトでは、非常に高い CC 値を持つ関数が含まれます。非常に高いため、例の 1 つで CC が 2 か 3 かどうかは問題ではありません。300 を超える CC を持つ関数は、間違いなく分析するものです。CC が 301 か 302 かは関係ありません。
  2. 頭を使うことを忘れないでください。多くの決定点を必要とするメソッドがあります。多くの場合、何らかの形でリファクタリングして数を減らすことができますが、そうでない場合もあります。「CC > xy ですべてのメソッドをリファクタリングする」などのルールを使用しないでください。それらを見て、頭を使って何をすべきかを決めてください。

毎週の分析のアイデアが気に入っています。品質管理において、傾向分析は、問題の発生時に問題を特定するための非常に効果的なツールです。これは、明らかに大きくなるまで待たなければならないよりもはるかに優れています (詳細については、 SPCを参照してください)。

于 2008-10-15T11:51:41.010 に答える
4

CC は品質測定の万能薬ではありません。ループの CC の方が大きい場合でも、繰り返しステートメントがループよりも「優れている」というわけではないことは明らかです。ループの CC が大きい理由は、実行される場合と実行されない場合があり、両方をテストする必要がある 2 つの異なる「ケース」につながるためです。あなたの場合、定数を使用しているため、ループは常に3 回実行されますが、CC はこれを検出するほど賢くありません。

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

于 2008-10-15T11:25:58.860 に答える
1

循環的複雑度は温度に似ています。どちらも測定値であり、ほとんどの場合、文脈がなければ意味がありません。外の気温が 72 度だったとしても、あまり意味がありません。しかし、私が北極にいたという事実を加えると、72 という数字が重要になります。メソッドの循環的複雑度が 10 であると誰かが私に言った場合、そのコンテキストがなければ、それが良いか悪いかを判断することはできません。

既存のアプリケーションをコード レビューするとき、循環的複雑度が有用な「出発点」の指標であることがわかります。最初にチェックするのは、CC が 10 を超えるメソッドです。これらの「10 を超える」メソッドは、必ずしも悪いものではありません。コードをレビューするための出発点を提供してくれるだけです。

CC 番号を検討する際の一般的なルール:

  • CC # と # of tests の関係は、CC# <= #tests である必要があります
  • 保守性が向上する場合にのみ CC# のリファクタリングを行う
  • 10 を超える CC は、多くの場合、1 つ以上のコードの匂いを示します
于 2010-01-06T14:35:49.133 に答える
1

これは、メトリックをやみくもに適用する危険性です。CC メトリックには確かに多くの利点がありますが、コードを改善するための他の手法と同様に、コンテキストから切り離して評価することはできません。Casper Jone の Lines of Code 測定に関するディスカッションを管理者に紹介してください (リンクを見つけていただければ幸いです)。彼は、コードの行数が生産性の良い尺度である場合、アセンブラー言語の開発者は地球上で最も生産性の高い開発者であると指摘しています。もちろん、他の開発者より生産性が高いわけではありません。より少ないソースコードで高水準言語が行うことを達成するために、より多くのコードが必要になるだけです。私が言っているように、私はこれに言及しているので、メトリックがあなたに伝えていることをインテリジェントにレビューせずに盲目的にメトリックを適用することがいかに愚かであるかをマネージャーに示すことができます.

そうでない場合は、さらにレビューする必要があるコード内の潜在的なホット スポットを特定する方法として、経営陣が CC 測定値を使用することをお勧めします。コードの保守性やその他の優れたコーディングの基準に言及せずに、盲目的に CC を下げるという目標を目指すのは愚かなことです。

于 2008-10-15T11:47:49.830 に答える
0

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

循環的複雑度は、潜在的に (確実ではありませんが) 問題のあるコード スニペットを見つけるための特定の自動化されたショートカットにすぎないようです。しかし、解決すべき本当の問題はテストの問題ではないでしょうか? コードに必要なテスト ケースの数は? CC が高くても、テスト ケースの数が同じでコードがきれいな場合は、CC について心配する必要はありません。

1.) そこには決定点はありません。そこには、プログラムを通るパスが 1 つだけあり、2 つのバージョンのいずれかで可能な結果は 1 つだけです。最初のものはより簡潔で優れています。Cyclomatic Complexity は気にしません。

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

2.) どちらの場合も、「wibble」と書くか、書かないかのどちらかです。

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

3.) 最初の 1 の結果は、何もない、「1」、または「1」と「1 と 2」になる可能性があります。3 パス。2 番目のものは、2 つのうちのいずれか、または両方の結果として何も生じない可能性があります。4 パス。

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

于 2013-10-31T03:55:17.283 に答える
0

[オフトピック] メトリクスの良いスコアよりも可読性を優先する場合 (J.Spolsky が「何を測定し、何を行うか」と言ったのですか? - メトリクスは頻繁に悪用されていると思います)、多くの場合、適切な名前のブール値を使用して、複雑な条件ステートメントを置き換えます。

それから

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

なる

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

if (theWeatherIsFine)
    Console.WriteLine("wibble");
于 2008-10-15T11:38:24.547 に答える