クリーンなコード:いくつかのパラメーターを持つ関数[終了]


49

Robert C. MartinによるClean Codeの最初の章を読みましたが、かなり良いように思えますが、疑問があるのですが、ある部分では、関数のパラメーターが少ないほど良い(認知的に)ことは言及されています可能な限り、3つ以上のパラメータが関数には大きすぎることを示唆しています(私は非常に誇張されており、理想的です)ので、私は疑問に思い始めました...

グローバル変数を使用し、関数に多くの引数を渡すという慣習はどちらも悪いプログラミング慣行ですが、グローバル変数を使用すると、関数のパラメーターの数を大幅に減らすことができます...

だから私はあなたがそれについて考えることを聞きたかったのですが、関数のパラメータの数を減らすためにグローバル変数を使う価値はありますか?どのような場合になりますか?

私が思うに、それはいくつかの要因に依存しているということです:

  • ソースコードのサイズ。
  • 関数の平均のパラメーターの数。
  • 関数の数。
  • 同じ変数が使用される頻度。

私の意見では、ソースコードのサイズが比較的小さい場合(600行未満のコードなど)、多くの関数があり、同じ変数がパラメータとして渡され、関数には多くのパラメータがあり、グローバル変数を使用する価値がありますが、知りたい...

  • 私の意見を共有しますか?
  • ソースコードが大きい他のケースなどについてどう思いますか?

PS。私はこの投稿を見ました、タイトルは非常に似ていますが、彼は私が知りたいことを尋ねません。


144
代替手段はグローバルだとは思いませんが、代わりに引数をオブジェクトに統合します。それはおそらくpostLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)、の臭いバージョンである提案の多くですpostLetter(Address address)。本を読み続けてください、そういうことを願っています。
ネイサンクーパー

3
@DocBrownボブおじさんが3つ以上のパラメーターを使用してはいけないと言っているように、グローバル変数を正しく使用することでこの問題を回避できるという意味ですか?:-)おそらく著者は、この問題を回避するためのより良い方法があることを知らないと思います-以下の回答で述べたように。
bytedev

9
経験則(nの任意の値)は、n個以下のパラメーターであり、ダイヤモンドにはエッチングされません。良いアドバイスを任務と間違えないでください。一般に、多くのパラメーターは、1つの関数/メソッドであまりにも多くのコードの匂いがします。人々は、余分な呼び出しの追加オーバーヘッドを避けるために、複数の機能に分割することを避けていました。これほどパフォーマンスが集中するアプリケーションはほとんどなく、プロファイラーは余分な呼び出しを回避する必要があるときと場所を通知できます。
ジャレッドスミス

14
これは、この種の判断のないルールの何が悪いのかを示しています。判断のない「解決策」への扉を開きます。関数に多くの引数がある場合、通常は関数だけでなく、その関数が使用されているコンテキストの最適でない設計を示している可能性があります。解決策(必要な場合)は、コードをリファクタリングすることです。私はあなたにそれを行う方法に関する単純で一般的な、判断のないルールを与えることはできませんが、それは「N個以下の引数」が良いルールであることを意味しません。
-sdenham

4
関数に対するパラメーターが多すぎる場合、それらの一部が関連していて、複数のデータをカプセル化する単一のパラメーターになるオブジェクトにグループ化する必要がある可能性があります。ここには3番目のオプションがあります。

回答:


113

私はあなたの意見を共有しません。私の意見では、グローバル変数を使用することは、あなたが説明した品質に関係なく、より多くのパラメーターよりも悪い習慣です。私の推論では、パラメータを増やすとメソッドの理解が難しくなる可能性がありますが、グローバル変数は、テスト性の低下、同時実行性バグ、密結合など、コードに多くの問題を引き起こす可能性があります。関数がいくつのパラメーターを持っているとしても、グローバル変数と同じ問題は本質的にありません。

...同じ変数がパラメーターとして渡されます

