アプリケーションに値をハードコーディングするのは良い考えですか?または、これらのタイプの値を変更する必要がある場合に動的に呼び出すことは常に正しいことですか?
コメント
回答
はい、ただし 明白 。
実行:
- 定数を使用
- 説明的なを使用変数名
禁止事項:
- 任意のマジックナンバーコードの周りに浮かんでいる
コメント
- どちらがクリーンか、
diameter = 2 * radius
またはdiameter = RADIUS_TO_DIAMETER_FACTOR * radius
?マジックナンバーの方が解決策となる可能性があるコーナーケースが実際にあります。 - 同意できません’私はプログラミングを小説家のように考える傾向があります。あなたはコードを通してあなたのストーリーを語り、人々がロジックを理解できない場合、私の意見ではあなたのコードは無価値になります。その’なぜよく考えられた命名規則が本質的に読みやすさのためであるか。また、マジックナンバーを使用する正当な理由はありません。マジックナンバーを使用することにより、”理由方程式から、理解しにくくしますタンド。例:”直径= 2 * radius “この2つは何のためのものですか?この”直径= RADIUS_TO_DIAMETER_FACTOR *半径”の方がはるかに理にかなっています。
- 直径= 2 *半径は高校の数学。 ” 2 “に名前を付けない理由は、他の値を設定するには、次の法則を変更する必要があるためです。物理学または数学、あるいはその両方。 (一方、PiまたはPlancks定数に名前を付けることは、読みやすくするための良い方法です。)
- @Joonas:Pfft。確かに
diameter = radius << 1
のことですか?diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
の可能性もあると思います。 - どのように’いくつかの
diameter = radius.toDiameter()
回答
このQについて奇妙だと思うこと&これまでのところ、「ハードコード」またはさらに重要な代替手段を明確に定義しようとした人は誰もいません。
tl; dr :はい、値をハードコーディングすることは 良い考えですが、いつするかについての簡単なルールはありません。完全にコンテキストに依存します。
質問では、値に絞り込みます。これは、マジックナンバーを意味します。 しかし、それらが「良いアイデア」であるかどうかの答えは、実際に使用されている目的に関連しています!
「ハードコードされた」のいくつかの例「値は次のとおりです。
-
構成値
私は声明を見るたびにうずくまる
command.Timeout = 600
のように。なぜ600?誰がそれを決めたのですか?以前にタイムアウトになり、根本的なパフォーマンスの問題を修正する代わりに、誰かがタイムアウトをハックとして上げましたか?それとも、実際には、処理時間に対する既知の文書化された予想ですか?これらはマジックナンバーまたは定数であってはならず、構成ファイルまたはデータベースのどこかに外部化されている必要があります。意味のある名前。最適な値は、アプリケーションが実行されている環境によって大部分または完全に決定されるためです。
-
数式
数式は通常、かなり静的である傾向があるため、内部の定数値の性質はそれほど重要ではありません。ピラミッドの体積は(1/3)b * hです。 1または3がどこから来たのか気になりますか?あんまり。以前のコメント投稿者は、
diameter = radius * 2
はおそらくdiameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
よりも優れていると正しく指摘しましたが、これは誤った二分法です。このタイプのシナリオで実行する必要があるのは、関数を作成することです。私はあなたがどのようにして式を思いついたのかを知る必要はありませんが、それでもそれが何のためにあるのかを知る必要があります。上記のナンセンスの代わりに
volume = GetVolumeOfPyramid(base, height)
と書くと、突然すべてがより明確になり、魔法数を内部に置いてもまったく問題ありません em 関数(return base * height / 3
)は、「数式の一部にすぎないことは明らかだからです。ここで重要なのは、もちろん短い関数と単純な関数。これは、10個の引数と30行の計算を持つ関数では機能しません。その場合は、関数の合成または定数を使用してください。
-
ドメイン/ビジネスルール
値が正確に何であるかに依存するため、これは常に灰色の領域です。 ほとんどの場合、定数に変換する候補となるのはこれらの特定のマジックナンバーです。これにより、プログラムロジックを複雑にすることなく、プログラムを理解しやすくなります。テストと
if Age < LegalDrinkingAge
;おそらく 定数なしで何が起こっているのかを理解できますが、説明を使用すると簡単になりますタイトル。これらはまた関数抽象化の候補になる可能性があります(例:
function isLegalDrinkingAge(age) { return age >= 19 }
)。唯一のことは、ビジネスロジックがそれよりもはるかに複雑で、それぞれ20〜30個のパラメータを持つ数十の関数を書き始めるのは意味がないかもしれません。「オブジェクトや関数に基づく明確な抽象化がない場合は、定数に頼っても問題ありません。」 p>注意点は、「税務部門で働いている場合、
AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
と書くのは本当に本当に面倒で正直無意味になるということです。あなたは “あなたをするつもりはないt、あなたは「AttachForm("B-46")
に行きます。なぜなら、これまで働いたことがある、またはこれから働くすべての開発者は、「B-46」が単一の納税者のフォームコードであることを知っているからです。ファイリング何とか何とか何とか-フォームコードはドメイン自体の一部であり、変更されることはないため、「実際にはマジックナンバーではありません。したがって、ビジネスロジックでは定数を慎重に使用する必要があります。基本的に、その「マジックナンバー」が実際にマジックナンバーであるかどうか、またはそれがドメインのよく知られた側面であるかどうかを理解する必要があります。それがドメインである場合は、そこにない限りソフトコーディングしないでください。変更される可能性は非常に高いです。
-
エラーコードとステータスフラグ
Previous action failed due to error code 46
に見舞われたことのある貧しい野郎なら誰でもわかるように、これらはハードコーディングしても問題ありません。 ご使用の言語でサポートされている場合は、列挙型を使用する必要があります。それ以外の場合は、「通常、ファイル/モジュール全体が特定のエラータイプの有効な値を指定する定数でいっぱいになります。決して
return 42
エラーハンドラーで、capiche?言い訳はありません。
おそらくいくつかのシナリオを省略しましたが、ほとんどのシナリオをカバーしていると思います。
つまり、それは時々受け入れられる慣行です。ハードコーディングするものに。ただそれについて怠惰にならないでください。単純な古いずさんなコードではなく、意識的な決定である必要があります。
コメント
- 適切な内訳をありがとう! -ほとんどの人は’私が追加するすべてのオプションを考えていません “環境構成” -ほとんどのデータは構成ファイルまたはデータベースに配置する必要があるため、これらは(ハードコーディングではなく)回避する必要があると思います。これは、MVCまたはMVVMの主力である”データとロジックを分離しておく”の原則に従います。 string TestServerVar = ” foo “; string ProdServerVal = ” bar “;
回答
番号に識別子を割り当てる理由はさまざまです。
- 番号が変更される可能性がある場合は、識別子が必要です。 9のすべてのインスタンスを検索して、8に変更する必要があるかどうかを検討するよりも、NUMBER_OF_PLANETSを見つける方がはるかに簡単です(ユーザーに表示されることに注意してください)。ソフトウェアを別の言語で使用する必要がある場合は、文字列を変更する必要があり、「事前に予測するのは難しい」
- 数値を入力するのは難しいです。 piのような定数の場合、複数の場所で、おそらく不正確に再入力するよりも、1つの最大精度の定義を指定する方が適切です。
- 番号がさまざまな場所で発生する場合。隣接する関数での45の2つの使用法を見て、それらが同じことを意味するかどうか疑問に思う必要はありません。
- 意味がすぐに認識できない場合。誰もが3.14159265 …が何であるかを知っていると想定するのは安全です。それを想定するのは安全ではありません。誰もが重力定数、あるいはpi / 2を認識するでしょう。 (ここでの「全員」は、ソフトウェアの性質によって異なります。システムプログラマは、Unixパーミッションビットなどの8進表現を知っていることが期待できます。海軍/海洋アーキテクチャソフトウェアでは、提案された船体のフルード番号と速度を確認します。 1.1以上であるかどうかを確認してください。これは、作業する必要のある人には完全に自明です。)
- コンテキストが認識できない場合。 1時間に60分があることは誰もが知っていますが、数量が時間値またはレート値であるという即時の兆候がない場合、60で乗算または除算することは不明確な場合があります。 。
これにより、リテラルをハードコーディングするための基準が得られます。リテラルは不変であり、入力が難しくなく、1つの場所またはコンテキストでのみ発生し、認識可能な意味を持つ必要があります。意味がありません。たとえば、0をARRAY_BEGINNINGとして定義したり、1をARRAY_INCREMENTとして定義したりします。
回答
他の回答への追加として。可能な場合は、文字列に定数を使用してください。もちろん、持っていたくない
const string server_var="server_var";
しかし、持っている必要があります
const string MySelectQuery="select * from mytable;";
(特定のテーブルからすべての結果を常に取得したいクエリがあると仮定します)
それ以外は、0以外の任意の数の定数を使用します(通常)。必要に応じて255の権限ビットマスク。使用しないでください
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
代わりに使用してください
const int AllowGlobalRead=255;
もちろん、定数とともに、列挙子をいつ使用するかを知っています。上記のケースはおそらく1つにうまく適合します。
コメント
- typedef enum {state_0 = 0、state_1 = 1、state_2 = 2、.. 。} … ‘笑わないでください、私は’それが行われるのを見ました。その人の頭を濡れた魚で叩きます!
- @もちろんあなたは’もっと
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
- THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
- 文字列の場合、’定数だけが必要なわけではありません。ユーザーに表示される文字列をある種のリソースファイルに入れて(詳細はプラットフォームによって異なります)、別の言語に簡単に変更できるようにします。
- ビジネスロジック関連を使用することもできます。ある種の暗号化または難読化されたリソースファイル内の文字列(SQLクエリなど)。これにより、”好奇心が強い”ユーザーがロジック(またはデータベーススキーマ)をリバースエンジニアリングするのを防ぐことができます。
回答
ハードコーディングの対象によって異なります。ハードコーディングされたものをすべて回避しようとすると、最終的にソフトコーディングの領域になり、作成者だけが管理できるシステムを作成します(これが究極のハードコード)
多くのものが合理的なフレームワークでハードコードされており、機能します。つまり、C#アプリケーションのエントリポイントを変更できないようにする技術的な理由はありません(static void Main )、ただし、どのユーザーにも問題が発生しないハードコーディング( SOの質問を除く)
私が使用するルールは次のとおりです。システム全体の状態に影響を与えることなく、変更できるものと変更するものはすべて、混乱させる必要があります。
つまり、IMHOは、決して変更されないもの(pi、重力定数、数式の定数-球の体積を考えてください。
また、システムに影響を与えるようなものやプロセスをハードコーディングしないのはばかげています。つまり、ユーザーが動的フィールドをフォームに追加できるようにするのは無駄です。追加されたフィールドでメンテナンス開発者が入り、それを機能させるスクリプトを作成する必要がある場合です。また、構成ツールを作成するのはばかげているので(エンタープライズ環境で数回見たことがあります)、ハードコーディングされているものはありませんが、IT部門の開発者だけが使用でき、少しだけ簡単です。 VisualStudioで使用するよりも使用する。
つまり、ハードコーディングする必要があるかどうかは、2つの変数の関数です。
- 値は変化しますか
- 値の変更はシステムにどのように影響しますか
回答
アプリケーションに値をハードコーディングすることは良い考えですか?
値をハードコーディングする値がの場合のみ仕様(仕様の最終リリース)で指定されている、例: HTTPOK応答は常に200
になるため(RFCで変更されない限り)、(一部のコードでは)次のような定数が表示されます。
public static final int HTTP_OK = 200;
それ以外の場合は、プロパティファイルに定数を格納します。
仕様で定数を変更する理由は、仕様で定数を変更するには変更管理が必要なためです。利害関係者は変更を確認し、承認/不承認します。それは一夜にして起こることはなく、承認には数ヶ月/数年かかります。多くの開発者が仕様(HTTPなど)を使用していることを忘れないでください。仕様を変更すると、何百万ものシステムが破壊されます。
回答
- 値が変更される可能性があり、実際に変更される可能性がある場合は、関連する労力が期待収益を超えない限り、可能な限りソフトコーディングします
- 一部の値はできないソフトコデイット;これらの(まれな)ケースでは、ジョナサンのガイドラインに従ってください
回答
気づきましたコードからデータを抽出できるときはいつでも、残っているものが改善されます。新しいリファクタリングに気づき、コードのセクション全体を改善し始めます。
定数の抽出に取り組むのは良い考えです。愚かなルールとは見なさず、コーディングの機会と考えてください。
最大の利点は、コードのグループの唯一の違いである同様の定数を見つける方法です。それらを配列に抽象化することで、一部のファイルをサイズの90%削減し、かなり修正することができました。いくつかのコピー&はその間にバグを貼り付けます。
データを抽出しないことの利点はまだ1つもありません。
回答
最近、MySQL関数をコーディングして、2つの緯度と経度のペア間の距離を適切に計算しました。単にpythagorusを実行することはできません。緯度が極に向かって増加するにつれて経度線が互いに近づくので、ちょっと毛むくじゃらの三角法が関係しています。ポイントは、地球の半径をマイルで表す値をハードコーディングするかどうかについてかなり引き裂かれました。
実際には、緯度と経度の線が月などではるかに接近しているにもかかわらず、私はそれを行うことになりました。そして、私の関数は、木星上のポイント間の距離を大幅に過少報告します。私が構築しているウェブサイトの地球外の場所が入力される可能性はかなり低いと思いました。
コメント
- はい、おそらく、しかし何ですか google.com/moon
回答
言語がコンパイルされているかどうかによって異なります。コンパイルされていない場合は大したことではありません。プログラマー以外の人にとっては少しデリケートな場合でも、ソースコードを編集するだけです。
コンパイル言語でプログラミングしている場合、これは明らかに良い考えではありません。変数が変更された場合、再コンパイルする必要があり、この変数を調整する場合は時間の大きな無駄です。
変数を動的に変更するためにスライダーやインターフェイスを作成する必要はありませんが、できることはテキストファイルだけです。
たとえば、私のogreプロジェクトでは、常に使用しています。構成ファイルに書き込んだ変数をロードするためのConfigFileクラス。
回答
定数が(少なくとも私の意見では)OKである2つの場合:
-
他に何も関係のない定数。これらの定数は、何も変更せずにいつでも変更できます。例:グリッド列のデフォルトの幅。
-
「1週間あたりの日数」など、完全に不変で、正確で、明白な定数。
days = weeks * 7
7
を定数DAYS_PER_WEEK
に置き換えるとほとんど値が得られません。
回答
私はジョナサンに完全に同意しますが、すべてのルールとして例外があります…
「仕様のマジックナンバー:コードのマジックナンバー」
基本的に次のように述べていますそれらの説明的なコンテキストを取得するための合理的な試みの後に仕様に残っているマジックナンバーは、そのようにコードに反映する必要があります。マジックナンバーがコードに残っている場合は、それらを分離し、それらを原点に明確にリンクさせるためにあらゆる努力を払う必要があります。
マップされた値をメッセージに入力する必要がある場合、いくつかのインターフェイスコントラクトを実行しました。データベースから。ほとんどの場合、マッピングはかなり単純で、Jonathanの一般的なガイドラインに適合しますが、ターゲットメッセージの構造が単純にひどい場合があります。構造で渡されなければならなかった値の80%以上は、遠隔システムの仕様によって強制された定数でした。これは、メッセージ構造が巨大であるという事実と相まって、そのような定数を大量に入力する必要がありました。ほとんどの場合、それらは意味や理由を提供せず、「ここにMを置く」または「ここに4.10.53.10100.889450.4452を置く」とだけ言った。それらすべての横にコメントを付けようともしなかったので、結果のコードが読めなくなりました。ただし、これらのマジック値が表示されるコードセクションが適切に分離され、それらを適用する仕様を直接指すように適切な名前が付けられたコンテナ(クラス、パッケージ)があることを確認しました。
それ…それはほとんどすべて明白にすることです…
答え
「地球の値をハードコーディングしている」場合、重力定数は誰も気にしません。プロキシサーバーのIPアドレスをハードコーディングすると、「問題が発生します。
コメント
- earth
の重力定数であるため、数回ハードコーディングすると問題が発生する可能性があります。
- Peter Noone?Hermanから’ s Hermits ?
- 地球の重力加速度は、ほとんどの緯度と高度でほぼ9.81 m / s ^ 2です(もちろん、’石油を探している場合地下、または北極上空でICBMを撮影する場合、重力の変化を知ることは、より多くの10進数の場所にとって非常に重要です)、他の惑星の重力加速度は異なる数値ですが、私が知る限り、重力定数は一定です宇宙の周り。gが可変である場合に変更しなければならない物理学がたくさんあります。
回答
ほとんどありませんが、それはあなたがwiすることは注目に値すると思いますハードコードされた値の複製を開始すると、最も問題が発生します。複製しない場合(たとえば、クラスの実装で1回だけ使用する場合)、定数を使用しないことで問題ない場合があります。
pi
の値がいつ変更されるかはわかりません…