3つのタスクを実行する大きなメソッドがあり、それぞれを個別の関数に抽出できます。そのタスクごとに追加の関数を作成する場合、コードが良くなるか悪くなるか、そしてその理由は何ですか?
明らかに、メイン関数のコード行は少なくなりますが、追加の関数宣言があるので、クラスには追加のメソッドがありますが、クラスがより複雑になるため、これは良くないと思います。
すべてのコードを書く前にそれを行うべきですか、それともすべてが完了するまでそのままにしてから関数を抽出する必要がありますか?
3つのタスクを実行する大きなメソッドがあり、それぞれを個別の関数に抽出できます。そのタスクごとに追加の関数を作成する場合、コードが良くなるか悪くなるか、そしてその理由は何ですか?
明らかに、メイン関数のコード行は少なくなりますが、追加の関数宣言があるので、クラスには追加のメソッドがありますが、クラスがより複雑になるため、これは良くないと思います。
すべてのコードを書く前にそれを行うべきですか、それともすべてが完了するまでそのままにしてから関数を抽出する必要がありますか?
回答:
これは私がよくリンクする本ですが、ここでもう一度行きます。ロバートC.マーティンのクリーンコード、第3章、「関数」。
明らかに、メイン関数のコード行は少なくなりますが、追加の関数宣言があるので、クラスには追加のメソッドがありますが、クラスがより複雑になるため、これは良くないと思います。
+150行の関数、または3つの+50行関数を呼び出す関数を読みたいですか?私は2番目のオプションを好むと思います。
はい、それはより「読みやすい」という意味であなたのコードを改善します。ただ1つのことを実行する関数を作成します。それらは保守が容易で、テストケースを作成しやすくなります。
また、前述の本で私が学んだ非常に重要なこと:あなたの機能に適切で正確な名前を選んでください。関数がより重要であるほど、名前は最も正確でなければなりません。名前の長さを気にする必要はありませんFunctionThatDoesThisOneParticularThingOnly
。名前を呼び出す必要がある場合は、そのように名前を付けます。
リファクタリングを実行する前に、1つ以上のテストケースを作成します。動作することを確認してください。リファクタリングが完了したら、これらのテストケースを起動して、新しいコードが正しく機能することを確認できます。追加の「より小さい」テストを作成して、新しい関数が分離可能に実行されることを確認できます。
最後に、これは私が今書いた内容に反していません。本当にこのリファクタリングを行う必要があるかどうかを自問し、「いつリファクタリングするか?」の答えを確認してください (また、「リファクタリング」に関するSOの質問を検索してください、もっとあり、答えは読むのが面白いです)
すべてのコードを書く前にそれを行う必要がありますか、それともすべてが完了するまでそのままにしてから関数を抽出する必要がありますか?
コードがすでに存在し、機能していて、次のリリースに間に合わない場合は、触れないでください。そうでなければ、可能な場合はいつでも小さな関数を作成し、すべてが以前と同じように動作することを確認しながら、いつでもリファクタリングする必要があると思います(テストケース)
はい、明らかに。単一の機能の異なる「タスク」を簡単に確認して分離できる場合。
ただし、これには問題がある可能性があります。
あなたが提起している問題は、コーディング、慣習、またはコーディング慣行の問題ではなく、読みやすさの問題であり、テキストエディターがあなたが書いたコードを表示する方法です。これと同じ問題が投稿でも見られます:
長い関数やメソッドを他のものから呼び出されなくても小さなものに分割しても大丈夫ですか?
関数をサブ関数に分割することは、構成するさまざまな機能をカプセル化する目的で大きなシステムを実装する場合に意味があります。それでも、遅かれ早かれ、あなたは多くの大きな機能を自分自身で見つけるでしょう。それらのいくつかは、単一の長い関数として保持するか、より小さい関数として分割するかどうかを維持するのが難しく、維持するのが困難です。これは、システムの他の場所で操作を行う必要がない機能に特に当てはまります。このような長い関数の1つをピックアップして、より広い視野で考えてみましょう。
プロ:
コントラ:
ここで、長い関数をいくつかのサブ関数に分割し、それらをより広い視野で見てみましょう。
プロ:
コントラ:
どちらのソリューションにも賛否両論があります。実際の最良の解決策は、各関数がコンテンツを呼び出すために、インラインで完全な深さまで拡張できるエディターを持つことです。これにより、サブ関数の関数を分割することが唯一の最良のソリューションになります。
私にとっては、コードブロックを関数に抽出する4つの理由があります。
あなたはそれを再利用しています:あなたはただコードのブロックをクリップボードにコピーしました。単に貼り付けるのではなく、関数に入れて、ブロックを両側の関数呼び出しで置き換えます。そのため、そのコードブロックを変更する必要があるときはいつでも、コードを複数の場所で変更するのではなく、その単一の関数を変更するだけで済みます。したがって、コードブロックをコピーするたびに、関数を作成する必要があります。
これはコールバックです。イベントハンドラー、またはライブラリまたはフレームワークが呼び出すユーザーコードです。(関数を作成せずにこれを想像することはほとんどできません。)
現在のプロジェクトまたは他の場所で再利用されると思われます。2つの配列の最も長い共通サブシーケンスを計算するブロックを作成しただけです。あなたのプログラムがこの関数を一度しか呼び出さないとしても、他のプロジェクトでも最終的にこの関数が必要になると思います。
自己文書化コードが必要です。そのため、コードのブロック上にコメントの行を記述してコードの機能を要約するのではなく、全体を関数に抽出し、コメントに記述する名前を付けます。私はこれのファンではありませんが、使用されているアルゴリズムの名前、そのアルゴリズムを選択した理由などを書き出すのが好きなので、関数名は長すぎます...
余談:dallinの質問(現在は閉じられています)に応じてこれを書きましたが、まだ誰かに役立つと思うので、ここに行きます
関数をアトマイズする理由は2倍だと思います。@ jozefgが述べているように、使用する言語に依存しています。
関心事の分離
これを行う主な理由は、コードの異なる部分を分離しておくためです。そのため、関数の望ましい結果/意図に直接寄与しないコードブロックは、個別の懸念事項であり、抽出できます。
プログレスバーも更新するバックグラウンドタスクがあるとします。プログレスバーの更新は、実行中のタスクに直接関係しないため、プログレスバーを使用するコードの唯一の部分であっても抽出する必要があります。
JavaScriptで関数getMyData()があるとします。1)パラメーターからSOAPメッセージを作成し、2)サービス参照を初期化し、3)SOAPメッセージでサービスを呼び出し、4)結果を解析し、5)結果を返します。私はこの正確な関数を何度も書いていますが、実際には 3と5のコードのみを含む3つのプライベート関数に分割することができます(その場合) 。
改善されたデバッグエクスペリエンス
完全にアトミックな機能がある場合、スタックトレースはタスクリストになり、正常に実行されたすべてのコードがリストされます。
データの取得中にエラーが発生したことがわかると、より興味深いものになります。ただし、詳細なコールツリーのデバッグには、Microsoft Debugger Canvasなどのツールがさらに便利です。
また、このように書かれたコードを追跡するのは難しいかもしれないという懸念を理解しています。ただし、関数の名前が適切であり(インテリセンスを使用すると、速度を落とすことなく任意の関数で3〜4個のカマルケースワードを使用できます)、ファイルの先頭にパブリックインターフェイスが構築されている場合、コードは擬似コードのようになりますコードベースの高レベルな理解を得る最も簡単な方法です。
参考までに、これは「私が言うとおりにしない」ことの1つで、コードをアトミックに保つことは、冷酷に私見と矛盾しない限り無意味です。