Ist es jemals eine gute Idee, Werte in unseren Anwendungen fest zu codieren?


45

Ist es jemals eine gute Idee, Werte in unseren Anwendungen festzukodieren? Oder ist es immer richtig, solche Werte dynamisch aufzurufen, wenn sie sich ändern müssen?


2
Ein Konfigurationsparameter würde Ihnen helfen
Gopi

53
Sie wissen nie, wann sich der Wert von piändern könnte ...
Gabe

12
Mann, ich denke Leute wie @gabe sind der Grund, warum dies eine "Regel" ist. Wenn Sie 3.14 an 20 Stellen in Ihrem Code wiederholen und dann feststellen, dass Sie tatsächlich mehr Genauigkeit benötigen, sind Sie geschraubt. Ich wusste nicht, dass das nicht offensichtlich war.
Bill K

17
Das war ein bisschen unhöflich, @Bill. @Gabe war eindeutig ein Scherz, aber abgesehen davon drehte sich die Frage um die Parameter Hardcoding vs. Config und nicht um die Verwendung einer Konstanten vs. Repeat Magic Numbers an mehreren Stellen.
David Conrad

1
Ja, Hardcoding kann manchmal eine gute Idee sein. Siehe den Wikipedia-Artikel zum Anti-Pattern "Softcoding".
user16764

Antworten:


64

Ja, aber machen Sie es deutlich .

Machen:

  • benutze Konstanten
  • Verwenden Sie einen beschreibenden Variablennamen

Nicht:


44
Was ist sauberer diameter = 2 * radiusoder diameter = RADIUS_TO_DIAMETER_FACTOR * radius? In der Tat gibt es Eckfälle, in denen eine magische Zahl die bessere Lösung sein kann.
Joonas Pulakka

5
Ich kann dieser Antwort nicht genug zustimmen. Ich neige dazu, das Programmieren als Romanautor zu betrachten. Du erzählst deine Geschichte durch den Code und wenn die Leute die Logik nicht verstehen, macht es deinen Code meiner Meinung nach wertlos. Aus diesem Grund dienen gut durchdachte Namenskonventionen im Wesentlichen der Lesbarkeit. Es gibt auch keinen guten Grund, magische Zahlen zu verwenden. Indem Sie magische Zahlen verwenden, entfernen Sie das "Warum" aus der Gleichung und erschweren das Verständnis. Zum Beispiel: "Durchmesser = 2 * Radius" Wofür sind die beiden? Dieser "Durchmesser = RADIUS_TO_DIAMETER_FACTOR * Radius" ist viel sinnvoller.
Chrisw

9
Durchmesser = 2 * Radius ist direkt aus der High School Mathematik. Der Grund dafür, die "2" nicht zu benennen, ist, dass ein Wert von etwas anderem eine Änderung der Gesetze der Physik oder Mathematik oder von beidem erfordern würde. (Andererseits ist die Benennung der Pi-Konstante oder der Plancks-Konstante ein guter Schritt für eine einfache Lesbarkeit).
quick_now

8
@Joonas: Pfft. Sicher meinst du diameter = radius << 1? Das könnte wohl auch sein diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT.
Ameise

4
Wie wäre es mit ein paardiameter = radius.toDiameter()
Carson Myers

26

Was ich bisher an dieser Frage und Antwort merkwürdig finde, ist, dass niemand wirklich versucht hat, "harten Code" oder, was noch wichtiger ist, die Alternativen klar zu definieren.

tl; dr: Ja, es ist manchmal eine gute Idee, Werte hart zu codieren, aber es gibt keine einfache Regel, wann ; es hängt ganz vom Kontext ab.

Die Frage beschränkt sich auf Werte , die ich als magische Zahlen bezeichne , aber die Antwort darauf, ob sie eine gute Idee sind oder nicht, hängt davon ab, wofür sie tatsächlich verwendet werden!

