関数の適切な最大長として証明されているものは何ですか?[閉まっている]


44

関数の長さはプログラマの生産性に影響しますか?もしそうなら、生産性の損失を避けるための適切な最大行数は何ですか?

これは非常に意見の多いトピックであるため、いくつかのデータを使用してクレームをバックアップしてください。


6
長さはLOCで測定するのではなく、正確に何をするかを理解するのに必要な時間で測定する必要があります。そして、その長さは1分以内でなければなりません。私が数秒でそれを理解できない場合、それはおそらく多すぎます... 1分後に、それは間違いなくそうです。
CaffGeek


13
最大長は17でなければなりません
。– ThomasX

1
SをSOLIDで考えてください。
クリスクラウス

1
@CaffGeekまたは、おそらく関数は単純ではない何かをしているだけかもしれません。完全に理解するには数日かかる関数を見てきました。関連するすべての概念を理解している機能でさえ、詳細を理解するのに30分ほどかかります。些細な機能を持つのは良いことですが、多くの問題は本質的に難しいものです。
CodesInChaos

回答:


46

1970年にこのクレイジーなラケットに乗り出してから、実際には複数の印刷ページ(約60行)が必要なモジュールを1つだけ見ました。もっと長いモジュールを見てきました。

さらに言えば、より長いモジュールを作成しましたが、通常は大きなスイッチステートメントとして作成された大規模な有限状態マシンでした。

問題の一部は、最近のプログラマーが物事をモジュール化することを教えられていないことのようです。

垂直方向のスペースの無駄を最大限にするコーディング標準も問題の一部であるように見えます。(私はまだGerald Weinbergの「コンピュータプログラミングの心理学」を読んだソフトウェアマネージャーに会ったことがありません。プログラマーはスクロールするか、ページをめくる必要があり、理解度が大幅に低下します:覚えて、抽象化する必要があります。)

FORTHによる十分に文書化されたプログラマの生産性向上の多くは、ソースコードのFORTH "ブロック"システムによるものであると確信しています。無限に因数分解できますが、どのような状況でも 17行のルーチンを書くことはできません


3
FORTHの全体の哲学は、これを奨励するために設計されました...あなたは、あなた自身の語彙を設計し、プログラムをどんどん小さな断片に分割し、より少ないスクリプトとより多くの辞書で終わることを意図していました。長さ制限だけではそれができません-何らかのコーディング標準を満たすためだけに、ルーチンが任意の部分に分割されるのがわかります。プログラマーは単に「物事をモジュール化することを教えられていない」と疑うのは絶対に正しいと思います。これ OOPの大きな勝利の1つだったはずですが、さまざまな理由から、それ自体が目標として強調されないことがよくあります。
Shog9

1
@氏。CRT:ブロック指向のFORTH実装の長さ制限は、モジュール化を強制しました。ほとんどのFORTHのインタラクティブな性質は、小さなモジュールを奨励し、それらのモジュールの迅速なテストを行うことで役立ちます。ファイルベースのFORTHであるD85はモジュール化を強制しませんでした。D85で遊んでいる人は、それを使って多くのプログラマー意識の流れを永遠に書くモジュールを見ました。したがって、私の信念。(その価値について、Liz Ratherは私に反対します。主に、FORTHが生産性を向上させるのは対話性だと考えています。)
ジョンR.ストローム

2
+1ですばらしい本「コンピュータープログラミングの心理学」を紹介してくれました:)
サミュエル

30

本当に正しいサイズは何ですか?

使用する言語に依存しますが、一般的に(そして私の個人的な好みのために):

  • 理想的には、25行未満です。
  • 許容範囲内で、35行未満です。

それ以上の場合は、後で戻ってやり直す必要があります。

しかし、現実的には、何かを配達する必要があるときに必要なサイズであり、そのように吐き出す瞬間にもっと理にかなっているので、誰かが出荷前にレビューするのがさらに簡単になります。(ただし、後でそれに戻ります)。