それは可能な設計臭いこと。システム内のほとんどの関数に同じパラメーターが渡されている場合、新しいコンポーネントを導入することで対処する必要がある横断的な懸念がある可能性があります。同じ変数を多くの関数に渡すことは、グローバル変数を導入する正当な理由になるとは思いません。

質問のある編集で、グローバル変数を導入するとコードの可読性が向上する可能性があることを示しました。同意しません。グローバル変数の使用は実装コードでは隠されていますが、関数パラメーターは署名で宣言されています。関数は理想的には純粋でなければなりません。それらはパラメータでのみ動作し、副作用はありません。純粋な関数がある場合は、1つの関数だけを見て、その関数について推論できます。関数が純粋ではない場合、他のコンポーネントの状態を考慮する必要があり、推論するのがはるかに難しくなります。


わかりました、他の意見を聞くのは良いことですが、デザインの匂いについて、私は人工知能の方法によって解決されるC問題でプログラミングしており、ほとんど常に同じ行列、配列または変数を使用する多くの関数を使用する傾向があります関数にパラメーターとして渡します)、これらの変数を一般的な概念/構造体やユニオンのようなものの中に入れることができないので、より良いデザインを作成する方法がわかりませんので、これを言っています、そのため、この場合にグローバル変数を使用する価値があると思いますが、おそらく間違いです。
OiciTrap

1
それはデザインの問題のようには聞こえません。関数にパラメーターを渡すのが最善の設計だとまだ思っています。あなたが説明しているようなAIシステムでは、システムの各部をテストするためのユニットテストを書くことが有用であり、それを行う最も簡単な方法はパラメーターを使用することです。
サミュエル

96
パラメータが多いとサブルーチンが理解しにくくなり、グローバル変数はプログラム全体、つまりすべてのサブルーチンが理解しにくくなります。
ヨルグWミットタグ

2
一部の関数が12個以上のパラメーターを取るコードベースを維持しています。それは膨大な時間の浪費です。関数を呼び出す必要があるたびに、別のウィンドウでそのファイルを開く必要があるので、パラメーターを指定する必要がある順序を知ることができます。インテリセンスのようなものを提供するIDEを使用した場合、またはパラメーターに名前を付けた言語を使用した場合、それほど悪くはありませんが、これらすべての関数で12個のパラメーターの順序を覚えているのは誰ですか?
ジェリージェレミア

6
答えはそれが言っていることで正しいが、それでもOPは「クリーンコード」の推奨事項についての誤解を当然のことと考えているようだ。その本では、関数パラメータをグローバルに置き換えることは推奨されていないと確信しています。
Doc Brown

68

ペストのようなグローバル変数を避けるべきです。

引数の数(3や4など)に強い制限を設けることはしませんが、可能であれば、引数を最小限に抑える必要があります。

structs(またはC ++のオブジェクト)を使用して、変数を1つのエンティティにグループ化し、それを(参照により)関数に渡します。通常、関数は、構造体またはオブジェクト(いくつかの異なるものを含む)を、関数に何かを行うように指示する他のいくつかのパラメーターと共に渡しますstruct

香りの良い、きれいな、モジュール式のコードの場合、単一の責任原則に固執するようにしてください。それを構造体(またはオブジェクト)、関数、およびソースファイルで行います。そうすれば、関数に渡されるパラメーターの自然数は明らかです。


5
構造体に隠された数十のパラメーターを渡すことと明示的に渡すことの主な違いは何ですか?
ルスラン

21
@Ruslan Cohesion。
abuzittin gillifirca

9
また、数十個のパラメーターではなく、1つのパラメーターをサブ関数に渡すことができるため、関数をより小さな関数にリファクタリングする可能性が高くなります。また、位置引数を使用すると、パラメーターを混同するリスクが少なくなります。
ハンスオルソン