Einige Beispiele für "fest codierte" Werte sind:

  • Konfigurationswerte

    Ich zucke zusammen, wenn ich solche Aussagen sehe command.Timeout = 600. Warum 600? Wer hat das entschieden? War es zuvor eine Zeitüberschreitung, und jemand hob die Zeitüberschreitung als Hack an, anstatt das zugrunde liegende Leistungsproblem zu beheben? Oder ist es tatsächlich eine bekannte und dokumentierte Erwartung an die Bearbeitungszeit?

    Dies sollten keine magischen Zahlen oder Konstanten sein. Sie sollten in einer Konfigurationsdatei oder Datenbank mit einem aussagekräftigen Namen extern gespeichert werden, da ihr optimaler Wert weitgehend oder vollständig von der Umgebung abhängt, in der die Anwendung ausgeführt wird.

  • Mathematische Formeln

    Formeln sind in der Regel ziemlich statisch, sodass die Art der darin enthaltenen konstanten Werte nicht besonders wichtig ist. Das Volumen einer Pyramide beträgt (1/3) b * h. Interessiert es uns, wo die 1 oder 3 herkommen? Nicht wirklich. Ein vorheriger Kommentator hat zu Recht darauf hingewiesen, dass dies diameter = radius * 2wahrscheinlich besser ist als diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR- aber das ist eine falsche Zweiteilung.

    Was Sie für diese Art von Szenario tun sollten, ist das Erstellen einer Funktion . Ich muss nicht wissen, wie du auf die Formel gekommen bist, aber ich muss immer noch wissen, wofür sie ist . Wenn anstelle des oben beschriebenen Unsinns volume = GetVolumeOfPyramid(base, height)plötzlich alles klarer wird und es völlig in Ordnung ist, magische Zahlen in function ( return base * height / 3) zu haben, weil es offensichtlich ist, dass sie nur Teil der Formel sind.

    Der Schlüssel ist hier natürlich, kurze und einfache Funktionen zu haben. Dies funktioniert nicht für Funktionen mit 10 Argumenten und 30 Berechnungszeilen. Verwenden Sie in diesem Fall die Funktionszusammensetzung oder Konstanten.

  • Domain / Geschäftsregeln

    Dies ist immer der graue Bereich, da dies davon abhängt, wie genau der Wert ist. Meistens sind es diese speziellen magischen Zahlen, die Kandidaten für die Umwandlung in Konstanten sind, da dies das Programm verständlicher macht, ohne die Programmlogik zu komplizieren. Betrachten Sie den Test if Age < 19vs. if Age < LegalDrinkingAge; Sie wahrscheinlich kann herausfinden , was ohne die ständige vor sich geht, aber es ist einfacher , mit dem aussagekräftigen Titel.

    Diese können beispielsweise auch Kandidaten für die Funktionsabstraktion werden function isLegalDrinkingAge(age) { return age >= 19 }. Das Einzige ist, dass Ihre Geschäftslogik oft viel komplizierter ist und es möglicherweise keinen Sinn macht, Dutzende von Funktionen mit jeweils 20 bis 30 Parametern zu schreiben. Wenn es keine klare Abstraktion auf der Basis von Objekten und / oder Funktionen gibt, ist es in Ordnung, auf Konstanten zurückzugreifen.

    Die Einschränkung ist, wenn Sie für die Steuerabteilung arbeiten, wird es wirklich sehr, sehr lästig und ehrlich gesagt sinnlos zu schreiben AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR). Sie werden das nicht tun, Sie werden es tun, AttachForm("B-46")weil jeder einzelne Entwickler, der jemals gearbeitet hat oder jemals arbeiten wird, wissen wird, dass "B-46" der Formularcode für einen einzelnen Steuerzahler ist, der blah blah blah - Die Formularcodes sind Teil der Domain selbst, sie ändern sich nie und sind daher keine wirklich magischen Zahlen.

    Daher müssen Sie Konstanten in der Geschäftslogik sparsam einsetzen. Grundsätzlich muss man verstehen, ob es sich bei dieser "magischen Zahl" tatsächlich um eine magische Zahl handelt oder ob es sich um einen bekannten Aspekt der Domäne handelt. Wenn es sich um eine Domain handelt, können Sie sie nicht mit einem Softcode versehen, es sei denn, es besteht eine gute Chance, dass sie sich ändert.

  • Fehlercodes und Statusflags

    Diese sind nie in Ordnung zu hart Code, wie jeder armen Bastard, der jemals mit dem Hit wurde Previous action failed due to error code 46Ihnen sagen kann. Wenn Ihre Sprache dies unterstützt, sollten Sie einen Aufzählungstyp verwenden. Andernfalls verfügen Sie normalerweise über eine ganze Datei / ein ganzes Modul mit Konstanten, in denen die gültigen Werte für einen bestimmten Fehlertyp angegeben sind.

    Lass mich nie return 42in einer Fehlerbehandlungsroutine nachsehen, capiche? Keine Ausreden.

