もちろん、オブジェクト指向プログラミングでは、メソッドの最大長に厳密な規則はありませんが、これらの2つの引用符は互いに相反しているので、あなたの考えを聞きたいと思います。
Clean Code:A Handbook of Agile Software Craftsmanship で、Robert Martinは次のように述べています。
関数の最初のルールは、それらが小さいことです。関数の2番目のルールは、それらがそれよりも小さいことです。関数は100行の長さにしないでください。関数が20行になることはほとんどありません。
そして彼はJava彼がケントベックから見るコードからの例を与えます:
彼のプログラムのすべての関数は、2、3、または4行でした。それぞれが透過的に明白でした。それぞれが物語を語った。そして、それぞれがあなたを説得力のある順番で次へと導きました。それはあなたの機能がどれだけ短いべきかです!
これは素晴らしいように聞こえますが、一方で、 Code Complete では、Steve McConnellは非常に異なる何かを言います:
ルーチンは100から200行まで有機的に成長することを許可されるべきであり、数十年の証拠によれば、そのような長さのルーチンは、より短いルーチンよりもエラーを起こしにくいということです。
そして彼は、ルーティンが65行以上の方が開発コストが安いと言う研究に言及しています。
それでは、この問題については意見が分かれていますが、機能的なベストプラクティスはありますか?
関数は通常短くする必要があります。JavaまたはC#でコーディングする場合、5〜15行は私の個人的な「経験則」です。これはいくつかの理由で適切なサイズです。
ただし、絶対的なルールを設定することは、ルールから逸脱するための有効な例外/理由が常に存在するため、役に立ちません。
したがって、基本的には、常識を使用、ほとんどの場合小さな関数サイズに固執しますが、あなたがそれについて独断的ではありません異常に大きな機能を実行する真の理由があります。
正しいLOC番号についてハードルールはないと言ったときの私は他のコメントに同意しますが、過去に調べたプロジェクトを振り返って、上記のすべての関数を特定するとしたら、150行のコードがあるとしましょう。これらの関数のうち10個のうち9個がSRPを壊し(そしてOCPの可能性が非常に高い)、ローカル変数が多すぎ、制御フローが多すぎて、一般に読み取りや保守が難しいというコンセンサスになると思います。
したがって、LOCは不良コードの直接的な指標ではないかもしれませんが、特定の関数をより適切に記述できる可能性があることは、まともな間接的な指標です。
私のチームでは、私はリードのポジションに落ちました、そして、どんな理由であれ、人々は私に耳を傾けているようです。私が一般的に解決したのは、絶対的な制限はありませんが、50行以上のコードを追加した関数は、少なくともコードレビュー中に赤信号を発生させる必要があることをチームに伝え、再検討して再評価することです。複雑さとSRP/OCP違反のため。その再検討の後、私たちはそれをそのままにするか、それを変更するかもしれませんが、少なくとも人々はこれらのことについて考えさせます。
コーディングのガイドラインをまったく気にしていないプロジェクトに参加しました。コードを調べると、コードが6000行を超え、メソッドが10未満のクラスが見つかることがあります。これは、バグを修正する必要がある場合の恐ろしいシナリオです。
メソッドの最大サイズを決定する一般的なルールは、あまり良くない場合があります。私はロバートC.マーティン(ボブおじ)のルールが好きです:「メソッドは小さく、小さくより小さい」。私はいつもこのルールを使うようにしています。私のメソッドは1つのことだけを行い、それ以外のことは何もしないことを明確にすることで、メソッドをシンプルかつ小さく保つようにしています。
回線数ではなく、SRPについてです。この原則によれば、メソッドは1つだけ実行する必要があります。
あなたのメソッドがこれとこれとこれを行う場合OR that =>それはおそらく多くのことをしているでしょう。 「必要です」、「ここでこれらの要素を処理する」、「結果を取得するために最終的にこれらを組み合わせる」これらの「ブロック」は、他のメソッドにリファクタリングする必要があります。
あなたが単にSRPに従うならば、あなたの方法のほとんどは小さく、明確な意図があります。
「このメソッドは20行を超えるので間違っている」と言っても正しくありません。 表示何かかもしれないこの方法では間違っている可能性があります。
メソッドに400回線のスイッチがある場合があり(多くの場合テレコムで発生します)、それは単一の責任であり、完全に問題ありません。
状況によります、真剣に、あなたが扱っている言語が問題であり、5行目から15行目が言及されているため、この質問に対する確かな答えはありません- この回答では はC#またはJavaで動作する可能性がありますが、他の言語では動作するほど多くはありません。同様に、作業しているドメインによっては、大きなデータ構造でコード設定値を記述していることがあります。一部のデータ構造では、設定する必要がある要素が数十ある場合があります。関数が長く実行されているという理由だけで、別の関数に分割する必要がありますか?
他の人が指摘したように、最良の経験則は、関数は単一のタスクを処理する単一の論理エンティティであるべきであるということです。関数をn行より長くすることはできないという厳格なルールを適用しようとし、その値を小さすぎると、開発者が試して使用するときにコードが読みにくくなりますルールを回避するための凝ったトリック。同様に、高すぎる値を設定すると問題にならず、怠惰であるにも関わらず悪いコードにつながる可能性があります。あなたの最善の策は、コードレビューを実施して、関数が単一のタスクを処理していることを確認し、そのままにしておくことです。
ここでの1つの問題は、関数の長さがその複雑さについて何も言わないことです。 LOC(コード行)は、何かを測定するには不適切な手段です。
メソッドは過度に複雑であってはなりませんが、長いメソッドを簡単に保守できるシナリオがあります。次の例では、メソッドに分割できなかったわけではなく、メソッドによって保守性が変更されないことに注意してください。
たとえば、着信データのハンドラーには、大きなswitchステートメントと、ケースごとの単純なコードを含めることができます。私はそのようなコードを持っています-フィードからの着信データを管理します。 70(!)数値的にコード化されたハンドラ。ここで、「定数を使用する」と言います-はい、ただしAPIは定数を提供せず、ここでは「ソース」の近くに留まるようにします。メソッド?確かに-残念なことに、それらすべてが同じ2つの巨大な構造のデータを処理しています。より多くのメソッド(読みやすさ)がある場合を除いて、それらを分割してもメリットはありません。コードは本質的に複雑ではありません-フィールドに応じて1つのスイッチ。次に、すべてのケースに、データのx要素を解析して公開するブロックがあります。メンテナンスの悪夢はありません。フィールドがデータを持っているかどうかを決定する条件が1つ繰り返されます(pField = pFields [x]、pField-> IsSet(){blabla}の場合)-すべてのフィールドでほぼ同じです...
入れ子のループと多くの実際の切り替えステートメントを含むはるかに小さなルーチンでそれを置き換えます。巨大なメソッドは、1つの小さなルーチンよりも保守が簡単です。
そのため、申し訳ありませんが、LOCは最初から適切な測定方法ではありません。どちらかと言えば、複雑性/決定ポイントを使用する必要があります。
さらにもう1つ引用します。
プログラムは、人々が読むために、そして偶然にマシンが実行するためにのみ書かれなければならない
-ハロルド・アベルソン
100から200に成長する関数がこのルールに従うことはほとんどありません
私は1970年以来、このクレイジーなラケットに何らかの形で参加しています。
その間、私がすぐに得る2つの例外を除いて、私は1つ以上の印刷されたページである必要がある(ルーチン、メソッド、プロシージャ、関数、サブルーチンなど)うまく設計された約60行)。それらの大部分は、10から20行程度のかなり短いものでした。
しかし、モジュール化について聞いたことがないように思われる人々によって書かれた「意識の流れ」のコードをたくさん見ました。
2つの例外は非常に特殊なケースでした。 1つは実際には例外ケースのクラスであり、私はそれらをひとまとめにします。大きな有限状態オートマトンは、大きな醜いスイッチステートメントとして実装されます。これらは通常、自動テスト装置に表示され、テスト中のデバイスからのデータログを解析します。
もう1つは、CDC 6600 FORTRAN IVで書かれた、Matuszek-Reynolds-McGehearty-Cohen STARTRKゲームの光子魚雷ルーチンです。コマンドラインを解析してから、各魚雷の飛行を摂動でシミュレートし、魚雷と衝突する可能性のあるあらゆる種類の物との相互作用を確認し、そして再帰をシミュレートして、他の星の隣にある星の魚雷発射による新星。
長いメソッドが見つかった場合、このメソッドが適切にユニットテストされていないか、ほとんどの場合、ユニットテストがまったく行われていないと思います。 TDDを開始する場合、25の異なる責任と5つのネストされたループを持つ100行のメソッドを構築することはありません。テストでは、混乱を常にリファクタリングし、ボブおじさんのクリーンなコードを書く必要があります。
メソッドの長さに関して絶対的な規則はありませんが、次の規則が役立ちました。
作者は「機能」と「ルーティン」で同じ意味ですか?通常、「関数」とは、値を返さないサブルーチン/操作と、返さない(および呼び出しが単一のステートメントになる)ための「手順」を意味します。これは、現実世界のSE全体で共通の違いではありませんが、ユーザーのテキストで見ました。
どちらにしても、これに対する正しい答えはありません。どちらか一方の好み(まったく好みがある場合)は、言語、プロジェクト、組織間で大きく異なると私が予想するものです。すべてのコード規則と同じです。
私が追加する1つのビットは、「長い操作は短い操作よりもエラーが発生しにくい」というアサーション全体が厳密には当てはまらないことです。コードの数が増えるとエラースペースが増える可能性があるという事実に加えて、コードをセグメントに分割すると、エラーの回避と特定が容易になることは明らかです。そうでなければ、コードを断片に分割する理由はまったくなく、繰り返しを省きます。しかし、これはおそらく、セグメントが十分に文書化されており、実際のコードを読み取ったり追跡したりせずに操作呼び出しの結果を判断できる場合にのみ当てはまります(コード領域間の具体的な依存関係ではなく、仕様に基づく契約ごとの設計)。
さらに、より長い操作をうまく機能させたい場合は、より厳密なコード規則を採用してそれらをサポートすることができます。操作の途中でreturnステートメントを投げることは、短い操作では問題ないかもしれませんが、長い操作では、条件付きですが、クイックリードスルーでは明らかに条件のないコードの大きなセクションが作成される可能性があります(ほんの一例)。
したがって、どのスタイルがバグに満ちた悪夢である可能性が低いかは、大部分、コードの残りの部分に準拠する規則に依存すると思います。 :)
私見、関数を読むためにスクロールバーを使用する必要はありません。スクロールバーを移動する必要があるとすぐに、関数の動作を理解するのにもう少し時間がかかります。
したがって、チーム作業の通常のプログラミング環境(画面の解像度、エディター、フォントサイズなど)によって異なります。 80年代には、25行80列でした。これで、エディターに50行近く表示されます。画面を2つに分割して2つのファイルを同時に表示したため、表示する列の数は変わりませんでした。
簡単に言えば、それはあなたの同僚のセットアップに依存します。
TomTom's answer は私がそれについてどう感じているかに近づいたと思います。
線ではなく、循環的な複雑性にどんどん気づいています。
私は通常、メソッドごとに1つだけの制御構造を目指していますが、多次元配列を処理するために必要なループがいくつあっても例外です。
場合によっては、スイッチケースに1行のifを入れることがあります。これは、何らかの理由で、分割することが助けになるのではなく妨げられる場合が多いためです。
この制限に対してガードロジックはカウントしないことに注意してください。