(最近、私のチームはコードベースでプログラムを実行しました。メソッドが197個、メソッドが3個だけのクラスが見つかりましたが、そのうちの1つは600行でした。かわいいゲーム:2つの悪の悪いところは何ですか?)


さて、もっと禅の答えを...概して、1人か2人の偉大な男性を引用するのは良い習慣(TM)と考えられているので、ここに行きます:

すべてをできるだけシンプルにする必要がありますが、シンプルにする必要はありません。- A.アインシュタイン

最終的に完成するのは、追加するものがなくなったときではなく、奪うものがなくなったときです。- A.・ド・サン=テグジュペリ


コメントスタイルに関する補遺

これに対する補遺として、関数には、その意図を説明する明確な名前を付ける必要があります。コメントに関しては、通常、関数内ではコメントしません。

  • コメント「なぜ?」
  • コード「どのように?」

(説明が必要な)各関数の上部にあるコメントブロックで十分です。関数が小さく、関数名が十分に明確な場合は、達成したいこととその理由を言うだけで十分です。インラインコメントは、一部の言語のフィールド、または意図が不明な場合に25〜35行の規則に違反する関数のブロックスタートでのみ使用します。例外的な状況が発生したときに、コード内でブロックコメントを使用します(たとえば、必要のない、または何もしたくないcatchブロックには、理由を示すコメントが必要です)。

詳細については、読んでください私の答えスタイルとコメントコードの勧告を


@haylem私はこれがフレディ対ジェイソンのプログラマー版だと思います:
Gaurav

私は同意しますが、私はそれが1つの画面ページのサイズでなければならないことを追加します。1つの画面ページに72行ある場合、関数は72行を超えてはなりません。
表示名

@スクロールしないように、単一の関数が画面ページでも保持されることを保証する問題がありますが、それは通常私の主な関心事ではありません。私の懸念は、関数を読み取るときに情報を処理するのにかかる時間であり、25行で明確に記述されている場合はほとんど瞬時です。関数呼び出しを追跡するだけの問題になります。72は私には大きすぎるの方法である(あなたがスプリットスクリーンを持っている場合はどのようなプラス、そして、それは、フォントに依存するだろう。しかし、私は勧告の歴史的価値のために同意する?。)
haylem

1
もちろん、70の異なるフィールドを70の異なる場所にコピーするだけの機能がある場合もあります。私は主にttこれらを生成するために使用しますが、時々、とにかく興味のあることは何もしないので、実際の問題ではない長いお尻の機能(または長いお尻の機能)で立ち往生しています。
コンフィギュレー

1
たとえば、関数がMap(x => x.Property1); Map(x => x.Property2); Map(x => x.Property3);すべて同じであることが明らかです。(これは単なる例であり、この種の関数は時々ポップアップすることに注意してください)
configurator

12

私の意見では、すべての機能はできるだけ小さくする必要があります。各関数は1つだけを実行し、適切に実行する必要があります。それは実際には最大長の質問に答えるわけではありませんが、関数の長さについての私の気持ちです。

ボブおじさんの言葉を使うには、「もう抽出できないまで抽出してください。ドロップするまで抽出してください。」


2
可能な限り小さいとはどういう意味ですか?各関数に2行だけを持たせて、できる限り小さくしないのは1行です。1行は1つの操作を実行し、もう1行は関数を呼び出して残りを実行しますか?
ケルミクラ

ボブおじさん。自分のためだと思います。おじさんに耳を傾けないでください。彼らはあなたを迷わせる。
gnasher729

10

建物の最大高さはどのくらいですか?ビルドがどこにあるか、または希望する高さに依存します。
あなたは異なる都市から来る異なる人々から異なる答えを得るかもしれません。
一部のスクリプト関数とカーネル割り込みハンドラーは非常に長いです。