8
それは問題ありませんが、構造体の一貫性を確保する必要があります-構造体にグループ化されたパラメーターが「関連」していることを確認してください。状況によっては複数のStructを使用する場合があります。
アンドリュードッズ

8
@abuzittingillifircaあなたは自動的に凝集力を得ることはありません。構造体にパラメーターを配置する唯一の正当化が特定の関数にパラメーターを渡すことである場合、凝集はおそらく幻想的です。
-sdenham

55

私たちは、構文ではなく認知負荷について話している。質問は... このコンテキストのパラメーターと何ですか?

パラメータは、関数の動作に影響を与える値です。パラメータが多いほど、取得できる値の組み合わせが多くなり、関数に関する推論が難しくなります。

その意味で、関数が使用するグローバル変数パラメーターです。これらは、署名には表示されないパラメーターであり、構成の順序、アクセス制御、および残留磁気の問題があります。

上記のパラメーターが「横断的関心事」と呼ばれるもの、つまりすべてが使用するが何も変更しないプログラム全体の状態(ロギングオブジェクトなど)でない限り、関数パラメーターをグローバル変数に置き換えないでください。それらはまだパラメーターですが、厄介です。


11
あなたにとって+1、それはトイレでもトイレでも同じです。羊の服を着たオオカミを指摘する素晴らしい仕事。
ジャレッドスミス

1
+1は、多くのパラメーターとグローバル変数の両方が悪いことを述べているためです。しかし、私は何かを明確にしたい。ほとんどの言語では、プリミティブパラメータはデフォルトで値で渡されます(Java)が、他の言語では値で明示的に渡すことができます(PL / SQL)。一方、グローバルプリミティブは常に参照によってアクセスされます(つまり)。したがって、少なくともプリミティブ型のパラメータは、グローバル変数よりも常に安全です。もちろん、2つまたは3つ以上のパラメーターを持つことは臭いですが、12のパラメーターを持つことは、リファクタリングするべき大きな臭いです。
Tulainsコルドバ

4
絶対に、グローバル変数は隠されたパラメーターです。
ビルK

+1おわかりのように、グローバル変数に依存してデータを渡すMATLABシミュレーションを見てきました。どの変数がどの関数のパラメーターであるかを判断するのが非常に困難だったため、結果はまったく読めませんでした。
コートアンモン

34

私見あなたの質問は誤解に基づいています。「クリーンコード」では、Bob Martinは繰り返し関数のパラメーターをグローバルに置き換えることを提案していません。これは本当にひどいアドバイスになります。彼は、関数のクラスのプライベートメンバー変数でそれらを置き換えることをお勧めします。そして彼はまた、小さくて凝集性のあるクラス(通常、言及したコードの600行よりも小さい)を提案しているため、これらのメンバー変数は間違いなくグローバルではありません。

したがって、600行未満のコンテキストで「グローバル変数を使用する価値がある」という意見がある場合、ボブおじさんの意見を完全に共有します。もちろん、「最大で3つのパラメーター」が理想的な数であり、このルールが小さなクラスであってもメンバー変数が多すぎる場合は、議論の余地があります。私見これはトレードオフです、どこに線を引くかについての厳格なルールはありません。


10
なぜ実際の引数と一緒に生きるのではなく、コンストラクタにパラメータを詰め込んでクラスをステートフルにすることを好むのか、私は理解していません。これは常に、複雑さの大幅な増加として私を驚かせました。(私はこれを見てきた実際の生活の例では、依存性注入と組み合わせることは不可能近付いプログラムを介してデータベースの状態を追跡しようとして作られたデータベース接続オブジェクト、である。)しかし、おそらくクリーンコードは、その特定に言ってより多くを持っています件名。もちろん、グローバルは物事をステートフルにするという点でさらに悪い選択肢です。
jpmc26

2
@ jpmc26:クラスが大きくなり、メンバー変数が多くなりすぎた場合にのみ、「複雑さの大幅な増加」を得るため、結果はもはや凝集性ではありません。
Doc Brown

