コードでシンプルさを定義および測定するにはどうすればよいですか?


13

読みやすさに関するシンプルさに関する以前の質問には、コードのシンプルさの定義と理解が間違っている可能性が非常に高いことがわかりました。

コードでシンプルさを定義するにはどうすればよいですか?コードのシンプルさを測定するために、どのソフトウェア測定およびメトリックが利用可能ですか?


2
@MarkTrapp経験的なソフトウェアエンジニアリングのトピックなしでコードの単純さを議論する他の方法があります。たとえば、自動化されたテストを記述する機能の観点から単純さを議論します。私のスキルと知識があれば、経験的なソフトウェアエンジニアの観点からこの質問に答えることができますが、他の人は別の観点から答えることができます。そのステートメントを質問に追加すると、有用な回答の数が大幅に制限され、ローカライズされた(IMO)になります。追加したい場合は可能ですが、これは良い質問です。
トーマスオーエンズ

2
@ThomasOwens 実際の質問には、アイデアや意見ではなく答えがあります。誰もが同じ方法で質問に答える方法を解釈するように範囲を絞り込むことは、まさにStack Exchangeの目的です。問題を解決する方法は複数あるかもしれませんが、明確に述べられている問題は1つだけです。

現在の状態では、この質問に対する答えはほとんどありません(私の答えは経験的なソフトウェアエンジニアリングの観点に関するものであり、共通の測定基準があります-おそらく他にもあります)。他の観点から有効な選択肢を提供する回答を除外することは意味がありません。これがこの質問の言い回しです。私はこれらの編集に完全に同意せず、質問を元の形式に戻す必要があります。
トーマスオーエンズ

@MarkTrapp問題は明確です。コードの単純さを判断するにはどうすればよいですか?いくつかの良い答えがあります。私は、経験的なソフトウェアエンジニアリング手法を使用して複雑さを測定しています。別の方法として、自動化されたテストを作成することもできます。適切なテストを作成することが困難な場合、コードは複雑になります-完全に有効な答えです。私が知らない他の人がいるかもしれません。コードベースの複雑さ/シンプルさを測定する必要がある場合、質問者は特定のケースに最適なソリューションを選択できるように、すべての選択肢を提示できるように質問を表現する必要があります。
トーマスオーエンズ

回答:


16

複雑さを測定するための最も一般的なメトリック(または単純さを複雑さの反対にすれば単純さ)は、McCabeのCyclomatic ComplexityおよびHalstead Complexity Metricsです。

循環的複雑度は、特定のユニット(通常はメソッドまたは関数)を通る個別のパスの数を測定しますが、クラスで計算することもできます。パスの数が増えると、所定のモジュールを通るデータの流れを覚えることが難しくなります。これは、作業メモリの概念に関連しています。高度な循環的複雑度は、モジュールをテストする能力の難しさを示す傾向があります-システムを通るさまざまなパスをカバーするには、より多くのテストケースが必要です。また、高い循環的複雑度を高い欠陥率に関連付けた研究もあります。通常、循環的複雑度10は、ユニットをレビューし、場合によってはリファクタリングする必要があることを示します。

Halsteadの複雑さの測定では、合計および個別の演算子とオペランドの入力を使用して、コードの量、難易度、および労力を計算します。(一意の演算子の数/ 2)*(オペランドの総数/一意のオペランドの数)である難易度は、システムの学習やコードレビューの実行などのタスクのコードを読み取って理解する能力に関連しています。この場合も、システムレベル、クラスレベル、またはメソッド/関数レベルでこれをカウントできます。ここここでこれらの測定値を計算することに関するいくつかの投稿があります

コードの行を数えるだけでも、複雑さを知ることができます。コードの行が増えるということは、モジュール内で読み、理解する必要のある行が増えることを意味します。これをスタンドアロンの測定として使用することをためらいます。代わりに、特定のモジュール内の欠陥の数など、他の測定で使用して欠陥密度を取得します。欠陥密度が高い場合、テストの作成とコードレビューの実行に問題があることを示している可能性があります。これは、複雑なコードが原因である場合とそうでない場合があります。

ファンインとファンアウトは、データの流れに関連する2つの他のメトリックです。ここで定義されているように、ファンインは呼び出されたプロシージャの合計、パラメータの読み取り、グローバル変数の読み取り、ファンアウトは特定のプロシージャを呼び出すプロシージャの合計、書き込まれたパラメータ(外部ユーザーに公開され、参照によって渡されます)、およびグローバル変数に書き込まれます。繰り返しますが、ファンインとファンアウトが大きいということは、モジュールが理解しにくいことを示している場合があります。

