長い方法は常に悪いですか?[閉まっている]


64

そのため、先ほど見てみると、長い方法が悪い習慣であるというコメントがいくつかありました。

私は、長い方法が悪い(そして他の人からの意見が欲しい)ことにいつも同意するかどうかわかりません。

たとえば、オブジェクトをビューに送信する前にオブジェクトの処理を少し行うDjangoビューがあります。長いメソッドは350行のコードです。パラメータを処理するようにコードを作成しました。クエリセットの並べ替え/フィルタリングを行い、クエリが返したオブジェクトをビットごとに処理します。

そのため、処理は主に条件付き集計であり、データベースでは簡単に実行できない複雑なルールがあるため、メインループの外側で宣言された変数があり、ループ中に変更されます。

variable_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

したがって、理論によれば、すべてのコードをより小さなメソッドに分解する必要があります。そのため、ビューメソッドは最大1ページの長さであると見なされます。

ただし、過去にさまざまなコードベースで作業していたため、あるメソッドから次のメソッドに絶えずジャンプして、その最も外側のメソッドを頭の中で保持する必要がある場合、コードが読みにくくなることがあります。

適切にフォーマットされた長いメソッドを使用すると、内部メソッドで隠されないため、ロジックをより簡単に確認できます。

コードをより小さなメソッドに分解することもできますが、多くの場合、2つまたは3つのことに使用される内部ループがあるため、より複雑なコード、または1つだけではなく2つまたは3つ(またはタスクごとに内部ループを繰り返すこともできますが、パフォーマンスが低下します)。

だから、長い方法が必ずしも悪いわけではない場合はありますか?メソッドを1つの場所でのみ使用する場合、メソッドを記述する場合は常にありますか?

更新:1年以上前にこの質問をしたようです。

そこで、ここで(混合)応答の後にコードをリファクタリングし、メソッドに分割しました。これは、データベースから関連オブジェクトの複雑なセットを取得するDjangoアプリであるため、テストの引数が出ていません(おそらく、テストケースに関連するオブジェクトを作成するのにおそらく1年の大半を費やしていたでしょう。誰も文句を言う前の作業環境)。コードのその部分のバグを修正することは今やや簡単ですが、大したことではありません。

前 :

#comment 1 
bit of (uncomplicated) code 1a  
bit of code 2a

#comment 2 
bit of code 2a
bit of code 2b
bit of code 2c

#comment 3
bit of code 3

今:

method_call_1
method_call_2
method_call_3

def method_1 
    bit of (uncomplicated) code 1a  
    bit of code 2a

def method_2 
    bit of code 2a
    bit of code 2b
    bit of code 2c

def method_3
    bit of code 3

156
すべての絶対は悪いです。常に。
ヨアヒムザウアー

30
「再利用できる場合はメソッドを抽出する」という引数を頻繁に(この形式または類似の形式で)表示しますが、購入しません。メソッドが複数のことをしている場合、読みやすくするためにメソッド抽出する必要があります/ これらの新しいメソッドがコードの1箇所のみから呼び出された場合でも、保守性が向上します。
ヨアヒムザウアー

4
@gnat:うわー、ビルドステップでの何らかの種類の(インラインプリプロセッサを介した)インライン化は、ここでより良い解決策ではないでしょうか?
ヨアヒムザウアー

11
私が知っている最高のプログラマーの1人は、実際にメジャーが必要な場合、ローカル変数の数は実際の長さよりも優れているとコメントしました。彼は複雑なパスオプティマイザーに取り組んでおり、ガッツは数百行の長さの1つのメソッドでしたが、保持される状態(ローカル変数)の量は非常に少なかった。
チュウ

2
長いメソッドは必ずしも悪いとは限りません。しかし、それらはあなたが常に見て、「これは悪いですか?」と自問すべきものです。
Carson63000

回答:


80

いいえ、長い方法は必ずしも悪いとは限りません。

Code Completeの本では、長いメソッドはより速く、より簡単に書くことができ、メンテナンスの問題につながらないことが測定されています。