4
応答は、多くのクラスに分散している状態の管理の難しさ(可変性さえあるかもしれません)を無視していると思います。関数が引数だけでなく、オブジェクトの構築方法(またはその存続期間中に変更される方法)にも依存する場合、特定の呼び出しを行うときの現在の状態を理解することは難しくなります。ここで、呼び出しが何をするかを把握するために、別のオブジェクトの構成を追跡する必要があります。インスタンス変数を追加すると、オブジェクトを構築してすぐに破棄しない限り、プログラムの状態の量が積極的に増加しますか?
jpmc26

3
@ jpmc26リファクタリング時に定期的に使用するパターンの1つは、コンストラクターがコンテキストの設定のように動作し、メソッド引数がアクションに固有であるということです。オブジェクトが保持する状態は決して変わらないため、オブジェクトは完全にステートフルではありませんが、これらの一般的なアクションをこのコンテナのメソッドに移動すると、これが使用されている場所で可読性が大幅に向上します(コンテキストは一度だけ設定され、Pythonのコンテキストマネージャに似ています)オブジェクトのメソッドに対して複数の呼び出しが行われます。
イズカタ

3
+1メンバー変数はグローバル変数ではないことを明確に言うため。多くの人がそうだと思います。
Tulainsコルドバ

34

多くのパラメータを持つことは望ましくないと見なされますが、実際の問題を解決するのではなく、新しい問題が発生するため、それらをフィールドまたはグローバル変数に変えることは非常に悪いことです。

多くのパラメータを持つこと自体は問題ではありませんが、問題が発生する可能性があるという症状です。この方法を検討してください:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

7つのパラメーターを持つことは、明確な警告サインです。根本的な問題は、これらのパラメーターが独立していないが、グループに属していることです。leftそして、topとして一緒に属しPosition-構造、lengthおよびheightなどSizeの構造、およびredblueおよびgreenなどColorの構造。そして、おそらくColor透明性はBrush構造に属しますか?おそらくPosition、そしてSize一緒にRectangle構造に属している場合、その場合PaintRectangle代わりにオブジェクト上のメソッドに変えることを検討することもできますか?したがって、次のようになる可能性があります。

Rectangle.Paint(brush);

任務完了!しかし重要なことは、実際に全体の設計を改善したことであり、パラメーターの数の削減はこの結果です。根本的な問題に取り組むことなく、パラメーターの数を減らすだけの場合、次のようなことを行うことができます。

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

ここでは、パラメータ数の同じ削減を達成しましたが、実際には設計を悪化させました

結論:プログラミングのアドバイスと経験則については、根本的な理由を理解することが本当に重要です。


4
+1素晴らしく、建設的で、理解可能で、非理論的な答え。
AnoE

1
言うまでもなく、地獄とは、長さと高さの両方の属性を持つ「正方形」のことです。:)
ワイルドカード

1
+1は、いくつかの答え(つまり、関数呼び出しの前にいくつかの構造/オブジェクトへの多くの割り当て)によって暗示される明らかな3番目の方法が良くないことを認めたためです。
benxyzzy

@Wildcard:ありがとう、問題を混乱させないために「長方形」に変更しました!
ジャックB

7

関数のパラメーターの数を減らすためにグローバル変数を使用する価値があるかどうか?

ない

この本の最初の章を読みました

本の残りを読みましたか?

グローバルは単に隠されたパラメーターです。彼らは別の痛みを引き起こします。しかし、それでも痛みです。このルールを回避する方法を考えるのをやめてください。それに従う方法を考えてください。

パラメータとは何ですか?

ものです。きれいにラベル付けされた箱の中。何でも入れられるのに、何箱持っているのが重要なのですか?

送料と手数料です。

Move(1, 2, 3, 4)

あなたはそれを読むことができると教えてください。続けてみてください。

Move(PointA, PointB)

それが理由です。

このトリックは、パラメータオブジェクトの導入と呼ばれます