特定のパラダイムでは、他にも有用な測定値またはメトリックが存在する場合があります。たとえば、オブジェクト指向の世界では、カップリング(低い方が望ましい)、凝集度(高い方が望ましい)、および継承の深さ(低い方が望ましい)の監視を使用して、システムがどれだけ単純または複雑であるかを評価できます。

もちろん、多くのメジャーとメトリックは単なる指標であることを理解することが重要です。単純さを高めるためにリファクタリングする必要があるかどうか、またはそうする努力の価値がないかどうかを判断するには、判断を使用する必要があります。測定を行い、メトリックを計算し、コードについて学習することはできますが、数字でシステムを設計したくはありません。最終的には、意味のあることを行います。


5
あなたがそれを言及したことは知っていますが、循環的複雑性は実際には関数/メソッドレベルでのみ有用であり、より高いレベルでは著しく主観的/役に立たないことを強調することが重要です。
リャタール

問題は、これらの対策が一般的なガイドであるということです。「悪い」プログラムのスコアが高いケースがいくつかあります。たとえば、2つ以上のパラメーターを持つ1つの関数で十分な関数が12個ある場合や、逆に複雑な問題に対する適切に書かれたソリューションである「良い」プログラムの多くがスコアリングできる場合がありますひどく。
ジェームスアンダーソン

@James私はそれを明示的に指摘しました。測定または測定基準は、何かを見なければならないことを示す指標として状況に応じて取得する必要があります。修正アクションが必要かどうか、およびそのアクションが何であるかを判断するには、エンジニアの判断が必要です。ただし、積極的にデータを収集していない限り、潜在的な問題について経験的に知る方法はありません。
トーマスオーエンズ

7

シンプルさを定義する正式なモードを見る代わりに、コード作成の品質の属性としてシンプルさを定義したいと思います。

私は単純さを測るのではありませんが、いつあなたは単純な何かを呼ぶのでしょうか。

1.コードトラバーサル:コード内を
簡単に移動できますか?API関数が記述されている場所を見つけるのは簡単ですか?呼び出しフローを理解するのは簡単ですか、たとえば、どのメソッドが他のメソッドを呼び出しているか(およびその理由)-実装されているか、明確に識別されたアルゴリズムがありますか?

コードトラバーサルが簡単な場合、コードは 簡単です。

2.命名
他のコーディング標準はコードの見栄えを良くするのに役立ちますが、最も重要なことはクラス/オブジェクトインスタンス/変数/メソッドの命名です。名前明確かつ明確な使用は、明らかに大きな影響を与えていますシンプルコードのを。単純な名前を特定するのが難しい場合、それはその変数/メソッドであるという考えを再考したいという兆候です。

3.解釈と参考文献
各メソッドには明確な役割がありますか。各変数/属性は、果たしている役割を簡単に判断できますか?コードの一部が仮定を暗示したり、関係のない一連の変数に影響を与える何かを行うと、メンテナンスの悪夢になります。

4.依存関係または結合
これは、コードを見ただけでは判断が困難ですが、誰かがあなたのバグを修正しようとすると非常に明らかになります。他のオブジェクトで他の何かが変更されると、ここでの操作は変更されますか?それらの変更は明らかですか?ものに対応するために頻繁にAPIを変更する必要がありますか。これらは、モジュール間の関係が単純ではないことを示唆しています

5.入力ユーザーまたはアプリケーション
最後に、ユーザー入力またはアプリケーションはAPI / UIでどの程度簡単ですか。複数の可能なユーザー/アプリケーション(異なる目的のため)が必要な場合-それらは明らかですか?高度な抽象化に関連していないが、インターフェースをさかのぼる状態/詳細はありますか?

私が一般的に尋ねる簡単な質問は次のとおりです:プログラムの代わりに、人間が同じ機能を実行するように要求した場合、この情報を紙のフォームに記入しましたか?そうでない場合、私はそうではありませんここで十分に単純で

このリストがすべてを網羅しているとは言いませんが、私はソフトウェアを使用して変更することがどれほど簡単か難しいかを判断基準としています。それは簡単です。


1
彼は測定値と測定値を求めました。これらは主観的なものであるため、あまり重要ではないと思います。
PSR

@psr同意します。また、トーマスの答えからの答えからも明らかでした。しかし、彼は読みやすさに関連するシンプルさについて言及しました。トーマスの答えは循環的複雑さを扱っています-これはコードをテストするのがどれだけ複雑かを示しており、コードが読みやすさの面でどれだけ複雑で保守性を拡張できるかを示してます。これらは非常に異なる2つの概念です。まさに矛盾を置くためにこの答えを書いたのはまさにそのためです。残念ながら、読みやすさの点でコードの単純さを示すメトリックはありません。
ディパンメタ

