読みやすさに関するシンプルさに関する以前の質問には、コードのシンプルさの定義と理解が間違っている可能性が非常に高いことがわかりました。
コードでシンプルさを定義するにはどうすればよいですか?コードのシンプルさを測定するために、どのソフトウェア測定およびメトリックが利用可能ですか?
読みやすさに関するシンプルさに関する以前の質問には、コードのシンプルさの定義と理解が間違っている可能性が非常に高いことがわかりました。
コードでシンプルさを定義するにはどうすればよいですか?コードのシンプルさを測定するために、どのソフトウェア測定およびメトリックが利用可能ですか?
回答:
複雑さを測定するための最も一般的なメトリック(または単純さを複雑さの反対にすれば単純さ)は、McCabeのCyclomatic ComplexityおよびHalstead Complexity Metricsです。
循環的複雑度は、特定のユニット(通常はメソッドまたは関数)を通る個別のパスの数を測定しますが、クラスで計算することもできます。パスの数が増えると、所定のモジュールを通るデータの流れを覚えることが難しくなります。これは、作業メモリの概念に関連しています。高度な循環的複雑度は、モジュールをテストする能力の難しさを示す傾向があります-システムを通るさまざまなパスをカバーするには、より多くのテストケースが必要です。また、高い循環的複雑度を高い欠陥率に関連付けた研究もあります。通常、循環的複雑度10は、ユニットをレビューし、場合によってはリファクタリングする必要があることを示します。
Halsteadの複雑さの測定では、合計および個別の演算子とオペランドの入力を使用して、コードの量、難易度、および労力を計算します。(一意の演算子の数/ 2)*(オペランドの総数/一意のオペランドの数)である難易度は、システムの学習やコードレビューの実行などのタスクのコードを読み取って理解する能力に関連しています。この場合も、システムレベル、クラスレベル、またはメソッド/関数レベルでこれをカウントできます。こことここでこれらの測定値を計算することに関するいくつかの投稿があります。
コードの行を数えるだけでも、複雑さを知ることができます。コードの行が増えるということは、モジュール内で読み、理解する必要のある行が増えることを意味します。これをスタンドアロンの測定として使用することをためらいます。代わりに、特定のモジュール内の欠陥の数など、他の測定で使用して欠陥密度を取得します。欠陥密度が高い場合、テストの作成とコードレビューの実行に問題があることを示している可能性があります。これは、複雑なコードが原因である場合とそうでない場合があります。
ファンインとファンアウトは、データの流れに関連する2つの他のメトリックです。ここで定義されているように、ファンインは呼び出されたプロシージャの合計、パラメータの読み取り、グローバル変数の読み取り、ファンアウトは特定のプロシージャを呼び出すプロシージャの合計、書き込まれたパラメータ(外部ユーザーに公開され、参照によって渡されます)、およびグローバル変数に書き込まれます。繰り返しますが、ファンインとファンアウトが大きいということは、モジュールが理解しにくいことを示している場合があります。
特定のパラダイムでは、他にも有用な測定値またはメトリックが存在する場合があります。たとえば、オブジェクト指向の世界では、カップリング(低い方が望ましい)、凝集度(高い方が望ましい)、および継承の深さ(低い方が望ましい)の監視を使用して、システムがどれだけ単純または複雑であるかを評価できます。
もちろん、多くのメジャーとメトリックは単なる指標であることを理解することが重要です。単純さを高めるためにリファクタリングする必要があるかどうか、またはそうする努力の価値がないかどうかを判断するには、判断を使用する必要があります。測定を行い、メトリックを計算し、コードについて学習することはできますが、数字でシステムを設計したくはありません。最終的には、意味のあることを行います。
シンプルさを定義する正式なモードを見る代わりに、コード作成の品質の属性としてシンプルさを定義したいと思います。
私は単純さを測るのではありませんが、いつあなたは単純な何かを呼ぶのでしょうか。
1.コードトラバーサル:コード内を
簡単に移動できますか?API関数が記述されている場所を見つけるのは簡単ですか?呼び出しフローを理解するのは簡単ですか、たとえば、どのメソッドが他のメソッドを呼び出しているか(およびその理由)-実装されているか、明確に識別されたアルゴリズムがありますか?
コードトラバーサルが簡単な場合、コードは 簡単です。
2.命名
他のコーディング標準はコードの見栄えを良くするのに役立ちますが、最も重要なことはクラス/オブジェクトインスタンス/変数/メソッドの命名です。名前明確かつ明確な使用は、明らかに大きな影響を与えていますシンプルコードのを。単純な名前を特定するのが難しい場合、それはその変数/メソッドであるという考えを再考したいという兆候です。
3.解釈と参考文献
各メソッドには明確な役割がありますか。各変数/属性は、果たしている役割を簡単に判断できますか?コードの一部が仮定を暗示したり、関係のない一連の変数に影響を与える何かを行うと、メンテナンスの悪夢になります。
4.依存関係または結合
これは、コードを見ただけでは判断が困難ですが、誰かがあなたのバグを修正しようとすると非常に明らかになります。他のオブジェクトで他の何かが変更されると、ここでの操作は変更されますか?それらの変更は明らかですか?ものに対応するために頻繁にAPIを変更する必要がありますか。これらは、モジュール間の関係が単純ではないことを示唆しています
5.入力ユーザーまたはアプリケーション
最後に、ユーザー入力またはアプリケーションはAPI / UIでどの程度簡単ですか。複数の可能なユーザー/アプリケーション(異なる目的のため)が必要な場合-それらは明らかですか?高度な抽象化に関連していないが、インターフェースをさかのぼる状態/詳細はありますか?
私が一般的に尋ねる簡単な質問は次のとおりです:プログラムの代わりに、人間が同じ機能を実行するように要求した場合、この情報を紙のフォームに記入しましたか?そうでない場合、私はそうではありませんここで十分に単純で。
このリストがすべてを網羅しているとは言いませんが、私はソフトウェアを使用して変更することがどれほど簡単か難しいかを判断基準としています。それは簡単です。
コードを単純化するための既存の優れたメトリックを認識していません(それらが存在しないことを意味するものではありません-単にそれらについて知らないというだけです)。私はいくつかを提案することができます、おそらくいくつかは助けるでしょう:
使用される言語機能の単純さ:言語に「高度な」および「単純な」と考えられる機能がある場合、高度な機能の出現回数をカウントできます。「高度」をどのように定義するかは、もう少し主観的かもしれません。これは、プログラムの「賢さ」を測定するようなものだと言う人もいるかもしれません。一般的な例:?:
オペレーターが「高度な」機能であるべきだと言う人もいれば、反対する人もいます。これをテストできるツールを書くことがどれほど簡単かはわかりません。
プログラム内の構造の単純さ:関数が受け入れるパラメーターの数を測定できます。> mパラメータを持つすべての関数の> n%がある場合、nとmの定義方法に応じて、単純ではないとカウントすることを選択できます(n = 3とm = 6?)。これを測定できる静的解析ツールがいくつかあると思います-JTestは、m個以上のパラメーターで関数を測定しただけだと思います。
ネストされたループまたは制御構造の数を数えることを試みることができます。これは実際には悪い指標ではないと思いますし、それに名前があると思います(頭の中で思い出すことはできません)。繰り返しますが、これをある程度測定できるツール(JTestなど)があると思います。
「リファクタリング」を測定してみてください。あなたのコードは、コードの断片がたくさん含まれている場合は可能性がリファクタリングが、ことではありませんが、多分それは、できる限り単純ではないだろう。私もJTestで働いていたときからJTestがこれを測定しようとしたことを思い出しますが、このケースではよく同意しなかったので、YMMVです。
システムの異なる部分間のレイヤーの数を測定することを試みることができます。例:データベースに保存される前に、Webフォームからのデータに触れるコードの数はいくつですか?これは適切に測定するのが難しいものかもしれません...
?:
は、それらが5つの深さで入れ子にされるときのようなものが問題であるとだけ言いたいです。レイヤーについては、きれいに分離されたレイヤーは、1つの畳み込みレイヤーよりも優れています。ただし、必要なのが2つまたは3つだけの場合、ほとんど冗長な7つのレイヤーは悪いことです。