実際、本当に重要なのは、DRYを維持し、懸念の分離を尊重することです。計算は書くのに長い場合もありますが、実際には将来問題を引き起こすことはありません。

しかし、私の個人的な経験から、ほとんどの長い方法は懸念の分離に欠ける傾向があります。実際、長いメソッドは、コード内の何かが間違っている可能性があることを検出する簡単な方法であり、コードレビューを行う際にはここで特別な注意が必要です。

編集:コメントが作成されると、答えに興味深いポイントを追加します。実際には、関数の複雑さのメトリック(NPATH、循環的複雑さ、さらにはより良いCRAP)もチェックします。

実際、長い関数ではそのようなメトリックをチェックせず、すべての関数で自動ツール(たとえばjavaのcheckstyleなど)でそれらのアラートを含めることをお勧めします。


41
+1:「いいえ、長いメソッドは必ずしも悪いわけではありません」が、ほとんど常に悪いです
Binary Worrier

67
長いメソッド本体は、古典的なコードの匂いです。それ自体は問題ではありませんが、おそらく問題があることを示しています。
ヨアヒムザウアー

6
+1ですが、ロングメソッドの循環的な複雑さを確認することをお勧めします。高い値は、単体テストでは事実上不可能なメソッドを示します(長いメソッドが制御フローロジックを欠くことはほとんどありません)。
ダニエルB

11
メソッド名を使用してコメントを最小限にします。これにより「getSelectedNodeWithChildren」などが発生する場合がありますが、同僚からコードが読みやすいと言われ続けています。また、略語を避けるようにしています。それらは書くのは良いですが、読むのはそれほど良いことではありません。
K ..

4
@ da_b0uncerそれも私が従うポリシーです。コードを書くよりも読むのが難しいので、コードを読みやすくするために書くときの余分な努力は報われます。
deadalnix

55

ここでの焦点のほとんどは常に言葉の周りにあるようです。はい、絶対は悪いです、そしてソフトウェア工学はそれが科学であるのとほとんど同じくらい芸術です、そして...それはあなたが与えた例のために、それが分割された場合、方法はより良いだろうと言わなければなりませんアップ。これらは、メソッドの分割を正当化するために通常使用する引数です。

読みやすさ:他の人についてはわかりませんが、350行のコードをすばやく読むことができません。はい、それが自分コードであり、それについて多くの仮定を立てることができれば、私それを非常に迅速にざっと読むことができますが、それは重要ではありません。メソッドが他のメソッドへの10回の呼び出し(それぞれが説明的な名前を持つ)で構成されている場合、そのメソッドの読みやすさを考慮してください。これを行うことで、コードに階層化を導入しました。高レベルのメソッドは、何が起こっているのかについて読者に簡潔で簡潔なアウトラインを提供します。

編集-それを別の観点から見ると、次のように考えてください。新しいチームメンバーにその方法をどのように説明しますか?確かにそれは持っているいくつかのあなたが「Cなど時々 、その後、Bそして、まあ、それはAをやってから始まり」の線に沿ってまとめることができた構造を。他のメソッドを呼び出す短い「概要」メソッドがあると、この構造が明らかになります。利益のないコードが350行見つかることは非常にまれです。人間の脳は何百ものアイテムのリストを扱うことを意図していないので、それらをグループ化します。

再利用性:長いメソッドは凝集度が低い傾向があります- 多くの場合、複数のことを行います。低粘着性は再利用の敵です。複数のタスクを1つのメソッドに結合すると、本来よりも少ない場所で再利用されることになります。

テスト容易性と結束性:上記のコメントで循環的複雑性について言及しました。これは、メソッドがどれほど複雑であるかのかなり良い尺度です。入力に応じて、コードを通る一意のパスの数の下限を表します(編集:MichaelTのコメントに従って修正)。また、メソッドを適切にテストするには、少なくとも循環的複雑度の数と同じ数のテストケースが必要であることを意味します。残念ながら、実際には相互に依存していないコードの断片をまとめると、この依存性の欠如を確実にする方法がなく、複雑さが増す傾向があります。この測定値は、実行しようとしているさまざまなことの数の指標と考えることができます。高すぎる場合は、分割して征服する時間です。

