それは秘密のコードは、高いソフトウェア品質のために必要な記述、デバッグ、および維持するための複雑なものです。 さらに、コードの複雑さが高いほど、コードの欠陥レベルが高くなり、コードを維持するコストが高くなります。
だから、コードの複雑さを減らすことによって、バグや欠陥の数を減らすことができ、その寿命コストも削減することができます。 複雑なコードとは何ですか? コードベース全体であろうと、1つの小さな関数であろうと、コードの複雑さを客観的に評価するにはどうすればよいですか?
この記事では、コードの複雑さを評価するための三つの複雑さの指標について説明します。 これらは:
- 循環的複雑さ
- Switch文と論理条件の複雑さ
- 開発者スキル
コードの複雑さを評価し理解することの利点のいくつかについても説明します。
サイクロマティック複雑度
1976年、Thomas McCabe Snrはサイクロマティック複雑度と呼ばれるコード複雑度を計算するためのメトリックを提案しました。 それはとして定義されています:
プログラムのソースコードを通る直線的に独立したパスの数の定量的尺度…プログラムの制御フローグラフを使用して計算されます。
制御フローグラフに慣れていない場合:
これは、実行中にプログラムを通過する可能性のあるすべてのパスのグラフ表記を使用した表現です。
は、より直接的に言えば、コードの一部を通るパスが少なく、それらのパスが複雑でないほど、循環的な複雑さは低くなります。 その結果、コードはそれほど複雑ではありません。 メトリックを示すために、いくつかの、やや任意の、Goコード例を使用してみましょう。
例1
func main() { fmt.Println("1 + 1 =", 1+1)}
関数を通るパスは1つしかないため、循環複雑度スコアは1であり、gocycloを実行することで見つけることができます。
例2
func main() { year, month, day := time.Now().Date() if month == time.November && day == 10 && year == 2018 { fmt.Println("Happy Go day!") } else { fmt.Println("The current month is", month) }}
この例では、現在の年、月、日を取得しています。 この情報を使用して、現在の日付が2018年11月10日であるかどうかをif/else条件で確認します。
そうであれば、コードは”Happy Go day!”コンソールに。 そうでない場合は、「現在の月は」と現在の月の名前が表示されます。 コード例は、条件が3つのサブ条件で構成されている場合のように、より複雑になります。 それを考えると、それは4のより高い複雑さのスコアを持っています。
例Three
func main() { _, month, _ := time.Now().Date() switch month { case time.January: fmt.Println("The current month is January.") case time.February: fmt.Println("The current month is February.") case time.March: fmt.Println("The current month is March.") case time.April: fmt.Println("The current month is April.") case time.May: fmt.Println("The current month is May.") default: fmt.Println("The current month is unknown.") }}
この例では、time.Now().Date()
への呼び出しから取得されたmonth
の値に基づいて、現在の月を出力しています。 この関数には7つのパスがあり、case文ごとに1つ、defaultごとに1つずつあります。
その結果、その周期的な複雑さは7です。 しかし、デフォルトと一緒に年のすべての月を会計処理した場合、そのスコアは14になります。 これは、Gocycloが次の計算規則を使用しているために発生します。
1は、’if’、’for’、’caseごとの関数
+1の基本複雑さです’, ‘&&’ または’||’
これらの3つの例を使用して、コードの複雑さを計算するための標準的なメトリックを持つことによって、コードの複雑さを迅速に評価できることが
また、コードの異なる複雑なセクションがどのように比較されているかを見ることができます。 しかし、循環的な複雑さだけでは十分ではありません。
Switch文と論理条件の複雑さ
コードの複雑さの次の評価者はswitch文と論理条件の複雑さです。 以下のコード例では、2番目のGoの例を使用して、複合if条件を3つのネストされた条件に分割しました。
func main() { year, month, day := time.Now().Date() output := fmt.Sprintf("The current month is %s", month) if month == time.November { if day == 13 { if year == 2018 { output = fmt.Sprintf("Happy Go day!") } } } fmt.Println(output)}
どちらが理解しやすい(またはそれほど複雑ではない)、元のもの、またはこれですか? 次に、次の3つの質問を考慮して、これを構築しましょう。
- 上記のように、複数のif条件があり、それぞれが非常に複雑であった場合はどうなりますか?
- 複数のif条件があり、それぞれの本文のコードが非常に複雑であった場合はどうなりますか?
- コードを理解するのは簡単ですか、それとも難しくなりますか?
ネストされた条件の数が多く、それらの条件内の複雑さのレベルが高いほど、コードの複雑さが高くなると言っても過言ではありません。
ソフトウェア開発者のスキルレベル
開発者のスキルレベルはどうですか? 以下の2番目のGoの例のCバージョンを見てください。
#include <stdio.h>#include <time.h>#include <string.h>int main(){ time_t t = time(NULL); struct tm tm = *localtime(&t); const char * months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; if (tm.tm_year == 2018 && strncmp(months, "November", strlen(months)) == 0 && tm.tm_mday == 10) { printf("Happy C Day!.\n"); } else { printf("The current month is %s.\n", months); }}
技術的には、他の例が行うことを行います。 ただし、同じ結果を達成するには、より多くのコードが必要です。 公平を期すために、もし私がCに精通していれば、コードはGoの例よりも長くないかもしれません。
しかし、これが同じ結果を達成するために必要な最小値であるとしましょう。 この2つを比較すると、Goと比較したときのCの構文のより冗長な性質を考えると、理解するのが難しくなります。
さらに、Cの経験がなかった場合、比較的類似した循環的複雑度スコアにもかかわらず、あなたの認識は何でしょうか?
コードはそれほど複雑ではないと思いますか? これはコードの複雑さを理解するためのもう一つの重要な要素です。
ソフトウェアの複雑さを測定する利点
コードの複雑さを測定する利点には、4つのコアの利点があります。
より良いテスト
コードの一部を介してどのように多くの独立したパスがあるかを知ることによって、テストするパスの数を知っています。
ところで、私は100%のコードカバレッジを提唱していません—それはしばしば無意味なソフトウェアメトリックです。 しかし、私は常に実用的で可能な限り高いレベルのコードカバレッジを提唱しています。
だから、そこにあるコードパスの数を知ることによって、テストするパスの数を知ることができます。 その結果、コードがカバーされていることを確認するために、最低でも必要なテストの数の尺度があります。
リスクを低減
古い諺にもあるように:
コードを書くよりもコードを読むのが難しいです。
:
- コードは書かれているよりもはるかに読まれている
- 良いソフトウェア開発者は、彼らが書いた(または変更された)コードの行によって評価されるべきではありませんが、彼らが維持しているコードの品質によって評価されるべきではありません。
それを考えると、コードの複雑さを減らすことによって、欠陥を導入するリスクを減らすことができます。
低コスト
潜在的な欠陥のリスクが低減されると、発見して除去する欠陥が少なくなります。 その結果、維持費も削減される。
以下の図に示すように、ソフトウェアの寿命のさまざまな段階で欠陥を見つけることに関連するコストを見て、よく知っています。
だから、コードの複雑さを理解し、どのセクションが他のセクションよりも複雑であるかを理解すれば、その複雑さを減
だから、その複雑さを減らすことによって、欠陥を導入する可能性を減らします。 それはソフトウェアの人生のすべての段階に流れ込みます。
予測可能性の向上
ソフトウェアの複雑さを軽減することにより、予測可能性の高い開発が可能になります。 私が意味するのは、コードのセクションが完了するまでにどれくらいの時間がかかるかを自信を持って言うことができるということです。 これを知ることで、リリースが出荷されるまでの時間を予測することができます。
この知識に基づいて、ビジネスまたは組織は、特に当該ソフトウェアに直接依存する目標と期待を設定することができます。 このような場合は、現実的な予算や予測などを設定する方が簡単です。
開発者が学ぶのを助ける
開発者が学び、成長するのを助けることは、コードが複雑であると考えられる理由を理解することの最終的な利点です。 私がこの時点まで複雑さを評価するために使用したツールはそれをしません。
彼らがすることは、全体的または粒状の複雑さのスコアを提供することです。 しかし、Codacyのような包括的なコード複雑性ツールはそうです。
上のスクリーンショットでは、リストされている六つのファイルのうち、一つは30の複雑さを持っていることがわかります。
循環的な複雑さは、コードの品質が何らかの変更で悪化しているかどうかを理解するのに最適な指標です。 循環的な複雑さは、それを見たり、無限のスケールを与えられ、モジュールのサイズに関連していないモジュール全体を比較するときに推論するのが難し これは、どのファイルが貧弱なコード品質の候補であるかを理解するのに役立ち、その結果、それらのモジュールを理解するのに役立ちます。
それはラップです
また、これはコードの複雑さとは何か、それがどのように評価されているか、そしてそれを減らすことの重要な利点についての深 コードの複雑さを理解するには、ここで説明したよりも多くのことがありますが、それを理解するためには長い道のりがありました。
この用語について初めて聞いたり、ツールについて学んだりする場合は、リンクされた記事やツールを探索して、より多くを学ぶことをお勧めします。 GoまたはCでコード化しない場合は、googleの「コード複雑化ツール」とソフトウェア言語を追加します。 利用できる多くの用具を見つけて確実である。
コード品質を向上させるためのヒントについては、Codacyの他のブログ記事をチェックしてください。
最後に、コード品質を評価するための包括的なツールと、開発者の学習と成長に役立つツールが必要な場合は、Codacyを試してみてください。
Codacyは何千人もの開発者が毎日数十億行のコードを分析するために使用されています!
始めるのは簡単で無料です! GitHub、Bitbucket、またはGoogleアカウントを使用してサインアップするだけです。
はじめに