私はあなたに完全に同意します。私は比likeが好きです。:) 3階建ての建物は、有効な安全出口の設置場所がわからない愚かな建築家によって建てられた可能性があり、他の建物は10階建てで完璧な建築設計になります。メソッド自体をサイズ変更するのではなく、サイズを縮小するメソッドをリファクタリングする主な理由は、読みやすさと保守性であることに常に留意してください。サイエンスフィクション映画を除き、90%の超高層ビルで都市を建設することはできませんでした。:)
サミュエル

10

私にとって有効な方法は次のとおりです。より長い関数の一部に意味のある名前を付けることができますか。メソッドの長さは、適切なネーミングのようにそれほど重要ではないと思います。このメソッドは、名前が示すとおり、それ以上でもそれ以下でもありません。そして、あなたは良い名前を付けることができるはずです。メソッドに適切な名前を付けられない場合、コードはおそらく適切にまとめられていません。


そして、あなたのメソッドは良い名前を持つためにただ一つのことをすべきです... 'And'、 'Or'、またはメソッド名を50文字にする他のものはありません。
サミュエル

10

必要なことを実行する必要がある限り、もはや必要ありません。


cで言うように、「cには別のポインターをそのポインターに追加しても解決できないという問題はありません。」その下に別の機能をいつでも追加できます。彼の質問は、「どこで終わりますか?」
表示名

1
私は実際にそれをひっくり返して、「必要なだけ短く、短くはない」と言いますが、十分に近いために私の+1を得ることができます:)
ベンヒューズ

6

トレードオフがあると思います。短いメソッドが多数ある場合、1つの長いメソッドよりもデバッグするのが難しいことがよくあります。1回のメソッド呼び出しをトレースするためにエディターを20回または30回ジャンプする必要がある場合、すべてを頭の中に保持するのは困難です。一方、明確に書かれた明確な方法が1つあれば、たとえ100行であっても、頭の中に留めておいた方が簡単です。

本当の問題は、アイテムを異なる方法にする必要がある理由であり、上記の答えはコードの再利用です。コードを再利用していない(または知らない)場合は、1つの巨大な簡単な方法でそのままにしておくことは理にかなっています。再利用する必要がある場合は、再利用が必要な部分を分割します。より小さなメソッドに使用します。

実際には、優れたメソッド設計の一部は、機能的に凝集したメソッドを作成することです(本質的に1つのことを行います)。メソッドの長さは関係ありません。関数が1つの明確に定義された処理を実行し、1,000行である場合、それは良い方法です。関数が3つまたは4つのことを行い、15行しかない場合、それは悪い方法です...


私は短い方法が好きです。
マーシー

メソッドが10行を超えてはならないというのは、私の見解ではユートピアだからです。OKメソッドが長すぎるため、詳細を説明するコメントがいっぱいではありません。メソッドには100行のコードが含まれている可能性があり、理解して保守するには完全にクリーンである可能性があります。しかし、それは習慣というよりも例外であるべきです。ファクトリーメソッドのスイッチケースは例外の良い例だと思います。
サミュエル

5

関数全体を一度に見ることができれば、自分がやっていることを追跡するのが簡単になります。だから私は関数を書くことを好む方法です:

  1. 適切なフォントでモニターに収まるほど短い。
  2. #1より長くする必要がある場合は、妥当なフォントで紙に印刷するのに十分な短さです。
  3. #2よりも長くする必要がある場合は、2枚の紙に1枚印刷するのに十分な短さです。

それより長い関数を書くことはめったにありません。それらのほとんどは、巨大なC / C ++ switchステートメントです。


モニターに収まるほど短いのはいいですが、フォントの種類とサイズを指定します。私たちの見解では、紙は私のルールではないはずです。私たちは2013年であり、まだコードを紙に印刷しているのです。Visual Studio、intellisenseなどのツールを使用すると、コードを紙で分析する必要がなくなります。
サミュエル

5

私にとって、関数は必要な長さです。私がそれを分割するほとんどの時間は、コードを再利用するときです。

基本的に、主要な「高凝集、低結合」に固執し、長さに制約はありません。


5

