web-dev-qa-db-ja.com

パラメーターが多すぎますか?

ルーチンはパラメーターを持つことができますが、それはニュースではありません。必要な数のパラメーターを定義できますが、パラメーターが多すぎると、ルーチンの理解と保守が難しくなります。

もちろん、回避策として構造化変数を使用できます。これらすべての変数を単一の構造体に入れて、ルーチンに渡します。実際、構造体を使用してパラメーターリストを単純化することは、Code CompleteでSteve McConnellが説明した手法の1つです。しかし、彼が言うように:

慎重なプログラマーは、論理的に必要な以上のデータのバンドルを避けます。

したがって、ルーチンのパラメーターが多すぎる場合、または構造体を使用して大きなパラメーターリストを偽装している場合、おそらく何か間違ったことをしていることになります。つまり、カップリングを緩く維持しているわけではありません。

私の質問は、パラメーターリストが大きすぎると考えられるのはいつですか? 5つ以上のパラメーターが多すぎると思います。どう思いますか?

228
Auron

言論の自由に対する第1修正条項の保証にもかかわらず、規制できるものであるとわいせつなものが考えられるのはいつですか?ポッター・スチュワート判事によると、「見ればわかる」。ここでも同じことが言えます。

答えはプロジェクトのサイズと範囲によって変わるだけでなく、モジュールレベルまでも変わると思うので、このような厳格なルールを作成するのは嫌です。メソッドが何をしているか、またはクラスが何を表すかによって、2つの引数が多すぎて、カップリングが多すぎることを示す可能性があります。

そもそも質問をして、あなたと同じくらいあなたの質問を修飾することによって、あなたはこのすべてを本当に知っていることをお勧めします。ここでの最善の解決策は、ハードナンバーとファーストナンバーに依存するのではなく、ピア間のデザインレビューとコードレビューに目を向けて、凝集度が低く密結合のある領域を特定することです。

同僚に自分の仕事を見せることを恐れないでください。もしあなたが怖いなら、それはおそらくあなたのコードに何か問題があり、あなたがすでに知っているであることを示す大きな兆候です。

162
Nick

一部のパラメーターが冗長である場合、関数にはパラメーターが多すぎます。すべてのパラメーターを使用する場合、関数には正しい数のパラメーターが必要です。このよく使用される機能をご覧ください。

HWND CreateWindowEx
(
  DWORD dwExStyle,
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  HWND hWndParent,
  HMENU hMenu,
  HINSTANCE hInstance,
  LPVOID lpParam
);

これは12個のパラメーター(x、y、w、hを長方形としてバンドルする場合は9)であり、クラス名から派生したパラメーターもあります。これをどのように減らしますか?必要な数にさらに減らしたいですか?

パラメーターの数を気にせず、論理的で十分に文書化されていることを確認し、インテリセンスを許可します* 助けます。

* 他のコーディングアシスタントが利用可能です!

124
Skizz

Clean Code では、ロバートC.マーティンが4ページを主題に当てました。ここに要点があります:

関数の引数の理想的な数はゼロ(niladic)です。次に1つ(単項)、2つ(2項)が続きます。可能な場合は、3つの引数(3項)を避ける必要があります。 3つ以上(ポリアドリック)には非常に特別な正当化が必要です。

106

過去に作業したコードの中には、あまりにも多くのパラメーターを渡さないようにするためにグローバル変数を使用したものがありました。

しないでください!

(通常。)

79

署名内のパラメーターをメンタルにカウントオフし、それらを呼び出しに一致させる必要がある場合は、リファクタリングの時間です!

38
Rob Walker