リファクタリングと構造:長いメソッドは、多くの場合、コードに構造が欠けていることを示しています。多くの場合、開発者は、そのメソッドのさまざまな部分の共通点と、それらの間に線を引くことができる場所を把握できませんでした。長い方法が問題であることを認識し、それをより小さな方法に分割しようとすることは、全体のより良い構造を実際に識別するための長い道のりの最初のステップです。おそらく、クラスを1つまたは2つ作成する必要があります。最終的には必ずしも複雑になるとは限りません!

また、この場合、長いメソッドを持つことの言い訳は「...メインループ外で宣言されたいくつかの変数がループ中に変更される」ことだと思います。私はPythonの専門家ではありませんが、この問題は何らかの形で参照渡しすることで簡単に修正できると確信しています。


13
質問のいつもの部分を否定し、肉に焦点を合わせた+1:長い方法が悪いかどうか。OPは、彼のシナリオがエッジケースであるかのように正当化を求めていると思いますが、通常、一般的ではないシナリオの必要に応じて人々が悪い慣行を説明するのを聞くとき、それは彼らが良い慣行を非常に一生懸命に試みなかったからです。珍しいシナリオは本当に珍しいことですが、悲しいことに長い方法は非常に一般的です。
ジミー・ホッファ

2
上記のリストを見てください:過去の経験から私が言う可読性は、メソッドからメソッドにコードをジャンプするのではなく、メソッドを長くし、コメントを多く含み、適切にフォーマットすることによって向上しますが、これはおそらくかなり主観的です。コードの一部が再利用されるとは思わない。コードの再利用のほとんどは、現時点では継承から実現されています。
wobbily_col

1
@wobbily_colところで、短いメソッドを使用するという理論的根拠のある、よく書かれたテキストを探している場合は、Clean Codeの最初のいくつかの章を読んでください。
ダニエルB

5
@wobbily_col多くの方法でコードを理解するために飛び回る必要があるのはわかりにくいと言いますが、ここで欠けている点は命名の重要性だと思います。この方法がうまく命名されている場合、あなたはそれをやっているかを調べるために、それを見てする必要はありません、呼び出し元のメソッドは、呼び出したメソッドが何をしているかのいずれかの基本的な知識がなくても、完全に理解する必要があり、例えば、あなたが今まで使用してきたsomeVar.toString()と感じましたtoStringのコードを見て、それが何をしているかを知る必要がありましたか?メソッドの命名が優れているため、すぐに読んでください。
ジミー・ホッファ

4
余談ですが、n個のパラメーターを必要とするメソッドを持つことはコードの匂いでもあり、メソッドが複数のことを行う可能性があることを示しています。同じことは、名前を付けるのが難しいメソッドを持つことにも当てはまります。そして、それらすべてのパラメーターが本当に必要な場合、それらは通常、より大きな概念の一部であり、独自のクラスに含めることができます。もちろん、このルールを使用しないほうが良い例が思い浮かぶかもしれません-私のポイントは、あなたがそのような方法を見たら、それを徹底的に調査し、おそらく何らかの形で悪いことです。
KL

28

長い方法は常に悪いですが、時折他の方法よりも優れています。


5
説明がないと、他の誰かが反対意見を投稿した場合に、この答えが役に立たなくなる可能性があります。たとえば、「長い方法は決して悪いことではありませんが、ときどき他の方法より悪い」というような主張を誰かが投稿した場合です。、この答えは読者が2つの反対意見を選ぶのにどのように役立ちますか?考えてみましょ編集をより良い形にそれをINGの
ブヨ

9

長いメソッドはコードの匂いです。彼らは通常、何かが間違っていることを示しますが、それは難しいルールではありません。通常、正当化されるケースには、多くの状態とかなり複雑なビジネスルールが含まれます(ご存じのとおり)。

他の質問については、ロジックのチャンクを1回しか呼び出されない場合でも、別々のメソッドに分離することがしばしば役立ちます。これにより、高レベルのロジックが見やすくなり、例外処理が少し簡潔になります。処理状態を表すために20個のパラメーターを渡す必要がない限りです!


