私は少し議論を交わし、そこにいる人々がどう思うか疑問に思っていました:
C++ (または一般的に) では、コードを多くの短い関数に分割し、 main() を論理的な順序で関数のリストだけで構成することを好みますか、それとも必要な場合 (つまり、何度も再利用できますか)? それともその間の何か?
私は少し議論を交わし、そこにいる人々がどう思うか疑問に思っていました:
C++ (または一般的に) では、コードを多くの短い関数に分割し、 main() を論理的な順序で関数のリストだけで構成することを好みますか、それとも必要な場合 (つまり、何度も再利用できますか)? それともその間の何か?
機能は小さいほど良いというのが常識であり、その通りだと思います。実際に、単体テストの数と比較した決定の数によって個々の機能を評価する分析ツールを使用している会社があります。
理論的には、アプリケーション全体の複雑さを軽減できる場合とできない場合がありますが、特定の関数の複雑さを完全に制御できます。
循環的複雑度と呼ばれる測定値は、悪いコードと正の相関があると考えられています...具体的には、メソッドを通るパスが多いほど、その CCN 番号が高くなり、記述が不十分であるほど、理解が難しくなり、変更や変更が難しくなります。より多くの単体テストが必要になります。
わかりました、ツールを見つけました。それは、ええと、変更リスク分析および予測指標と呼ばれます。
最近、情報を一度だけエンコードするという原則は、新しい頭字語、特にDRY (Don't Repeat Yourself) やDIE (Duplication is Evil)を成長させました... この哲学を推進してくれたRoRコミュニティに部分的に感謝できると思います...
機能を分割しますが、機能を分割しないでください。
機能はレイヤーに分類される場合があり、各レイヤーは異なる機能に分割される場合があります。たとえば、サイン シリーズを処理している場合、加算と減算のメイン ループはプライマリ関数にある必要があります。これはレイヤ 1 と見なすことができます。電力を検出する機能はレイヤ 2 に分類できます。これはサブ機能として実装できます。同様に、階乗を見つけることも、別のサブ機能であるレイヤー2に属します。常に機能を考慮し、行数を数えないでください。行数は 3 から 300 までさまざまですが、問題ありません。これにより、コードの可読性と保守性が向上します。これが分割についての私の考えです。
唯一の答えはその中間だと思います。可能な限り関数を分割すると、読めなくなります。同様に、決して別れなければ、それも読めなくなります。
私は関数をセマンティックの違いにグループ化するのが好きです。これは、何らかの計算のための 1 つの論理単位です。ユニットを小さく保ちますが、実際に何か役に立つことを行うのに十分な大きさにします。
関数の粒度に関する私のお気に入りの経験則は、「それぞれが 80 文字未満の行を 24 行以下にする」ことです。これは、少なくとも C や C ほど豊富ではない言語では、「ひと目で把握」できる関数の合理的なガイドラインだと思います。 「役割」または「目的」としての「機能」の意味!-) は、「多すぎる機能」が 24 行に簡単に詰め込まれる言語で使用する二次的な規則です。しかし、「レキシカル アイフル」ガイドライン -- 24 x 80 -- は、今でも私のメイン ガイドラインです。
小さい関数は良いものであり、小さい関数は小さいほど優れています。
約 5 ~ 8 行のコードが関数サイズの上限です。それを超えて、それはあまりにも複雑です。次のことができるはずです。
もう 1 つは、コードを記述する前に関数を使用する必要があることです。関数をどのように使用するつもりかがわかると、その関数が尊重しなければならない事前条件と事後条件がわかります。
一見して明らかに正しくないものは、実行中の解説で正しいことが証明されるはずです。それが難しい場合は、サブ機能を除外します。
コードの再利用と可読性に役立つものは何でも最適に機能すると私は信じています。
それを行うためだけに多くの 1 行の関数を作成しても読みやすさが向上しないため、意味のあるクラスにグループ化し、関数を分割して、その関数で何が起こっているかをすばやく理解できるようにする必要があります。
何が起こっているのかを理解するためにあちこち飛び回らなければならない場合、その設計には欠陥があります。
私は関数 (またはメソッド) が 1 画面分のコードに収まるようにすることを好みます。そのため、その関数がどのように機能するかを理解するために参照する必要があるものはすべて一目でわかります。通常、エディター ウィンドウには約 50 行のスペースがあり、通常は 80 列もあるため、モニターに 2 つ並べて表示し、2 つのコード間の相互参照を行うことができます。
したがって、私は一般的に 50 行が最大であると考えています。私がもっと許可することを検討するのは、1 つの大きな長い初期化関数または完全に線形 (変数、条件、またはループがない) のものがある場合だけです。起動して実行するための一連の初期化と、それを小さな関数に分割しても、あまり役に立ちません。
とはいえ、全体としては、1 つのことを行い、適切な名前が付けられた、素晴らしく小さくて理解しやすい関数は、数百行の長さと 10 レベルの深さのインデントで追跡する数十の変数を追跡する、巨大で無秩序に広がった怪物よりもはるかに好ましいものです。
もう 1 つの単純な理由: コードのブロックが 1 回または 2 回以上再利用されている場合は、関数を作成する必要があります。非常に小さなコード (1 つまたは 2 つのステートメントなど) の場合、マクロを使用すると問題が軽減されることがよくあります。