Ich habe wahrscheinlich mehrere Szenarien ausgelassen, aber ich denke, das deckt die meisten davon ab.

Also, ja, es ist manchmal akzeptabel, Dinge hart zu codieren. Sei einfach nicht faul dabei; Es sollte eine bewusste Entscheidung sein und kein einfacher, alter, schlampiger Code.


Danke für die gute Panne! - die meisten Menschen denken nicht über alle Optionen möchte ich hinzufügen , „Umwelt - Konfiguration“ - Ich denke , diese (nicht hartcodiert) sollten vermieden werden, da die meisten Daten sollen in einer Konfigurationsdatei oder Datenbank gestellt werden. Dies folgt dem Prinzip "Daten und Logik getrennt halten", das eine Hauptstütze von MVC oder MVVM ist. string TestServerVar = "foo"; string ProdServerVal = "bar";
m1m1k

7

Es gibt verschiedene Gründe, einer Nummer eine Kennung zuzuweisen.

  • Wenn sich die Nummer ändern könnte, sollte sie eine Kennung haben. Es ist viel einfacher, NUMBER_OF_PLANETS zu finden, als nach jeder Instanz von 9 zu suchen und zu überlegen, ob sie in 8 geändert werden soll eine schwierige Sache im Voraus vorherzusagen.)
  • Wenn die Nummer in irgendeiner Weise schwer zu tippen ist. Für Konstanten wie pi ist es besser, eine Definition mit maximaler Genauigkeit anzugeben, als sie an mehreren Stellen erneut einzugeben, möglicherweise ungenau.
  • Wenn die Nummer an verschiedenen Stellen vorkommt. Sie sollten sich nicht zwei Verwendungen von 45 in benachbarten Funktionen ansehen und sich fragen müssen, ob sie dasselbe bedeuten.
  • Wenn die Bedeutung nicht sofort erkennbar ist. Man kann davon ausgehen, dass jeder weiß, was 3.14159265 ... ist. Es ist nicht sicher anzunehmen, dass jeder die Gravitationskonstante oder sogar pi / 2 erkennt. ("Jeder" hier hängt von der Art der Software ab. Von Systemprogrammierern kann erwartet werden, dass sie die Oktaldarstellung von Unix-Berechtigungsbits oder dergleichen kennen. In Software für Marine- / Marinearchitekturen wird die Froude-Nummer eines vorgeschlagenen Rumpfs und die Geschwindigkeit überprüft sehen, ob es 1.1 oder höher ist, ist für jeden, der daran arbeiten sollte, selbsterklärend.)
  • Wenn der Kontext nicht erkennbar ist. Jeder weiß, dass 60 Minuten in einer Stunde liegen, aber das Multiplizieren oder Dividieren mit 60 kann unklar sein, wenn es keine unmittelbaren Anzeichen dafür gibt, dass es sich bei der Menge um einen Zeitwert oder einen Ratenwert handelt.

Dies gibt uns Kriterien für die Hardcodierung von Literalen. Sie sollten unveränderlich und nicht schwer zu tippen sein, nur an einem Ort oder in einem Kontext vorkommen und eine erkennbare Bedeutung haben. Es hat keinen Sinn, 0 beispielsweise als ARRAY_BEGINNING oder 1 als ARRAY_INCREMENT zu definieren.


