web-dev-qa-db-ja.com

反復法は循環的複雑度を減らし、サポート性を改善しますか?

C#やJavaScriptなどの最近の言語で一般的に見られるような反復メソッドや、(うまくいけば)Java 8)は、コードの理解可能性やサポート可能性に対する循環的複雑度の影響を軽減しますか?

たとえば、C#では次のコードを使用します。

List<String> filteredList = new List<String>();

foreach (String s in originalList){
   if (matches(s)){
      filteredList.add(s);
   }
}

これには、単純な循環的複雑度2があります。

これは次のように簡単に書き直すことができます。

List<String> filteredList = originalList.where(s => matches(s));

単純な循環的複雑度は0です。

これは実際にサポート可能なコードになりますか?このトピックに関する実際の調査はありますか?

11
C. Ross

私の推測では、複雑さを分割/移動しただけです。 CCでの.where()の実装をカウントしないため、減少しました。

全体的なCCは実際には移動していません。独自のコードのCCは減少しました。これは、フレームワークのコードに移動したためです。

私はそれがより保守可能だと思います。言語の特徴ならそれを使いましょう。それはあなたが使っている「ああ、なるほど、それは巧妙なトリックです」ではなく、単純なインライン削減のような関数だけです。

14

あなたがしているのは、循環的複雑度の欠陥をメトリックとして強調することだけです。コードの複雑度は実際には変わっていません。最初の例には明示的な分岐があり、2番目の例には暗黙の分岐があることを理解する必要があります。 2番目の構文は、構文を理解していれば、より明確で理解しやすく、問題になる可能性のある基本的でない構文を使用します。

11
Ryathal

この質問に客観的に答えるためには、保守性のための何らかの指標が必要です。循環的複雑度自体は保守性の尺度ではありませんが、保守性を測定することを目的とする一部のメトリックのコンポーネントです。たとえば、 Maintainability Index の式は次のとおりです。

MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC)

ここで、Gは問題のコードの循環的複雑度です。したがって、コードのサイクロマティック複雑度を減らすと、コードの保守性インデックスと、同様にサイクロマティック複雑度を使用する他のメトリックスが改善されます。

あなたが提案する種類の変更がプログラムseemをプログラマにとってより保守しやすくするかどうかを言うのは難しいです。それはおそらく、あなたが(あなたの場合)whereメソッドに慣れていることに依存します。

6
Caleb

示されている 循環的複雑度(CC)はコードサイズと非常に強く相関しているため、「CCにはそれ自体の説明力がないと言えるほどです」。あなたが本当に求めていることは、「C#やJavaScriptなどの現代言語で一般的に見られるような反復法があり、そして(うまくいけば)Java 8で)、コードサイズがコードの理解可能性とサポート可能性に与える影響を減らすかどうかです。 」

その時点で、答えが明白になることを願っています。コードが短いほど、一般的に理解、維持、サポートが容易になることは、何十年も前から知られています。

3
John R. Strohm

Cyclomatic Complexityの生の統計について話しているなら、確かに。あなたはそれを2から0にかけただけです。もしあなたが数字で行っているなら、純粋な利得、ずっとです。

ただし、実用的な(読む:人間の)観点からは、実際には増加複雑さは2であると主張します。その1つの点は、他のプログラマーが知識を持ち込んだり、知識を得たりする必要があるという事実から来ています。このコードを理解するためのfluent-syntax LINQ。

困難さが増しているもう1つの点は、ラムダ式を理解することです。ラムダはかなり単純ですがこの例ではですが、それらを完全に理解するには、いくつかのパラダイムシフトを行う必要があります。

この場合、a.where(x => matches(x, arg))を使用するのはひどいことではありません。正直に言うと、同僚に初めてLINQとLambdaの式を見て操作してもらうための素晴らしい方法です(実際にLINQ /このコードや他のコードセットを使用している元同僚のラムダは、大きな効果を発揮します。)ただし、これらの使用にはある程度の知識が必要です。

LINQリファクタリングがforeachループよりも実際に読むのが大幅に悪いケースを見たことがあるので、注意することをお勧めします。

2
Andrew Gray

主観的には、ラムダ式を理解しているかどうかは、開発者の聴衆に依存します。

List<String> filteredList = originalList.where(s => matches(s));

理解が速く、おそらく少し簡単です。私は、sとmatches()の使用についてもっと心配します。どちらも自己記述的ではありません。

List<String> filteredList = 
    originalList.where(stringToBeTested => matchesNameTest(stringToBeTested));

または

List<String> filteredList = 
        originalList.where(originalListString => matchesNameTest(originalListString));

開発者により意味のある情報を提供し、分析が簡単です。matches()関数に飛び込んで、実行されている一致を判別する必要はありません。

保守性は、コードを理解する能力だけでなく、主にコードを理解できる速度と正確さに関するものです。

1
AceCTO