「誤解されることのない名前を使用してください」 -私見これは、非現実的で不可能な目標を目指して、あまりにも高く目指しています。あまり明確にしようとせず、単に「明確で明確な名前を使用する」と言いたいと思います。
ペテルトレック

@PéterTörök同意します。多くの組織では、通常、命名規則の非常に明確に定義されたルールと、特定の変数の意図に関する多少の混乱が続いていると思います。そのため、目的明確にすることは、正式な規則とは対照的に単純であることを強調することでした。私は私が説明した方法で行き過ぎたかもしれません。ありがとう。
ディパンメータ

@Dipan Cyclomaticの複雑さは、作業メモリを介したコードの可読性に関連しています。サイクロマティックの複雑度が高い(または単にブロックの深さが高い)コードを作業メモリに保持することは困難であるため、まっすぐに読むことはより困難です。
トーマスオーエンズ

0

コードを単純化するための既存の優れたメトリックを認識していません(それらが存在しないことを意味するものではありません-単にそれらについて知らないというだけです)。私はいくつかを提案することができます、おそらくいくつかは助けるでしょう:

  • 使用される言語機能の単純さ:言語に「高度な」および「単純な」と考えられる機能がある場合、高度な機能の出現回数をカウントできます。「高度」をどのように定義するかは、もう少し主観的かもしれません。これは、プログラムの「賢さ」を測定するようなものだと言う人もいるかもしれません。一般的な例:?:オペレーターが「高度な」機能であるべきだと言う人もいれば、反対する人もいます。これをテストできるツールを書くことがどれほど簡単かはわかりません。

  • プログラム内の構造の単純さ:関数が受け入れるパラメーターの数を測定できます。> mパラメータを持つすべての関数の> n%がある場合、nmの定義方法に応じて、単純ではないとカウントすることを選択できます(n = 3とm = 6?)。これを測定できる静的解析ツールがいくつかあると思います-JTestは、m個以上のパラメーターで関数を測定しただけだと思います。

  • ネストされたループまたは制御構造の数を数えることを試みることができます。これは実際には悪い指標ではないと思いますし、それに名前があると思います(頭の中で思い出すことはできません)。繰り返しますが、これをある程度測定できるツール(JTestなど)があると思います。

  • 「リファクタリング」を測定してみてください。あなたのコードは、コードの断片がたくさん含まれている場合は可能性がリファクタリングが、ことではありませんが、多分それは、できる限り単純ではないだろう。私もJTestで働いていたときからJTestがこれを測定しようとしたことを思い出しますが、このケースではよく同意しなかったので、YMMVです。

  • システムの異なる部分間のレイヤーの数を測定することを試みることができます。例:データベースに保存される前に、Webフォームからのデータに触れるコードの数はいくつですか?これは適切に測定するのが難しいものかもしれません...


2
#3はブロック深度と呼ばれます。決定的な制御構造が関与している場合、それは循環的複雑性にも関連しています。
トーマスオーエンズ

ダウン投票の説明はありませんか?
FrustratedWithFormsDesigner

「言語機能のシンプルさ」に同意できません。 コードを簡素化するための高度な機能があります。シンプルで基本的な機能のみを使用すると、コードが実際に実行していることをわかりにくくし、抽象化レイヤーのリークを避けることができません。高度な言語機能により、より高いレベルの抽象化を表現できるため、コードの密度が高まり、読みやすくなります。使用している高度な機能(もちろん、賢明な)は、単純さのためにより優れています。たとえば、Matlab(実際には「高度な」)のコードを、基本機能のみで作成された同様のFortranコードと比較するだけです。
SKロジック

また、多くのレイヤーメトリックにも同意しません。数十の簡単できれいなステップで、または1つのねじれた変換で何かを行うことができる場合は、いくつかのステップでそれを行う方がよいでしょう。多くのシンプルで明確に分離されたレイヤーは、単一のツイストレイヤーよりもはるかに優れています(そしてシンプルです)。
SKロジック

@ SK-logic:私はその1つを「賢さ」と呼ぶべきだったと思う、それは私が意図したものにより近い。私?:は、それらが5つの深さで入れ子にされるときのようなものが問題であるとだけ言いたいです。レイヤーについては、きれいに分離されたレイヤーは、1つの畳み込みレイヤーよりも優れています。ただし、必要なのが2つまたは3つだけの場合、ほとんど冗長な7つのレイヤーは悪いことです。
FrustratedWithFormsDesigner
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.