7

長いメソッドは必ずしも悪いとは限りません。彼らは通常、問題があるかもしれないという兆候です。

私が取り組んでいるシステムには、10,000行を超える半ダースほどのメソッドがあります。1つは現在54,830行の長さです。そして大丈夫です。

これらの途方もなく長い関数は非常に単純で、自動生成されます。その大きな54,830行のモンスターには、1962年1月1日から2012年1月10日までの毎日の極運動データが含まれています(最後のリリース)。また、ユーザーが自動生成されたファイルを更新できる手順をリリースします。そのソースファイルには、http://data.iers.org/products/214/14443/orig/eopc04_08_IAU2000.62-nowの極座標モーションデータが含まれており、C ++に自動翻訳されています。

安全なインストールでは、そのWebサイトをその場で読むことはできません。外の世界とのつながりはありません。Webサイトをローカルコピーとしてダウンロードし、C ++で解析することもオプションではありません。解析は遅く、これは速くなければなりません。ダウンロード、C ++への自動翻訳、およびコンパイル:これで、高速なものが手に入りました。(最適化してコンパイルしないでください。最適化コンパイラが50,000行の非常に単純な直線コードをコンパイルするのにどれほど時間がかかるかは驚くべきことです。 。最適化するものは何もありません。それは単純な直線コードで、次々に割り当てステートメントがあります。)


6
「次々に代入文」...私はそれを「データファイル」と呼びます。なぜコードなのですか?
ヨアヒムザウアー

3
@JoachimSauer-モンテカルロセットアップで実行時に大きなデータファイルを解析するのは悪い考えです。非常に、非常に悪い考えです。
デビッドハンメン

4
@DavidHammen:リンカー/ローダーを強制するのと同じように、初期化時に実行します。または、Cコードではなく、ヘッダーファイルにC構造体としてデータファイルを書き込みます。少なくともローダーはデータブロックとしてロードします。
ハビエル

3
@Javier:初期化時でさえ、少なくともモンテカルロ設定では、非常に悪い考えです。初期化に数分かかりますが、実行に数秒しかかからないシミュレーションは、一晩で何万回も実行されるというグレインに反します。主要な初期化時間タスクをコンパイル時間タスクに変更すると、その問題が修正されます。コンパイル済みのデータ構造アプローチを含む、多くの手法を試しました。動作しないか、場合によっては動作させるのが非常に困難です(例:巨大な重力モデル)。直線コードのアプローチは、自動生成と検証が簡単です。codeいコードです。
デビッドハンメン

7
面白いストーリーを+1。生成されたコードはもちろんソースコードではないため、これがルールを「破らない」と主張することができます。一つは、それ自体が素敵な短いメソッドを持っていたコードジェネレータを前提と
JKを。

7

長い方法を分割する良い方法と悪い方法があるとだけ言ってみましょう。「頭の中で一番外側のメソッドを保持する」ということは、それを最適な方法で分割していないこと、またはサブメソッドの名前が間違っていることを示しています。理論的には、長い方法の方が良い場合があります。実際には、それは非常にまれです。短いメソッドを読みやすくする方法がわからない場合は、誰かにコードをレビューしてもらい、メソッドを短縮するためのアイデアを具体的に尋ねてください。

想定されるパフォーマンスヒットを引き起こす複数のループについては、測定せずにそれを知る方法はありません。複数の小さなループは、必要なものがすべてキャッシュ内にとどまることができる場合、非常に高速になります。パフォーマンスが低下した場合でも、通常は読みやすさを考慮して無視できます。

多くの場合、長いメソッドは読むのがより難しいのに、書くのがより簡単だと言うでしょう。だから誰も彼らを好きではないのに、彼らは増殖するのです。チェックインする前にリファクタリングを最初から計画することには何の問題もありません。


1
「チェックインする前に最初からリファクタリングを計画することには何の問題もありません。」そのために+1。最近のほとんどのIDEには、これを非常に簡単にするリファクタリングツールがあります。しかし、存在しない関数に物事を委任し、後でメソッドに入力するリバースメソッドがありますが、私が試した限りでは、そのようにコーディングすることはできませんでした。
Tjaart