そして、はい、あなたがしているすべてがパラメータを数えることであるならば、それはただのトリックです。あなたが数えるべきものは、アイデアです!抽象化!一度にどれくらい考えさせてくれますか?複雑にしないでおく。

これは同じカウントです:

Move(xyx, y)

わー!それは恐ろしいです!ここで何が間違っていたのですか?

アイデアの数を制限するだけでは不十分です。それらは明確なアイデアでなければなりません。一体何がxyxですか?

今、これはまだ弱いです。これについて考えるより強力な方法は何ですか?

関数は小さくなければなりません。それより小さくありません。

ボブおじさん

Move(PointB)

本当に必要な以上のことを関数に行わせるのはなぜですか?単一の責任原則は、クラスだけのものではありません。真剣に、アーキテクチャ全体を変更するだけで、1つの機能が、他のパラメータでは使用できない10の関連パラメータを含む過負荷の悪夢に変わるのを防ぐことができます。

関数内の最も一般的な行数が1であるコードを見てきました。まじめに。私はあなたがそのように書かなければならないと言っているわけではありませんが、このルールに従うことができる唯一の方法はグローバルだと言ってはいけません。その機能を適切にリファクタリングすることから抜け出すのをやめてください。あなたができることを知っています。いくつかの機能に分類される場合があります。実際には、いくつかのオブジェクトに変わる可能性があります。地獄では、その一部を完全に異なるアプリケーションに分割することもできます。

本はあなたのパラメータを数えるように言っていません。それはあなたが引き起こしている痛みに注意を払うように言っています。痛みを修正するものはすべて問題を修正します。あなたが単に一つの痛みを別の痛みと交換しているときだけに注意してください。


3
「本の残りを読みましたか?」あなたの質問は私の投稿の最初の8語で答えられます
...-OiciTrap

私は完全に同意します-ポイントは問題を小さな断片に分解することです。オブジェクトは、これらのピースを整理してグループ化するのに非常に役立ちます。また、接続されていない多数のピースではなく、単一の概念単位をパラメーターとして渡すこともできます。3つ以上のパラメーターを持つメソッドを見ると不安になります。5は、私の設計がくだらないことになったことを示しており、リファクタリングをもう1回行う必要があります。パラメーターカウントなどの設計上の問題を解決するために見つけた最良の方法は、単純に小さく単純な単位(クラス/メソッド)にリファクタリングすることです。
ビルK

2
この答えのトーンは改善される可能性があります。それは非常に突然で厳しいものとして読みます。例:「教えてください。読み進めてください。続けてください。」は非常に攻撃的に見え、「上/下の2つの関数呼び出しのうち、どちらが読みやすいですか?」と書き直すことができます。攻撃せずにポイントを取得しようとする必要があります。OPはただ学習しようとしています。
カイルA

OPも目を覚まそうとしていることを忘れないでください。
candied_orange

4

パラメーターを減らすためにグローバル変数を使用することはありません。その理由は、グローバル変数はどの関数/コマンドでも変更できるため、関数の入力が信頼できなくなり、関数が処理できる範囲外の値になりやすいためです。関数の実行中に変数が変更され、関数の半分の値が他の半分と異なる場合はどうなりますか?

一方、パラメーターを渡すと、変数のスコープが独自の関数のみに制限され、関数が呼び出された後にパラメーターを変更できるようになります。

パラメーターの代わりにグローバル変数を渡す必要がある場合は、コードを再設計することをお勧めします。

ちょうど私の2セント。


「グローバル変数を使用してパラメーターを減らすことはありません」と完全に同意します。不必要な結合を作成します。
bytedev

2

私はこれについてボブおじさんと一緒にいますが、3つ以上のパラメータは避けるべきものであることに同意します(関数で3つ以上のパラメータを使用することはほとんどありません)。単一の関数に多数のパラメータを設定すると、メンテナンスの問題が大きくなり、おそらく関数が多すぎる/多すぎる責任を負っています。

