web-dev-qa-db-ja.com

マジックナンバーの排除:「いいえ」と言うのはいつですか?

マジックナンバー(ハードコードされた値)は、特にコメントのないコードのセクションを変更するとき、プログラムで大混乱を引き起こす可能性があることは誰もが知っていますが、どこに線を引きますか?

たとえば、2日間の秒数を計算する関数がある場合、次のように置き換えますか?

seconds = num_days * 24 * 60 * 60

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

どの時点で、ハードコードされた値が何を意味するかが完全に明白であると判断し、それをそのままにしますか?

36
oosterwal

数値リテラルの代わりに記号定数を使用する理由は2つあります。

  1. マジックナンバーが変更された場合のメンテナンスを簡略化します。これはあなたの例には当てはまりません。 1時間の秒数、または1日の時間数が変化することはほとんどありません。

  2. 読みやすさを向上させるため。 「24 * 60 * 60」という表現は、ほとんどの人にとってかなり明白です。 「SECONDS_PER_DAY」もそうですが、バグを探している場合は、SECONDS_PER_DAYが正しく定義されていることを確認する必要があるかもしれません。簡潔に価値があります。

正確に1回だけ出現し、プログラムの他の部分から独立しているマジックナンバーの場合、そのナンバーのシンボルを作成するかどうかの決定は好みの問題です。疑問がある場合は、先に進んでシンボルを作成してください。

こんなことしないで:

public static final int THREE = 3;
40
kevin cline

私はマジックナンバーを持たないというルールを守ります。

ながら

seconds = num_days * 24 * 60 * 60

クランチモードで3〜4週間、1日10時間コーディングした後、ほとんどの場合完全に読み取り可能

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

読みやすくなります。

FrustratedWithFormsDesignerの提案はより優れています:

seconds = num_days * DAYS_TO_SECOND_FACTOR

またはそれ以上

seconds = CONVERT_DAYS_TO_SECONDS(num_days)

あなたが非常に疲れているとき、物事は明白ではなくなります。 防御的なコード

29
Vitor Py

ノーと言う時はほとんどいつもです。ハードコードされた数値を使用する方が簡単だと思うときは、UIレイアウトなどの場所にあります。フォーム上のすべてのコントロールの配置のための定数を作成すると、非常に面倒で面倒になり、そのコードが通常UIデザイナーによって処理される場合、大した問題ではありません。 ... UIが動的にレイアウトされているか、アンカーへの相対位置を使用しているか、手動で記述されている場合を除きます。その場合は、レイアウトに意味のある定数を定義した方がよいと思います。また、「適切な」ものを配置または配置するために、あちこちにファッジファクターが必要な場合は、それも定義する必要があります。

しかし、あなたの例では、24 * 60 * 60 沿って DAYS_TO_SECONDS_FACTOR 優れている。


コンテキストと使用法が完全に明確である場合、ハードコードされた値も問題ないと思います。しかし、これは判断の呼びかけです...

例:

@rmxが指摘したように、0または1を使用してリストが空かどうか、またはループの境界にあるかどうかを確認することは、定数の目的が非常に明確な場合の例です。

数値に意味や目的を特定できない場合は停止します。

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

数字を使うよりも読みやすいです。 (ただし、単一のSECONDS_PER_DAY定数ですが、完全に別の問題です。)

コードを見ている開発者は、コードが何をするかを見ることができると仮定します。しかし、彼らもその理由を知っていると思い込まないでください。あなたの定数が理由を理解するのに役立つなら、それのために行きます。そうでない場合は、しないでください。

ある回答で示唆されているように、定数が多すぎる場合は、代わりに外部構成ファイルを使用することを検討してください。ファイルに定数が数十個あると、読みやすさが正確に向上しないためです。

8
biziclop

HOURS_PER_DAYのような明らかなものに対して定数の使用を促進するために私が見つけた最良の例の1つは次のとおりです。

私たちは、物事が人のジョブキューに留まっている時間を計算していました。要件は大まかに定義され、プログラマーはいくつかの場所で24をハードコーディングしました。結局、実際に1日8時間しか働かないのに、問題に24時間座っていたとしてもユーザーを罰するのは公平ではないことがわかりました。タスクがこれを修正し、他のレポートで同じ問題が発生する可能性があることを確認した場合、24のコードをgrep /検索するのは非常に困難でしたHOURS_PER_DAY

7
bkulyk

私はおそらく次のようなことに「ノー」と言うでしょう:

#define HTML_END_TAG "</html>"

そして間違いなくは「いいえ」と言います:

#define QUADRATIC_DISCRIMINANT_COEF 4
#define QUADRATIC_DENOMINATOR_COEF  2
7
dan04

その数が完全に一定であり、変化する可能性がない限り、それは完全に許容できると思います。したがって、あなたの場合、seconds = num_days * 24 * 60 * 60は問題なく(もちろん、この種の計算をループ内で行うような愚かなことをしないと仮定して)、seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTEよりも間違いなく読みやすくなっています。

このようなことをするのは悪いことです。

lineOffset += 24; // 24 lines to a page

ページにこれ以上行を挿入できなくなった場合や、変更するつもりがない場合でも、代わりに定数変数を使用してください。ある日、あなたを悩ませるために戻ってくるからです。結局のところ、要点は読みやすさであり、CPUでの2サイクルの計算を節約するものではありません。貴重なバイトがすべての価値のために圧迫されたとき、これはもはや1978年ではありません。

4
Neil
seconds = num_days * 24 * 60 * 60

完全に元気です。これらは決して変わらないので、実際には魔法の数字ではありません。

合理的に変化する可能性のある数値、または明らかな意味を持たない数値は、変数に入れる必要があります。つまり、それらのほとんどすべてを意味します。

3
Carra

ある単位から別の単位に値を変換するための定数(マジック値)の作成は避けます。変換する場合は、話すメソッド名を使用します。この例では、これはDayToSeconds(num_days) internal "24"と "60"の意味が明確であるため、メソッドは魔法の値を必要としません。

この場合、秒/分/時間は使用しません。 TimeSpan/DateTimeのみを使用します。

3
KayS

コンテキストをパラメータとして使用して決定する

たとえば、「calculateSecondsBetween:aDay and:anotherDay」という関数がある場合、関数名は非常に代表的なものであるため、これらの数値が何をするかについて多くの説明をする必要はありません。

そして別の質問は、別の方法でそれを計算する可能性はどれですか?時々同じことをする多くの方法があるので、将来のプログラマーを導き、あなたが使用した方法を彼らに示すために、定数を定義することはそれを理解するのに役立ちます。

1
guiman