あなたのすべての答えをありがとうございました:

  • 5個のパラメーターがコードの健全性の適切な制限であると思う(私もそう思う)人を見つけるのは少し驚きでした。

  • 一般に、人々は3〜4の制限が良い経験則であることに同意する傾向があります。人々は通常4つ以上のものを数えるのに苦労するため、これは合理的です。

  • Milanポイント のように、平均して、一度に7個以上のアイテムを頭の中に入れることができます。しかし、ルーチンを設計/保守/研究するときは、パラメータだけでなく、より多くのものを心に留めておく必要があることを忘れることはできないと思います。

  • 一部の人々は、ルーチンには必要なだけの引数があるべきだと考えています。私は同意しますが、いくつかの特定のケース(OS APIの呼び出し、最適化が重要なルーチンなど)についてのみです。これらの呼び出しのすぐ上に可能な限り抽象化の層を追加することにより、これらのルーチンの複雑さを隠すことをお勧めします。

  • Nickには 興味深い考え があります。あなたが彼のコメントを読みたくない場合、私はあなたのために要約します:一言で言えば、それは依存します

    答えはプロジェクトのサイズと範囲によって変わるだけでなく、モジュールレベルまでも変わると思うので、このような厳格なルールを作成するのは嫌です。メソッドが何をしているか、またはクラスが何を表すかによって、2つの引数が多すぎて、カップリングが多すぎることを示す可能性があります。

    ここでの教訓は、コードを同僚に見せることを恐れず、同僚と話し合い、「凝集度が低く密結合のある領域を特定する」を試みることです。

  • 最後に、wnoiseはNickに大いに同意し、 この詩的なビジョン (以下のコメントを参照)との風刺的な貢献を結論付けたと思います。プログラミングの芸術:

    プログラミングはエンジニアリングではありません。コードの編成は、人間の要因に依存するため、芸術です。人的要因は、厳格なルールではコンテキストに依存しすぎます。

31
Auron

この回答は、OO言語を想定しています。 1つを使用していない場合は、この回答をスキップしてください(言い換えれば、これは言語に依存しない回答ではありません。

3つ以上のパラメーター(特に組み込み型/オブジェクト)を渡す場合、「多すぎる」ということではなく、新しいオブジェクトを作成する機会を逃している可能性があります。

複数のメソッドに渡されるパラメーターのグループを探します。2つのメソッドに渡されたグループでさえ、そこに新しいオブジェクトがあることをほぼ保証します。

次に、新しいオブジェクトに機能をリファクタリングすると、コードとOOプログラミングの両方の理解に役立つとは思わないでしょう。

16
Bill K

単なる数以外の考慮事項があるように思われますが、ここで思い浮かぶいくつかがあります:

  1. 機能の主な目的と一時的な設定との論理的な関係

  2. それらが単なる環境フラグである場合、バンドルは非常に便利です。

13
John Mulder

Alan Perlisの有名なプログラミングエピグラムの1つ(ACM SIGPLAN Notices 17(9)、1982年9月に詳述)は、「10個のパラメーターを持つプロシージャがある場合、おそらくいくつかを見落としている」と述べています。

12
Peter S. Housel

Code CompleteのSteve McConnellによると、

ルーチンのパラメーターの数を約7に制限します

11
Paul Reiners

私にとって、リストがIDEで1行にまたがると、1つのパラメーターが多すぎます。アイコンタクトを壊すことなく、すべてのパラメーターを1行で表示したい。しかし、それは私の個人的な好みです。

9
Learning

私は一般的に5に同意しますが、もっと必要な状況があり、それが問題を解決する最も明確な方法である場合、私はより多くを使用します。

9
Inisheer

短期記憶にある7つのこと?

  1. 関数の名前
  2. 関数の戻り値
  3. 機能の目的
  4. パラメータ1
  5. パラメータ2
  6. パラメータ3
  7. パラメータ4
8
Mike Clark

ワースト5コードスニペット で、2つ目の「これはコンストラクターですか」を確認します。 37⋅4≈150以上のパラメーターがあります:

ここでプログラマーがこのコンストラクターを書いた[... S]はい、それは大きなコンストラクターだと思う人もいるかもしれませんが、彼はEclipse自動コード生成ツールを使用しました[。] NOOこのコンストラクタは手書きで作成されたと結論付けます。 (ちなみに、これはコンストラクタの最上部にすぎず、完全ではありません)。

constructor with over 150 parameters

7
medopal

必要以上に1つ。私はglibであるつもりはありませんが、かなり多くのオプションを必要とする機能がいくつかあります。例えば:

void *
mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset);