「「頭の中で一番外側の方法を維持する」ことへの+1は、最適な方法でそれを解体していないことの兆候です」
マイケルショー

4

長いメソッドは、より計算的でスペース効率が良く、ロジックを簡単に確認してデバッグすることができます。ただし、これらのルールは、そのコードに触れるプログラマが1人だけの場合にのみ実際に適用されます。コードはアトミックではない場合、拡張するのが苦痛になります。本質的に次の人は最初から始めなければならず、既知の良いコードを使用していないため、これをデバッグしてテストすることは永遠にかかります。


34
「あなた」と「あなた、今から3週間後」という少なくとも2人のプログラマーが常に関与しています。
ヨアヒムザウアー

3

長いメソッドを可能な限り小さなメソッドに分割することを意味する、機能分解と呼ばれるものがあります。メソッドにはソート/フィルタリングが含まれると述べたように、これらのタスク用に個別のメソッドまたは関数を用意する方がよいでしょう。

正確には、メソッドはパフォーマンス1のタスクのみに焦点を合わせる必要があります。

そして、何らかの理由で別のメソッドを呼び出す必要がある場合は、そうしないと、すでに書いているものを続けます。また、読みやすくするために、コメントを追加できます。従来、プログラマはメソッドの説明に複数行のコメント(C、C ++、C#、およびJavaの/ ** /)を使用し、単一行のコメント(C、C ++、C#、およびJavaの//)を使用します。また、コードを読みやすくするための優れたドキュメントツール(JavaDocなど)も利用できます。.Net開発者であれば、XMLベースのコメントを調べることもできます。

ループはプログラムのパフォーマンスに影響を与え、適切に使用しないとアプリケーションのオーバーヘッドを引き起こす可能性があります。考えは、ネストされたループをできるだけ使用しないようにアルゴリズムを設計することです。


「関数は1つのことを行うべきです」とも呼ばれます。
-lorddev

3

長い関数を書くことはまったく問題ありません。ただし、実際に必要かどうかはコンテキストによって異なります。例えば、最高のアルゴリズムのいくつかは、それがピースであるときに最高に表現されます。一方、オブジェクト指向プログラムのルーチンの大部分は、非常に短いアクセサールーチンになります。条件をテーブル駆動方式で最適化できる場合、長いスイッチケースを持つ長い処理ルーチンの一部。

Code Complete 2には、ルーチンの長さに関する優れた短い議論があります。

理論上の最良の最大長は、多くの場合、66〜132行のプログラムリストの1ページまたは2ページとして記述されます。最近のプログラムでは、非常に短いルーチンといくつかの長いルーチンが混在する傾向があります。

数十年の証拠によると、このような長さのルーチンは、短いルーチンよりもエラーを起こしやすいということはありません。ネストの深さ、変数の数、およびその他の複雑性に関連する考慮事項などの問題で、長さを課すのではなく、ルーチンの長さを決定できるようにします

約200行より長いルーチンを作成する場合は注意してください。コストの削減、エラー率の低下、またはその両方が200行を超えるサイズで区別される大きなルーチンを報告した研究はなく、200行のコードを渡すと、理解しやすい上限に達します。536個の制限それ自体。


2

それはほとんど常に間違っているという別の投票。しかし、それが適切な答えである2つの基本的なケースを見つけます。

1)基本的に他の多くのメソッドを呼び出すだけのメソッドであり、実際の作業自体は行いません。達成するのに50ステップを要するプロセスがあり、50の呼び出しを含むメソッドを取得します。通常、それを解こうとして得られるものは何もありません。

2)ディスパッチャ。OOP設計ではこのような方法のほとんどが廃止されましたが、データの入力ソースは本質的に単なるデータであるため、OOPの原則に従うことはできません。データを処理するコードにある種のディスパッチャルーチンを置くことは、まったく珍しいことではありません。