5

Als Ergänzung zu anderen Antworten. Verwenden Sie nach Möglichkeit Konstanten für Zeichenfolgen. Natürlich willst du nicht haben

const string server_var="server_var";

aber du solltest haben

const string MySelectQuery="select * from mytable;";

(Angenommen, Sie haben tatsächlich eine Abfrage, bei der Sie immer alle Ergebnisse einer bestimmten Tabelle abrufen möchten.)

Verwenden Sie ansonsten (normalerweise) Konstanten für eine andere Zahl als 0. Wenn Sie eine Berechtigungsbitmaske von 255 benötigen, verwenden Sie diese nicht

const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.

Verwenden Sie stattdessen

const int AllowGlobalRead=255;

Zusammen mit Konstanten wissen Sie natürlich, wann Sie Enumeratoren verwenden müssen. Der obige Fall würde wahrscheinlich gut in einen passen.


typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, ...} ... Lache nicht, ich habe es getan gesehen. Schlage diese Person mit einem nassen Fisch um den Kopf!
quick_now

@ schnell gut natürlich möchten Sie etwas mehr wietypedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
Earlz

6
THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
StuperUser

4
Für Zeichenfolgen möchten Sie nicht nur Konstanten. Sie möchten für den Benutzer sichtbare Zeichenfolgen in eine Art Ressourcendatei einfügen (Details hängen von Ihrer Plattform ab), damit Sie problemlos in eine andere Sprache wechseln können.
David Thornley

Möglicherweise möchten Sie auch geschäftslogikbezogene Zeichenfolgen (z. B. SQL-Abfragen) in eine Ressourcendatei mit einer Art Verschlüsselung oder Verschleierung einfügen. Dadurch wird verhindert, dass "neugierige" Benutzer Ihre Logik (oder Ihr Datenbankschema) zurückentwickeln.
TMN

4

Es kommt darauf an, was Sie für Hardcoding halten. Wenn Sie versuchen, alle hardcodierten Dinge zu vermeiden, landen Sie im Bereich der Softcodierung und erstellen ein System, das nur der Ersteller verwalten kann (und das ist der ultimative Hardcode).

Viele Dinge sind in einem vernünftigen Rahmen fest programmiert und funktionieren. Das heißt, es gibt keinen technischen Grund, warum ich den Einstiegspunkt einer C # -Anwendung nicht ändern sollte (static void Main), aber eine Hardcodierung, die für keinen Benutzer Probleme bereitet (mit Ausnahme der gelegentlichen SO-Frage ).

Als Faustregel gilt, dass alles, was sich ändern kann und wird, ohne den Zustand des gesamten Systems zu beeinträchtigen, konfigurierbar sein sollte.

Also, meiner Meinung nach, ist es dumm, Dinge, die sich nie ändern, nicht fest zu codieren (pi, Gravitationskonstante, eine Konstante in einer mathematischen Formel - denke an das Volumen einer Kugel).

Es ist auch dumm, Dinge oder Prozesse, die sich auf Ihr System auswirken und in jedem Fall programmiert werden müssen, nicht fest zu codieren. Es ist also sinnlos, dem Benutzer das Hinzufügen dynamischer Felder zu einem Formular zu erlauben, wenn der Wartungsentwickler dies für ein hinzugefügtes Feld tun müsste Geh rein und schreibe ein Skript, das das Ding zum Laufen bringt. Außerdem ist es dumm (und ich habe es einige Male in Unternehmensumgebungen gesehen), ein Konfigurationstool zu erstellen, sodass nichts fest codiert ist, aber nur die Entwickler in der IT-Abteilung können es verwenden, und es ist nur geringfügig einfacher zu verwenden als in Visual Studio ausführen.

Unterm Strich hängt es also von zwei Variablen ab, ob ein Objekt fest codiert werden soll:

  • Wird sich der Wert ändern?
  • Wie wirkt sich eine Wertänderung auf das System aus?