6つの議論があり、それらのすべてが不可欠です。さらに、それらをバンドルすることを正当化するための共通のリンクはありません。 「struct mmapargs」を定義できるかもしれませんが、それはさらに悪いでしょう。

6
Kirk Strauser

Perl Best Practicesによると、3は大丈夫、4は多すぎます。これは単なるガイドラインですが、私たちの店ではそれを固守しようとしています。

5
Adam Bellaire

97はほぼ適切に聞こえます。

それ以下では、柔軟性が失われます。

5
Johan

あなたが考慮しなければならない関連する質問は、どのように 凝集性 ルーチンであるかです。多数のパラメータは、ルーチン自体がやりすぎているため、凝集性が疑われることを示す匂いかもしれません。固くて速いパラメータの数はおそらく不可能であることには同意しますが、凝集度の高いルーチンはパラメータの数が少ないことを意味すると思います。

5

私は自分で5つのパラメーターでパブリック関数の制限を引き出します。

私見、長いパラメーターリストは、コード内のいくつかの特定の場所からのみ呼び出されることを意図したプライベート/ローカルヘルパー関数でのみ受け入れられます。そのような場合、多くの状態情報を渡す必要があるかもしれませんが、読みやすさはそれほど重要ではありません。なぜなら、あなた(または、コードを保守し、モジュールの基本を理解する人)だけが気にしなければならないからです。その関数を呼び出します。

5
Kip

パフォーマンスの観点から指摘することの1つは、パラメーターをメソッドに渡す方法によっては、多くのパラメーターを値で渡すと、各パラメーターをコピーしてスタックに配置する必要があるため、プログラムの速度が低下することです。

単一のクラスを使用してすべてのパラメーターを含めると、参照によって渡される単一のパラメーターがエレガントでクリーンで高速になるため、より適切に機能します。

4

一般的な経験則として、3つのパラメーターで停止します。これで、代わりにパラメーターの配列または構成オブジェクトを渡す時間になります。これにより、APIを変更せずに将来のパラメーターを追加することもできます。

4
Eran Galperin

パラメータリストの長さ制限は、もう1つの制限です。そして、制限は暴力を適用することを意味します。面白そうに聞こえますが、プログラミング中であっても暴力的ではない場合があります。コードにルールを指示させてください。多くのパラメータがある場合、関数/クラスメソッドの本体はそれらを使用するのに十分な大きさになることは明らかです。また、通常、大きなコードスニペットはリファクタリングされ、小さなチャンクに分割されます。リファクタリングされた小さなコードに分割されるため、多くのパラメーターを無料ボーナスとして使用することに対する解決策が得られます。

4
Anonymous

私によると、4を超えるか、一定の数を超える場合があります。目を引くものは

  1. メソッドの処理が多すぎるため、リファクタリングする必要があります。
  2. コレクションまたは何らかのデータ構造の使用を検討することもできます。
  3. クラスの設計を考え直してください。おそらく、いくつかのことをやり直す必要はありません。

使いやすさやコードの読みやすさの観点から、メソッドシグネチャを「ワードラップ」する必要がある場合は、停止して考える必要があると思います。検索結果はありません。過去および現在の非常に優れたライブラリには、4〜5台以上の乳母車が使用されています。

3
Perpetualcoder

私の経験則では、呼び出しを見て、それが何をするのかを伝えるのに十分な長さのパラメーターを覚えておく必要があるということです。そのため、メソッドを見てからメソッドの呼び出しに切り替えて、どのパラメーターが何を行うかを覚えていない場合は多すぎます。

私にとっては約5に相当しますが、私はそれほど明るくはありません。あなたのマイレージは異なる場合があります。

パラメータを保持するプロパティを持つオブジェクトを作成し、設定した制限を超えた場合にそれを渡すことができます。 Martin Fowlerの Refactoring 本と、メソッド呼び出しをより簡単にする章を参照してください。

3
Mike Two

Clean MartinのRobert Martinの引用に同意します( 上記のように ):パラメーターが少ないほど良いです。 5〜7を超えるパラメーターとメソッド呼び出しを理解するのはかなり難しくなります。一部のパラメーターがオプションである場合(つまり、NULL値をとる場合)、またはすべてのパラメーターが同じタイプである場合(どのパラメーターがどのパラメーターであるかを判別するのがさらに難しくなります)、事態は特に悪化します。 CustomerやAccountなどの凝集性のあるドメインオブジェクトにパラメーターをバンドルできる場合、コードの操作はずっと快適になります。