また、自動生成されたものを扱うときは、質問を検討するべきではないと言うでしょう。自動生成されたコードが何をするのかを理解しようとする人はいません。人間が理解しやすいかどうかは重要ではありません。


1
50ステップのプロセスは、おそらくいくつかのバケットにまとめられます。手順1〜9はパラメーターチェックなので、パラメーターチェックと呼ばれる新しいメソッドを作成します。(これが不可能な例がいくつかあると確信しています。見たいと思います)。
sixtyfootersdude

@sixtyfootersdude:もちろん、解散することもできます。私はそれが不可能だとは言いませんでした。それを解体しても何も得られないと言いました。50ステップではありませんでしたが、ゲームワールドの作成というようなものを見つけました。#1は空の世界を作成し、#2は地形を作成し、その後、いくつかのステップが何らかの方法でそれをマッサージしました。
ローレンペクテル

&sixtyfootersdude:見たことのないコードをどのように知り、改善するかは驚くべきことです。
gnasher729

2

あなたが与えた例を取り上げたいと思います。

たとえば、オブジェクトをビューに送信する前にオブジェクトの処理を少し行うDjangoビューがあります。長いメソッドは350行のコードです。パラメータを処理するようにコードを作成しました-クエリセットの並べ替え/フィルタリングを行い、クエリが返したオブジェクトをビットごとに処理します。

私の会社では、私たちの最大のプロジェクトはDjangoで構築されており、長いビュー機能もあります(多くは350行以上です)。私たちはそれほど長くする必要はなく、彼らは私たちを傷つけていると主張します。

これらのビュー関数は、モデル、ヘルパークラス、またはヘルパー関数に抽出する必要がある、大まかに関連する多くの作業を実行しています。また、さまざまなことを行うためにビューを再利用することになります。代わりに、よりまとまりのあるビューに分割する必要があります。

あなたの意見には似たような特徴があると思います。私の場合、それが問題を引き起こすことがわかっているので、変更に取り組んでいます。問題を引き起こしていることに同意しない場合、修正する必要はありません。


2

誰かがすでにこれについて言及しているかどうかはわかりませんが、長いメソッドが悪い理由の1つは、通常いくつかの異なるレベルの抽象化を伴うためです。ループ変数があり、あらゆる種類のことが起こります。架空の機能を考えます:

function nextSlide() {
  var content = getNextSlideContent();
  hideCurrentSlide();
  var newSlide = createSlide(content);
  setNextSlide(newSlide);
  showNextSlide();
}

その関数ですべてのアニメーション、計算、データアクセスなどを行っていた場合、それは混乱でした。nextSlide()関数は、一貫した抽象化レイヤー(スライド状態システム)を維持し、他のレイヤーを無視します。これにより、コードが読みやすくなります。

小規模なメソッドに常に足を踏み入れて、それらの機能を確認する必要がある場合、関数を分割する演習は失敗しています。読んでいるコードが子メソッドで明らかなことをしていないからといって、子メソッドが悪い考えであることを意味するのではなく、単に間違って実行されたというだけです。

メソッドを作成するとき、私は通常、一種の分割統治戦略としてそれらをより小さなメソッドに分割します。のような方法

   if (hasMoreRecords()) { ... }

確かに読みやすい

if (file.isOpen() && i < recordLimit && currentRecord != null) { ... } 

右?

絶対的なステートメントが悪いことについては同意しますが、通常、長い方法は悪いことも同意します。


1

実話。私はかつて、2000行を超える方法に遭遇しました。このメソッドには、それらの領域で何をしていたかを記述する領域がありました。リージョンを読み終えた後、リージョン名に従って命名する自動抽出メソッドを実行することにしました。私が終わった頃には、メソッドはそれぞれ約50行の40のメソッド呼び出しに過ぎず、すべて同じように機能していました。

大きすぎるのは主観的です。場合によっては、メソッドは現在よりもさらに細分化できないことがあります。本を書くようなものです。ほとんどの人は、長いパラグラフを通常分割することに同意します。ただし、アイデアが1つしかない場合があり、それを分割すると、その段落の長さによって生じるよりも多くの混乱が生じます。


0