問題は、関数が何をする必要があるかです。そして通常、「1」のことをするために100行が必要になることはまれです。繰り返しますが、それはあなたがコードを見ているレベルに依存します:パスワードをハッシュすることは一つのことですか?または、パスワードをハッシュして保存することは一つのことですか?

1つの機能としてパスワードの保存から始めましょう。ハッシュが異なると感じ、コードをリファクタリングするとき。私は決して熟練したプログラマーではありませんが、私見では、関数の全体的なアイデアは小さく始まります。など

1000行を超えるSQL ストアドプロシージャを見てきました。ストアドプロシージャの行数も50未満ですか?わかりませんが、コードを読むのは大変です。上下にスクロールし続ける必要があるだけでなく、数行のコードに「this does validation1」、「this updates in the database」などの名前を付ける必要があります。これはプログラマが行うべき作業です。


+1は最初の段落のみ。その他はすべて、作業中のケースに関連しています。
表示名

そして、それを50個の関数に分割するとどうなりますか?関数が通信する必要がある場合、500行ではなく1000行で終了しますか?
gnasher729

5

以下からの循環的複雑度(ウィキペディア):

ソースコードのセクションの循環的な複雑さは、ソースコードを通る直線的に独立したパスの数です。

  • 1つの方法でその数を10未満に抑えることをお勧めします。10に達したら、リファクタリングの時間です。

  • コードを評価し、循環的複雑度を示すことができるツールがあります。

  • これらのツールをビルドパイプラインに統合するよう努力する必要があります。

  • 文字通りメソッドのサイズを追いかけるのではなく、その複雑さと責任に注目してください。複数の責任がある場合は、リファクタリングすることをお勧めします。その循環的な複雑さが増すと、おそらくリファクタリングの時間です。

  • 同様のフィードバックを提供するツールは他にもあると確信していますが、まだこれを調べる機会はありませんでした。


大規模な公開リポジトリの1つからの実際のコードでは、不自然な例ではなく循環的な複雑さが、生のSLOCと非常に強く相関していることが示されています。これにより、キャリッジリターンのカウントがはるかに簡単になるため、基本的に価値がなくなります。(はい、SLOCをプレイすることは可能です。正直に言うと、雇用主でSLOCメトリックスをプレイしていた誰かが給料を引き続けることができる期間はどれくらいですか?)
ジョンR.ストローム

4

通常、メソッド/機能を1680x1050モニターの画面に適合するものに維持しようとしています。収まらない場合は、ヘルパーメソッド/関数を使用してタスクを分割します。

画面と紙の両方で読みやすくします。


同じことをしますが、使用しているフォントの種類とサイズを指定する価値があります。私にとっては、スコット・ハンセルマンが提案したサイズが14の「コンソラ」が好きです。hanselman.com/blog/…非常に大きなフォントを使用するのは初めてですが、メソッドをできるだけ小さくすることを常に覚えておくのがベストプラクティスです。
サミュエル

4

一部の関数は本質的に複雑なアルゴリズムを実装しており、それらを短くしようとすると、新しい短い関数間の相互作用が非常に複雑になるため、最終的な結果は単純さを低下させないため、私は何にも強い制限を設けません。また、関数は「1つのこと」だけを行うべきだという考えは良いガイドではないと思います。なぜなら、高レベルの抽象化における「1つのこと」は、より低いレベルでは「多くのこと」になるからです。

私にとって、関数の長さがDRYのわずかな違反を引き起こしている場合、関数は間違いなく長すぎます。関数の一部を新しい関数またはクラスに抽出すると、これを解決できます。これが当てはまらない場合、関数は長すぎるかもしれませんが、将来の予測可能な変更に直面する可能性が高い方法でコードをよりモジュール化する関数またはクラスを簡単に抽出できます。


関数は特定の抽象化レベルで「1つのこと」を行いますが、心配するのはその1つの抽象化レベルだけです。それが全体のポイントです。あなたがそれを理解できないなら、抽象化を理解しているとは思わない。
ゾランパブロビッチ