4

Ist es jemals eine gute Idee, Werte in unseren Anwendungen festzukodieren?

I codieren Werte nur , wenn die Werte sind angegeben in der Spezifikation (auf einer endgültigen Freigabe der Spezifikation), zB die HTTP - OK - Antwort wird immer sein 200(es sei denn , es in der RFC ändert), so werden Sie (in einigen meiner Codes sehen ) Konstanten wie:

public static final int HTTP_OK = 200;

Ansonsten speichere ich Konstanten in der Eigenschaftendatei.

Der Grund, warum ich Spezifikationen spezifiziert habe, ist, dass das Ändern von Konstanten in Spezifikationen ein Änderungsmanagement erfordert, bei dem die Stakeholder die Änderung überprüfen und genehmigen / ablehnen. Es passiert nie über Nacht und dauert Monate / Jahre für eine Genehmigung. Vergessen Sie nicht, dass viele Entwickler Spezifikationen (z. B. HTTP) verwenden. Wenn Sie diese ändern, werden Millionen von Systemen zerstört.


3
  • Wenn sich der Wert ändern kann und sich auch ändern könnte, verwenden Sie nach Möglichkeit Softcode, solange der Aufwand die erwartete Rendite nicht überschreitet
  • Einige Werte können nicht softcodiert werden. Befolgen Sie in diesen (seltenen) Fällen die Richtlinien von Jonathan

2

Mir ist aufgefallen, dass jedes Mal, wenn Sie Daten aus Ihrem Code extrahieren können, die verbleibenden Daten verbessert werden. Sie bemerken neue Refactorings und verbessern ganze Abschnitte Ihres Codes.

Es ist nur eine gute Idee, auf das Extrahieren von Konstanten hinzuarbeiten. Betrachten Sie es nicht als eine dumme Regel.

Der größte Vorteil ist, dass Sie ähnliche Konstanten als einzigen Unterschied in Codegruppen finden können. Durch die Zusammenfassung in Arrays konnte ich einige Dateien um 90% ihrer Größe reduzieren und in der Zwischenzeit einige Fehler beim Kopieren und Einfügen beheben .

Ich habe noch keinen einzigen Vorteil darin gesehen, keine Daten zu extrahieren.


2

Ich habe kürzlich eine MySQL-Funktion programmiert, um den Abstand zwischen zwei Lat / Long-Paaren richtig zu berechnen. Sie können nicht nur Pythagorus machen; Längengradlinien rücken näher zusammen, wenn der Breitengrad zu den Polen hin zunimmt. Punkt ist, ich war ziemlich hin und her gerissen, ob ich den Wert, der den Erdradius in Meilen darstellt, hart codieren sollte.

Am Ende habe ich es geschafft, obwohl die Linien auf dem Mond viel enger beieinander liegen. Und meine Funktion würde Entfernungen zwischen Punkten auf Jupiter drastisch unterschreiten. Ich dachte, die Wahrscheinlichkeit, dass die Website, die ich gerade baue, einen außerirdischen Standort hat, der betreten wird, ist ziemlich gering.


Ja, wahrscheinlich, aber was ist mit google.com/moon
Residuum

1

Nun, es kommt darauf an, ob Ihre Sprache kompiliert ist. Wenn es nicht kompiliert ist, ist es keine große Sache, Sie bearbeiten einfach den Quellcode, auch wenn es für einen Nicht-Programmierer etwas heikel ist.

Wenn Sie mit einer kompilierten Sprache programmieren, ist dies eindeutig keine gute Idee, denn wenn sich die Variablen ändern, müssen Sie neu kompilieren. Dies ist eine große Zeitverschwendung, wenn Sie diese Variable anpassen möchten.

Sie müssen weder einen Schieberegler noch eine Benutzeroberfläche erstellen, um seine Variable dynamisch zu ändern, aber das Mindeste, was Sie tun können, ist eine Textdatei.