メソッドのポイントは、コードの逆流を減らすことです。メソッドには、それが担当する特定の機能が必要です。多数の場所でコードを再ハッシュすることになった場合、ソフトウェアが対処するように設計された仕様が変更されると、コードが予期しない結果になるリスクがあります。

350行のメソッドでは、特殊なタスクを実行するためにこのような大量のコードが必要になることは珍しいため、実行中のタスクの多くが他の場所に複製されることが示唆されます。


コードを減らすのに役立ちます
アヴナーシャハルカシュタン

@ AvnerShahar-Kashtan、彼はおそらく「複製」を意味します:
ペテル・トレック

0

悪い習慣であるのは、実際には長い方法ではありません。

サンプルをリファクタリングする実際の行為は、

varaible_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

Status status = new Status();
status.variable1 = 0;
status.variable2 = 0;
for object in queryset :
     if object.condition_condition_a and status.variable2 > 0 :
     status.variable1 += 1
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

それから

class Status {
    variable1 = 0;
    variable2 = 0;

    void update(object) {
        if object.condition_condition_a and variable2 > 0 {
            variable1 += 1
        }
    }
};

Status status = new Status();
for object in queryset :
     status.update(object);
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

これで、はるかに短い方法だけでなく、はるかに使いやすく理解しやすい方法への道を進んでいます。


0

メソッドが非常に長いという事実は確認するべきものであると思いますが、即座のアンチパターンではありません。巨大なメソッドで探すべき大きなことは、たくさんのネストです。あなたが持っている場合

foreach(var x in y)
{
    //do ALL the things
    //....
}

そして、ループの本体は極端にローカライズされていません(つまり、4個未満のパラメーターを送信できます)。

foreach(var x in y)
{
    DoAllTheThings(x);
}
...
void DoAllTheThings(object x)
{
    //do ALL the things
    //....
}

これにより、関数の長さが大幅に短縮されます。また、関数内の重複コードを探し、それを別の関数に移動するようにしてください

最後に、いくつかの方法は長くて複雑であり、あなたができることは何もありません。一部の問題には、コーディングが容易ではないソリューションが必要です。たとえば、非常に複雑な文法を解析すると、本当に長いメソッドが作成される可能性があります。


0

真実は、それは依存します。前述のように、コードが懸念事項を分離せず、1つのメソッドですべてを実行しようとすると、問題になります。コードを複数のモジュールに分離すると、コードの読み取りとコードの作成が容易になります(複数のプログラマーによる)。最初に、ソースファイルごとに1つのモジュール(クラス)に準拠することをお勧めします。

第二に、関数/手順に関しては:

void setDataValueAndCheckForRange(Data *data) {/*code*/} 

「データ」のみの範囲をチェックする場合に適した方法です。同じ範囲が複数の関数に適用される場合、これは悪い方法です(不正なコードの例):

void setDataValueAndCheckForRange(Data *data){ /*code */}
void addDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void subDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void mulDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}

これをリファクタリングする必要があります:

bool isWithinRange(Data *d){ /*code*/ }
void setDataValue(Data *d) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void addDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void subDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void mulDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 

可能な限りコードを再利用します。そして、それはあなたのプログラムの各機能が単純である(必ずしも簡単ではない)ときに十分です。

引用:マウンテンは小さな地球の粒で構成されています。海は小さな水滴で構成されています。(-Sivananda)


0

長いメソッドは、文、副作用、および可変性を好む命令型言語では「悪い」傾向があります。これは、これらの機能により複雑さが増し、バグが増えるためです。

式、純度、および不変性を支持する関数型プログラミング言語では、心配する必要はほとんどありません。

関数型言語と命令型言語の両方で、再利用可能なコードのチャンクを共通のトップレベルルーチンに含めることは常に最善ですが、ネストされた関数などでレキシカルスコープをサポートする関数型言語では、実際には、サブルーチンをトップ内に隠すのがより良いカプセル化です-レベル関数(メソッド)よりも他のトップレベル関数に分割します。


ただし、関数型言語では、長いメソッドはあまり一般的ではありません。
itsbruce
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.