オブジェクト指向言語のメソッドで3つ以上を使用している場合、パラメーターが何らかの形で互いに関連していないことを考慮する必要があります。したがって、実際にオブジェクトを渡す必要がありますか?

また、より多くの(より小さい)関数を作成すると、関数のパラメーターが3つ以下になる傾向があることに気付くでしょう。抽出関数/メソッドはあなたの友人です:-)。

より多くのパラメータを持つラウンドを取得する方法としてグローバル変数を使用しないでください!それは悪い習慣をさらに悪いものと交換することです!


1

多くの関数パラメーターの有効な代替手段は、パラメーターオブジェクトを導入することです。これは、(ほとんど)すべてのパラメーターを他の多くのメソッドに渡す合成メソッドがある場合に便利です。

単純なケースでは、これはプロパティとして古いパラメーターのみを持つ単純なDTOです。


1

グローバル変数を使用することは常にコーディングの簡単な方法のように思えますが(特に小さなプログラムの場合)、コードを拡張するのが難しくなります。

はい、配列を使用して1つのエンティティのパラメーターをバインドすることにより、関数内のパラメーターの数を減らすことができます。

function <functionname>(var1,var2,var3,var4.....var(n)){}

上記の関数は編集され、[連想配列を使用]に変更されます。

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

robert bristow-johnsonの答えに同意します。構造体を使用して、単一のエンティティにデータをバインドすることもできます。


1

PHP 4の例を使用して、次の関数のシグネチャを見てくださいmktime()

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

分かりにくいと思いませんか?この関数は「時間の作成」と呼ばれますが、3つの時間パラメーターだけでなく、日、月、年のパラメーターを取ります。彼らがどの順番に入ったのかを覚えるのはどれくらい簡単ですか?表示されたらどうしますmktime(1, 2, 3, 4, 5, 2246);か?他に言及することなく、それを理解できますか?224624時間の「22:46」と解釈されますか?他のパラメーターはどういう意味ですか?オブジェクトとしては良いでしょう。

PHP 5に移行すると、DateTimeオブジェクトがあります。そのメソッドには、と呼ばれる2つのメソッドがsetDate()ありsetTime()ます。その署名は次のとおりです。

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

パラメーターの順序が最大から最小に変わることをまだ覚えておく必要がありますが、それは大きな改善です。6つのパラメーターすべてを一度に設定できる単一のメソッドはないことに注意してください。これを行うには、2つの別個の呼び出しを行う必要があります。

ボブおじさんが言っているのは、平らな構造を避けることです。関連するパラメーターは1つのオブジェクトにグループ化する必要があります。パラメーターが3つ以上ある場合は、そこに疑似オブジェクトがある可能性が高いため、適切なオブジェクトを作成してさらに分離することができます。PHPは別の持っていませんがDateTimeクラスを、あなたがすることを検討することもできDateTime、本当に含まれているDateオブジェクトとTimeオブジェクトを。

次のような構造になる可能性があります。

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

毎回2つまたは3つのパラメーターを設定することは必須ですか?時間または日だけを変更したい場合は、簡単に変更できます。はい、各パラメーターが他のパラメーターと連動することを確認するためにオブジェクトを検証する必要がありますが、とにかく以前はそうでした。

最も重要なことは、理解しやすく、したがって保守しやすいですか?一番下のコードブロックは単一のmktime()関数よりも大きいですが、理解しやすいと私は主張します。プログラマーでなくても、それが何をするのかを問題なく解決できます。目標は、常に短いコードまたは賢いコードではなく、より保守可能なコードです。

ああ、グローバルを使用しないでください!


1

ここでは多くの良い答えがありますが、ほとんどはその点に取り組んでいません。なぜこれらの経験則ですか?それは範囲に関するものであり、依存関係に関するものであり、適切なモデリングに関するものです。

