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?
pi
ändern könnte ...
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?
pi
ändern könnte ...
Antworten:
Ja, aber machen Sie es deutlich .
Machen:
Nicht:
diameter = 2 * radius
oder diameter = RADIUS_TO_DIAMETER_FACTOR * radius
? In der Tat gibt es Eckfälle, in denen eine magische Zahl die bessere Lösung sein kann.
diameter = radius << 1
? Das könnte wohl auch sein diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
.
diameter = radius.toDiameter()
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 * 2
wahrscheinlich 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 < 19
vs. 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 46
Ihnen 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 42
in 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.
Es gibt verschiedene Gründe, einer Nummer eine Kennung zuzuweisen.
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.
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 {init_state=0, parse_state=1, evaluation_state=2, ... }
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:
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.
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.
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.
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.
Zwei Fälle, in denen Konstanten (zumindest meiner Meinung nach) in Ordnung sind:
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.
Absolut unveränderliche, präzise, offensichtliche Konstanten wie "Anzahl der Tage pro Woche". days = weeks * 7
Das Ersetzen 7
durch eine Konstante DAYS_PER_WEEK
liefert kaum einen Wert.
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 ...
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.
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.