マジックストリング/数字の使用[終了]


31

これはやや物議を醸すトピックであり、プログラマーと同じくらい多くの意見があると思います。しかし、そのために、ビジネス(または職場)での一般的な慣行を教えてください。

私の職場では、厳密なコーディングガイドラインがあります。その1つのセクションは、マジックストリング/マジックナンバー専用です。状態(C#の場合):

コードでは、記号定数を定義する以外に、数値または文字列のリテラル値を使用しないでください。次のパターンを使用して、定数を定義します。

public class Whatever  
{  
   public static readonly Color PapayaWhip = new Color(0xFFEFD5);  
   public const int MaxNumberOfWheels = 18;  
}

例外があります:値0、1、nullはほとんど常に安全に使用できます。多くの場合、値2および-1も問題ありません。ロギングまたはトレースを目的とした文字列は、この規則から除外されます。リテラルは、意味が文脈から明らかであり、将来の変更の影響を受けない場合に許可されます。

mean = (a + b) / 2; // okay  
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough

理想的な状況は、次の場合にコードの可読性/保守性への影響を示す公式の研究論文です。

  • 魔法の数字/文字列がいたるところにある
  • 魔法の文字列/数字は、一定の宣言によって合理的に(またはさまざまな範囲で)置き換えられます-「合理的に」使用することについて私に怒鳴らないでください
  • 魔法の文字列/数字は、過剰に置き換えられる必要があります(以下の私の例を参照)

私の同僚の1人と議論するときに科学的根拠に基づいた議論をするためにこれをしたいと思います。彼は次のような定数を宣言するようになります:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

別の例は次のようになります(これはJavaScriptで行われます)。

var someNumericDisplay = new NumericDisplay("#Div_ID_Here");

そのIDが1か所でしか使用されていない場合、javascriptファイルの上にDOM IDを貼り付けますか?

次のトピックを読みました
。StackExchange
StackOverflow
Bytes IT Community
さらに多くの記事があり、これらを読んだ後にいくつかのパターンが出現します。

私の質問は、コードで魔法の文字列と数字を使用することですか?可能な場合は、参考文献に裏打ちされた専門家の回答を特に探しています。


2
マジック変数は、その内容に反映されない意味を保持する変数です。整数値「10」は数値10の意味を反映しているため、定数にする必要はありません。スペースとセミコロンについても同様です。一方、値 '%% ?? %%'があり、これがカスタム区切り文字である場合、その内容は区切り文字であるという事実を反映しないため、定数として配置する必要があります。
Jeroen Vannevel

23
NumberTen = 10数字の10は再定義されないため、これは無意味です。MaxRetryCount = 10これには、最大再試行回数を変更したいというポイントがあります。private const char SemiColon = ';'; ダム。private const char LineTerminator = ';'; スマート。
マイク

1
実際の質問は明確ではありません。
Tulainsコルドバ

回答:


89

...私の同僚の1人と議論するとき、次のような定数を宣言することになります。

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

同僚と議論する必要があるのは、リテラルスペースに名前を付けることではなくSpace、定数の名前の選択が貧弱だということです。

コードの仕事は、セミコロン(a;b;c)で区切られたフィールドを含み、スペース(a;b;c d;e;f)で区切られたレコードのストリームを解析することだとしましょう。あなたの仕様書を書いた人が今から1ヶ月後にあなたに電話をしてきて、「間違えた、レコードのフィールドはパイプ記号(a|b|c d|e|f)で区切られている」と言ったら、どうしますか?

同僚が好むvalue-as-nameスキームの下では、リテラル(SemiColon = '|')の値を変更し、SemiColon実際にはセミコロンではないものに引き続き使用するコードを使用する必要があります。それはコードレビューで否定的なコメントを導きます。それを和らげるために、リテラルの名前をtoにPipeSymbol変更して、SemiColontoのすべての出現を変更できPipeSymbolます。そのレート';'では、最初にリテラルセミコロン()を使用しただけかもしれません。それを使用するたびに個別に評価する必要があり、同じ数の変更を行うからです。

定数の識別子、値何であるかではなく、値何をするのかを説明する必要あり、それがあなたの同僚が雑草に左折した場所です。上記のフィールド分割アプリケーションでは、セミコロンの目的はフィールド区切り記号であり、それに応じて定数に名前を付ける必要があります。

private const char FieldSeparator = ';';    // Will become '|' a month from now
private const char RecordSeparator = ' ';
private const int MaxFieldsPerRecord = 10;

このように、フィールドセパレータが変更されると、コードの1行、つまり定数の宣言が変更されます。変更を見ている人は、その1行だけを見て、フィールド区切り文字がセミコロンからパイプ記号に変更されたことをすぐに理解します。定数を使用していたため変更する必要のなかった残りのコードは同じままであり、読者は他に何が行われたかを見るためにコードを掘り下げる必要はありません。


全くもって同じ意見です。数十年前、私は、それぞれ8つの汎用レジスターを使用して、メッセージがセグメントで送信されるプロジェクトに取り組みました。誰かが宣言していました #define one 1 #define two 2 (または英国郵便局コーラル、当時の言語で同等のものは何でも)。ワードは、将来的に長さフィールドがので、バイトではなく、セグメントの数であろうと高い上から来明らかにコードに変更した #define one 8 #define two 16 など
Mawg

3
SemicolonやPipeSymbolのような名前のように馬鹿げているように、スクリプトを使用して一方を他方に変更することは、影響;を受けるすべてをに変更するよりもはるかに簡単です|
ブランディン

特定の文字列リテラルがファイル内で何度も使用されているが、その値以外の意味がない場合はどうでしょうか?たとえば、20の異なるシナリオでマップ内の特定のキーを受信できることをテストする場合、そのように定数を定義する必要がありますか?: public static final String MY_KEY_NAME = "MyKeyName"
ジョーダンマックイーン

1
@JordanMcQueen各リテラルが1回だけ使用され、他の場所では必要ない場合にのみ、ベアリテラルを使用する場合があります。それは各シナリオは、異なるファイル形式を処理するコードであることのようなものだ場合は、各フォーマットは、(例えば、独自の定数を定義する必要がありCSV_RECORD_SEPARATORTSV_RECORD_SEPARATORなど)。
Blrfl

8

セミコロンは既に定数であるため、セミコロンを定数として定義することは冗長です。変わることはありません。

いつか誰かが「用語の変更、+は新しいセミコロンです」と発表するようなものではなく、あなたの同僚は定数を更新するために喜んで急ぎます(彼らは私を笑った-今すぐ見てください)。

一貫性の問題もあります。私は彼のNumberTen定数がすべての人によって使用されないことを保証します(ほとんどのコーダーは気にしないわけではありません)。黙示録が来て「10」がグローバルに9に再スケーリングされた場合、定数を更新してもトリックは行われません10。コード内にリテラルsのヒープが残るため、システムはスコープ内でもまったく予測不能になります「10」が「9」を意味するという革命的な仮定の。

すべての設定をconstとして保存することも、私が考え直したことです。これを軽く行うべきではありません。

これまでのところ、このタイプの使用例は何ですか?ラインターミネータ...最大再試行回数...最大ホイール数...

代償として、デフォルト設定を変更するにはアプリケーションを再コンパイルする必要があり、場合によってはその依存関係さえもコンパイルする必要があります(コンパイル時に数値のconst値がハードコードされることがあります)。

テストとモッキングの側面もあります。接続文字列をconstとして定義しましたが、ユニットテストでデータベースアクセスをモック(偽の接続を確立)することはできません。


4
「それは決して変わらないだろう。」以前はアポストロフィについて考えていました(ASCII値39に永久に結びついています)。アポストロフィを丸くするために使用されるいくつかの古いアプリ。しかし、最近のアプリはそのASCII値を古いアプリと互換性のあるまっすぐなアポストロフィとして扱い、代わりに人々はカールしたマークの異なるグリフの表示と互換性のあるアプリに(左一重引用符、Unicode 8217)をしばしば使用します。ヨーロッパではアメリカ人が小数点としてピリオドを使用するのと同じようにコンマを使用しているため、「not ... ever」と宣言するのを少しためらっています。
TOOGAM

@TOOGAMだけでなく、あなたの例の詰めを持つDecimalPoint定数を-ではなく、CommaまたはPeriod定数。前者は、値の機能、役割、または目的を示しています。「セミコロン」または「コンマ」はそのカテゴリに該当しません。
コンラッド・モラウスキー

これは小数点の例にも当てはまります。ただし、アポストロフィの例は、カンマ(またはセミコロン)と同様の(または同一の)カテゴリのようです。
-TOOGAM

@KonradMorawskiセミコロンは、文字列の分割や行の終了など、多くの目的に使用できます。定数の命名に使用するのは、その値(値ではない)です。将来の変更、つまり明日は20レコードを処理できるようにします。そのため、NumberTenという名前の定数はコンテキストから外れますが、maxRecordは問題ありません。
MaxZoom

5
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

あなたの同僚は、デイリーWTFエントリーを目指しています。これらの定義は愚かで冗長です。ただし、他の人から指摘されているように、次の定義は愚かでも冗長でもありません

private const char StatementTerminator = ';';
private const char Delimiter = ' ';
private const int  BalanceInquiryCode = 10;

「魔法の」数字と文字列は、そのリテラル値を超えた意味を持つ定数です。定数に10「10のこと」を超える意味がある場合(特定の操作またはエラー条件のコードとして)、それが「魔法」になり、その抽象的な意味を説明するシンボリック定数に置き換える必要があります。

シンボリック定数は、意図を明確に説明するだけでなく、リテラルのスペルを間違えた場合の頭痛の種を軽減します。1行のコードの「CVS」から「CSV」への単純な転置は、単体テストとQAを経て本番環境に移行し、特定の操作が失敗する原因となりました。はい、明らかにユニットとQAテストは不完全であり、それはそれ自体の問題ですが、シンボリック定数を使用することで、その胸焼けを完全に回避できます。


3

論争の余地はないはずです。ポイントは、マジックナンバーを使用するかどうかではなく、読み取り可能なコードを持つことです。
違いを考えてみましょう:if(request.StatusCode == 1)if(request.HasSucceeded)。この場合、後者の方がはるかに読みやすいと主張しますが、それは、のようなコードを使用できないという意味ではありませんint MaxNumberOfWheels = 18

PS:これがコーディングガイドラインが嫌いな理由です。開発者は、このような判断呼び出しを行えるほど十分に成熟している必要があります。神が誰を知っているかによって形成されたテキストに任せるべきではありません。


13
ドライバーは、運転している道路のどちら側で判断できるほど成熟している必要があります;)
コンラッド・

2
判断呼び出しの結果は、成熟した開発者の間でも異なる可能性があるため、任意のコーディングガイドラインでさえ一貫性を通じて読みやすさを向上させることを目的としています。これは、定数NumberTenを作成しても意味がないという事実とは無関係です。
マイクパートリッジ

1
私は彼らが正式であるか、印を押されるなどする必要はないと主張しません。しかし、あなたは今あなたのコメントを削除しましたStefan :)
コンラッド・

1
@StefanBilliet-全然。私のポイントは、一貫性によって読みやすさが向上することです。ここでの問題は、コーディングのガイドラインそのものではなく、誤解によって極端にされたガイドラインです。
マイクパートリッジ

@MikePartridgeたぶん、詳しく説明する必要がありました。私が見てきたコーディングガイドラインは、誰かがどこかでは、ソフトウェアが書かれるべきと思った方法についての一般的なルールブックの動向によります、というよりも、あなたとコンラートのような契約は、おそらく:-)考えている
ステファンBilliet
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.