引数のグローバルは、あなたがそれを単純にしたように見えるだけで、実際には複雑さを隠しただけなので、より悪いです。プロトタイプにはもう表示されませんが、それを認識する必要があります(もう表示するために存在しないため、これは困難です)。関数のロジックに頭を悩ましても、助けにはなりません。背中の後ろに干渉する他の隠されたロジックである。あなたのスコープはあちこちに行きました、そして、何でもあなたの変数を混乱させることができるので、あなたは何にでも依存を導入しました。良くない。

関数を維持するための主なことは、プロトタイプを見て呼び出して、その機能を理解できることです。したがって、名前は明確で明確でなければなりません。しかし、また、議論が多ければ多いほど、それが何をするのかを把握するのが難しくなります。それはあなたの頭の範囲を広げ、あまりにも多くのことが起こっているので、数を制限したいのはこのためです。ただし、どのような議論を扱っているかが重要であり、他の議論よりも悪いものもあります。大文字と小文字を区別しない処理を可能にする追加のオプションのブール値は、関数を理解しにくくすることはないので、大したことはしたくないでしょう。補足として、enumはブール値よりも優れた引数を作成します。これは、enumの意味が呼び出しで明らかであるためです。

典型的な問題は、膨大な数の引数を使用して新しい関数を作成することではなく、解決している問題が実際にどれほど複雑であるかをまだ理解していない場合は、ほんのわずかです。プログラムが進化するにつれて、引数リストは徐々に長くなる傾向があります。モデルが頭に浮かんだら、それはあなたが知っている安全な参照であるので、それを保持したいです。しかし、振り返ってみると、モデルはそれほど大きくないかもしれません。ロジックの1つ以上のステップを逃し、1つまたは2つのエンティティを認識できませんでした。「OK ...やり直してコードをリファクタリングするのに1、2日費やすか、...この引数を追加して、結局は正しいことを実行して完了させることができます。今のところ。このシナリオでは。このバグをプレートから取り除いて、付箋を完了に移動できるようにします。」

2番目のソリューションを使用する頻度が高いほど、追加のメンテナンスはより高価になり、リファクタリングはより難しく魅力のないものになります。

既存の関数の引数の数を減らすためのボイラープレートソリューションはありません。それらを化合物にグループ化することは、実際に物事を簡単にするものではなく、カーペットの下の複雑さを拭く別の方法です。正しく行うには、コールスタック全体を再度確認し、不足しているものや間違っているものを認識する必要があります。


0

数回、一緒に送信された多くのパラメーターをグループ化することで改善されることがわかりました。

  • 一緒に使用される概念のこの集合に良い名前を付けることを強制します。これらのパラメーターを一緒に使用する場合、関係がある可能性があります(または一緒に使用しないでください)。

  • 一度オブジェクトを使用すると、私は通常、この明らかに一見するとわかりやすいオブジェクトの一部の機能を移動できることに気付きます。通常、テストは簡単で、優れた凝集力と低いカップリングにより、物事はさらに改善されます。

  • 次に新しいパラメータを追加する必要があるときは、多くのメソッドのシグネチャを変更せずにそれを含めるのに最適な場所があります。

したがって、100%動作しない場合がありますが、このパラメーターのリストをオブジェクトにグループ化する必要があるかどうかを自問してください。そしてお願いします。オブジェクトの作成を避けるため、Tupleのような型指定されていないクラスを使用しないでください。オブジェクト指向プログラミングを使用しているので、必要に応じてさらにオブジェクトを作成してもかまいません。


0

すべての敬意を払って、関数内に少数のパラメーターを持つという点を完全に見逃していると確信しています。

脳は一度に多くの「アクティブな情報」しか保持できず、関数にn個のパラメーターがある場合、簡単かつ正確に脳内に必要な「アクティブな情報」がn個以上あるという考え方です。コードの一部が何をしているのかを理解する(Steve McConnell、Code Complete(はるかに優れた本、IMO))、メソッド本体の7つの変数について同様のことを言っている能力はあなたの頭の中ですべてをまっすぐに保ちます)。