4

正しく最適化できるほど短い

メソッドは、1つだけを実行できるように短くする必要があります。この理由は簡単です。コードを適切に最適化できます。

JavaやC#のようなJIT化言語では、JITコンパイラーがコードを迅速に生成できるように、メソッドが単純であることが重要です。より長く、より複雑なメソッドは当然、より多くのJIT時間を必要とします。また、JITコンパイラーはほんの一握りの最適化のみを提供し、最も単純なメソッドのみがこの恩恵を受けます。この事実は、ビルワーグナーのEffective C#でも言及されていました。

CやC ++などの低レベル言語では、短いメソッド(数十行程度)を持つことも重要です。これにより、ローカル変数をレジスタではなくRAMに格納する必要性を最小限に抑えることができます。(別名「流出の登録」)。ただし、この管理されていない場合、各関数呼び出しの相対コストはかなり高くなる可能性があることに注意してください。

また、RubyやPythonなどの動的言語でも、短いメソッドを使用すると、コンパイラーの最適化にも役立ちます。動的言語では、機能が「動的」であるほど、最適化が難しくなります。たとえば、Xを受け取り、Int、Float、またはStringを返す可能性のある長いメソッドは、それぞれが単一の型のみを返す3つの個別のメソッドよりもはるかに遅いパフォーマンスを発揮します。これは、コンパイラが関数が返す型を正確に知っている場合、関数呼び出しサイトも最適化できるためです。(たとえば、型変換をチェックしない。)


アプリケーションの約99.999%には、データベースアクセス、ファイルアクセス、ネットワーク遅延など、プログラムの速度を低下させるものがはるかに多くあります。メソッドの設計中に速度を考慮することは、ゲーム、リアルタイムアプリケーション、または大量のデータを使用したレポートの正当な理由になる可能性がありますが、他の場合はそうではありません。ただし、それは良い点ですが、プログラマーほど小さいので、アプリケーションでこのタイプの最適化を行う必要はほとんどありません。
サミュエル

コードの速度を測定し、何をしているのかがわかっている場合(思ったほど簡単ではない)、コードを遅く測定し、後で測定して速度が向上した場合、そのようなことをします。
gnasher729

3

コードの内容に大きく依存します。

私は何の問題もない千行のルーチンを見てきました。それは巨大なswitchステートメントであり、12行を超えるオプションはなく、オプションの制御構造は単一ループのみでした。最近ではオブジェクトを使って書かれていましたが、それは当時のオプションではありませんでした。

また、目の前のスイッチで120行を見ています。ガード、割り当て、ブレークの3行を超えるケースはありません。テキストファイルを解析しているため、オブジェクトは存在しません。代替手段は読みにくいでしょう。


2

ほとんどのコンパイラーは、関数の長さを気にしません。機能は機能的である必要がありますが、人間にとって理解、変更、再利用が容易でなければなりません。最適な長さを選択してください。


1

私の一般的なルールは、関数が画面に収まるようにすることです。これに違反する傾向があることがわかったのは、3つのケースのみです。

1)関数をディスパッチします。昔はこれらは一般的でしたが、最近ではそれらのほとんどがオブジェクトの継承に置き換えられています。ただし、オブジェクトはプログラム内でのみ機能するため、他の場所から到着するデータを処理するときに、時折ディスパッチ機能が表示されます。

2)目標を達成するために一連のステップを実行する機能、およびステップに適切な細分化が欠けている場合。単純に他の関数の長いリストを順番に呼び出す関数になります。

3)#2と似ていますが、個々のステップが非常に小さいため、個別に呼び出されるのではなく、単にインライン化されます。


1

たぶん、関数の長さはそれほど良いメトリックではありません。メソッドでも循環的複雑度を使用しようとします。また、クラスおよびメソッド上の循環的複雑度はXより低くなければならないという将来のソース管理チェックイン規則の1つです。

メソッドの場合、Xは30に設定されますが、これは非常に厳密です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.