Edgeの場合があります:可変数のパラメーターをとるメソッド呼び出しがある場合論理セットを形成する、より多くのパラメーターを持つより少ない認知オーバーヘッドがあります。たとえば、HTTP要求の再試行回数をミリ秒単位で指定するメソッドが必要になる場合があります。 1秒、2秒、および3秒の間隔での3回の再試行は、次のように指定できます。

retries(1000, 2000, 3000)

この限られたケースでは、呼び出しにパラメーターを追加しても、精神的な過負荷はそれほど増えません。

もう1つの考慮事項は、言語が名前付きパラメーターリストをサポートし、オプションのパラメーターを省略できるかどうかです。名前の付いたパラメータリストが大きいほど、名前のないパラメータリストが大きい場合よりもわかりやすくなります。

しかし、私はまだ多くのパラメーターではなく、より少ないパラメーターの側で間違いを犯します。

1
Jim Ferrans

1つのルーチンに7〜10個のパラメーターがある場合、それらを新しいクラスにバンドルすることを検討します but クラスはdoで値をシャッフルする以外の何かをする必要があります。それ以外の場合は、長いパラメーターリストに我慢します。

1
finnw

関数が呼び出される頻度に基づいて答えを決めます。

これが一度しか呼び出されない初期化関数である場合は、気にする人が10個以上のパラメーターを取るようにします。

それがフレームごとの束と呼ばれる場合、構造を作成し、ポインタを渡す傾向があります(構造体を毎回再構築していないと仮定すると).

1
KPexEA

作業している環境に大きく依存します。javascriptを例に取ります。 JavaScriptでパラメーターを渡す最良の方法は、キー/値のペアを持つオブジェクトを使用することです。実際には、パラメーターは1つしかありません。他のシステムでは、スイートスポットは3または4になります。

最終的に、それはすべて個人の好みに要約されます。

1
Joeri Sebrechts

3は大丈夫、4はガイドラインとして多すぎることに同意します。 3つ以上のパラメーターを使用すると、必然的に複数のタスクを実行することになります。複数のタスクを別々のメソッドに分割する必要があります。

しかし、私が取り組んだ最新のプロジェクトを見ると、例外がたくさんあり、ほとんどの場合、3つのパラメーターに絞ることは困難です。

1
kae

Amazon名声のジェフ・ベゾスによると、 2つのピザ

1
Kevin Pang

平均して、人々は一度に7 +/- 2個の物を頭の中に入れておくことができるという事実は知られています。私はパラメーターでその原理を使用するのが好きです。プログラマーがすべて平均以上の知的な人々であると仮定すると、私はすべての10+が多すぎると思います。

ところで、パラメータが何らかの形で類似している場合、構造体またはクラスではなくベクトルまたはリストに入れます。

1
Milan Babuškov

IMO、長いパラメーターリストの正当性は、データまたはコンテキストが本質的に動的であるということです。printf()を考えてください。可変引数を使用する良い例です。このようなケースを処理するより良い方法は、ストリームまたはxml構造を渡すことです。これにより、パラメーターの数が最小限に抑えられます。

マシンは確かに多数の引数を気にしませんが、開発者は、メンテナンスのオーバーヘッド、単体テストケースの数、および検証チェックも考慮します。また、設計者は長い引数リストが嫌いです。引数が増えると、変更が行われるたびにインターフェイス定義の変更が増えることを意味します。カップリング/凝集についての質問は、上記の側面から湧きます。

0
questzen

オーバーロードが2〜4である限り、必要に応じてより高い位置に上がることができます。

0
Chad Moran

実際の数は、関数のコンテキストで論理的に意味のあるものに本当に依存すると思います。約4〜5個のパラメーターが混雑し始めることに同意します。

フラグを設定する場合、この状況を処理するための優れた方法は、値を列挙し、それらを一緒にORすることです。

0
Jordan Parmer