変数の数が少ないという点は、このコードで作業するための認知要件を小さく保つことができるため、より効率的に作業(または読み取り)できます。この副次的な原因は、適切にファクタリングされたコードのパラメータが少なくなる傾向があることです(たとえば、ファクタリングが不十分なコードは、大量のものを混乱にグループ化する傾向があります)。

値の代わりにオブジェクトを渡すことで、おそらくあなたの脳の抽象化レベルを得ることができます。なぜなら、今ではイエスを実現する必要があるからです

グローバル変数を使用しようとすると、完全に間違った方向に進んでしまいます。関数のパラメーターが多すぎるという問題を解決できなかっただけでなく、その問題を取り、頭の中で持ち歩かなければならないはるかに優れた問題に投げ入れました。

機能レベルだけで作業するのではなく、プロジェクトのグローバルスコープについても考慮する必要があります(勇気、なんてひどいのでしょう!私は震えています...)。関数の前にすべての情報さえありません(がらくた、そのグローバル変数名は何ですか?)(この関数を呼び出した後、他の何かによってこれが変更されないことを望みます)。

グローバルスコープの変数は、プロジェクトで見られる非常に最悪のもの(大規模または小規模)の1つです。これらは、適切なスコープ管理の障害を示します。これは、プログラミングの非常に基本的なスキルです。彼ら。あります。悪の。

関数からパラメーターを移動してグローバルに配置することで、あなたは自分自身を床(または脚、顔)で撃ちました。そして、神はあなたがこのグローバルを他の何かのために再利用できることをあなたが決めることを禁じます...私の心は思考に震えます。

全体の理想は、物事を管理しやすくすることであり、グローバル変数はそうするつもりはありません。私は彼らがあなたが反対方向に行くためにできる最悪のことの1つであると言うまで行きます。


-1

インターフェイス間の摩擦を最小限に抑えるための非常に効果的なアプローチ(JavaScript)を見つけましたすべてのモジュール、特に単一のparam関数に対して均一なインターフェイスを使用してください

複数のパラメーターが必要な場合:単一のオブジェクト/ハッシュまたは配列を使用します。

私と一緒に耐えて、私はトローリングしないことを約束します...

「単一のパラメータfuncは何が良いのか」または「1つの配列funcと複数の引数funcに違いはありますか?」と言う前に

はい、そうです。おそらく視覚的には微妙ですが、違いはたくさんあります。ここで多くの利点を探ります

どうやら一部の人々は3が正しい議論だと考えています。それは2だと思う人もいます。まあ、それは「どのパラメーターがarg [0]に入るの?」インターフェイスをより厳密な宣言で制約するオプションを選択する代わりに。

私はもっ​​と過激な立場を主張していると思います:位置引数に頼らないでください。私はそれが壊れやすいと感じており、いまいましい議論の位置に関する議論につながっています。それをスキップして、関数と変数の名前についての避けられない戦いに向かって右に進んでください。😉

まじめな話ですが、ネーミングが落ち着いた後、次のようなコードになることを願っています。

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})


6
名前付き引数を偽造することは、実際には1つの引数だけを渡すわけではありません。
JDługosz

私が着手した目標を達成した場合、なぜそれは「偽物」ですか?名前付き引数に高い優先順位を付けています。位置引数はコードの呼び出しには明らかではないため、開発者は名前付き関数の数を覚える必要があるため、どのパラメーターがどこにあり、どのパラメーターであるかを覚えておくと役に立ちません。...最終的には、オプションの後に必要なパラメータを追加します。幸運なことに、そのカードの家を文書化してアップグレードします。
ダン・レヴィ

2
名前付きパラメーターは強化学習のトリックでもあります-人間は単語のコレクションにより多くの意味を付けます。
ダン・レヴィ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.