Zum Beispiel verwende ich bei meinem Ogerprojekt immer die ConfigFile-Klasse, um eine Variable zu laden, die ich in eine Konfigurationsdatei geschrieben habe.


1

Zwei Fälle, in denen Konstanten (zumindest meiner Meinung nach) in Ordnung sind:

  1. Konstanten, die sich auf nichts anderes beziehen; Sie können diese Konstanten jederzeit ändern, ohne etwas anderes ändern zu müssen. Beispiel: Die Standardbreite einer Rasterspalte.

  2. Absolut unveränderliche, präzise, ​​offensichtliche Konstanten wie "Anzahl der Tage pro Woche". days = weeks * 7Das Ersetzen 7durch eine Konstante DAYS_PER_WEEKliefert kaum einen Wert.


0

Ich stimme Jonathan vollkommen zu, aber da es alle Regeln gibt, gibt es Ausnahmen ...

"Magische Nummer in der Spezifikation: Magische Nummer im Code"

Grundsätzlich heißt es, dass alle magischen Zahlen, die nach vernünftigen Versuchen, einen beschreibenden Kontext für sie zu erhalten, in der Spezifikation verbleiben, als solche im Code wiedergegeben werden sollten. Wenn magische Zahlen im Code verbleiben, sollten alle Anstrengungen unternommen werden, um sie zu isolieren und sie klar mit ihrem Ursprungspunkt zu verknüpfen.

Ich habe einige Schnittstellenverträge abgeschlossen, bei denen es erforderlich ist, Nachrichten mit Werten aus der Datenbank zu füllen. In den meisten Fällen ist die Zuordnung recht einfach und würde in Jonathans allgemeine Richtlinien passen, aber ich habe Fälle angetroffen, in denen die Zielnachrichtenstruktur einfach schrecklich war. Mehr als 80% der Werte, die in der Struktur übergeben werden mussten, waren Konstanten, die durch die Spezifikation des entfernten Systems erzwungen wurden. Dies ging einher mit der Tatsache, dass die Nachrichtenstruktur gigantisch war und viele solcher Konstanten aufgefüllt werden mussten. In den meisten Fällen gaben sie weder eine Bedeutung noch einen Grund an, sondern sagten nur "setze M hierher" oder "setze 4.10.53.10100.889450.4452 hierher". Ich habe auch nicht versucht, einen Kommentar neben alle zu setzen, da dies den resultierenden Code unleserlich gemacht hätte.

Das heißt, wenn du darüber nachdenkst ... dreht sich so ziemlich alles darum, es offensichtlich zu machen ...


0

Wenn Sie den Wert der Gravitationskonstante der Erde fest codieren, wird es niemanden interessieren. Wenn Sie die IP-Adresse Ihres Proxy-Servers fest codieren, treten Probleme auf.


1
Möglicherweise müssen Sie die Gravitationskonstante der Erde genauer bestimmen. Wenn Sie sie also mehrmals fest codieren, kann dies zu Problemen führen.
user281377

1
Peter Noone? Von Hermans Einsiedlern?
David Conrad

Die Erdbeschleunigung beträgt für die meisten Breiten- und Höhenlagen 9,81 m / s ^ 2 (natürlich, wenn Sie nach Öl unter Tage suchen oder ICBMs über den Nordpol schießen, ist es sehr wichtig, die Schwerkraftschwankungen zu kennen viel mehr Dezimalstellen), wobei die Gravitationsbeschleunigung auf anderen Planeten eine andere Zahl ist, aber meines Wissens ist die Gravitationskonstante im gesamten Universum konstant. Es gibt eine Menge Physik, die sich ändern müsste, wenn g variabel wäre.
Tangurena

0

Meistens nein, aber ich denke, es ist erwähnenswert, dass Sie die meisten Probleme haben, wenn Sie anfangen, den fest codierten Wert zu duplizieren. Wenn Sie es nicht duplizieren (z. B. nur einmal in der Implementierung einer Klasse verwenden), ist es möglicherweise in Ordnung, keine Konstante zu verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.