Was ist eine magische Zahl und warum ist sie schlecht? [geschlossen]


514

Was ist eine magische Zahl?

Warum sollte es vermieden werden?

Gibt es Fälle, in denen dies angemessen ist?


2
Sie würden magische Zahlen vermeiden, da andere Personen, die Ihren Code anzeigen, möglicherweise nicht verstehen, warum Sie das tun, was Sie tun. Im Moment const myNum = 22; const number = myNum / 11;könnten meine 11 Personen oder Flaschen Bier oder ähnliches sein. Stattdessen würde ich 11 in eine Konstante ändern wie Einwohner.
JuicY_Burrito

Die Verwendung magischer Zahlen in Attributen ist unvermeidlich, daher halte ich dies für angemessen.
Donatasj87

Antworten:


574

Eine magische Zahl ist eine direkte Verwendung einer Zahl im Code.

Zum Beispiel, wenn Sie (in Java) haben:

public class Foo {
    public void setPassword(String password) {
         // don't do this
         if (password.length() > 7) {
              throw new InvalidArgumentException("password");
         }
    }
}

Dies sollte überarbeitet werden, um:

public class Foo {
    public static final int MAX_PASSWORD_SIZE = 7;

    public void setPassword(String password) {
         if (password.length() > MAX_PASSWORD_SIZE) {
              throw new InvalidArgumentException("password");
         }
    }
}

Es verbessert die Lesbarkeit des Codes und ist einfacher zu warten. Stellen Sie sich den Fall vor, in dem ich die Größe des Kennwortfelds in der GUI festgelegt habe. Wenn ich eine magische Zahl verwende, muss ich mich bei jeder Änderung der maximalen Größe an zwei Codepositionen ändern. Wenn ich einen vergesse, führt dies zu Inkonsistenzen.

Das JDK ist voll von Beispielen , wie in Integer, Characterund MathKlassen.

PS: Statische Analysetools wie FindBugs und PMD erkennen die Verwendung magischer Zahlen in Ihrem Code und schlagen das Refactoring vor.


174
0 und 1 sind Ausnahmen von dieser Regel.
Jonathan Parker

24
@Kirill: Wenn Sie erwarten, dass sich die Definition von "Hundert Prozent" ändert, dann ja. Ein besserer Ansatz wäre, die Variable von dem, was sie ist, bis zu dem, was sie darstellt, zu haben, dh public static final MAX_DOWNLOAD_PERCENTAGE = 100. Auch wenn dies nicht sinnvoll wäre, da "100 Prozent" sehr gut definiert ist. Andererseits ist die Tatsache, dass Passwörter maximal 7 Zeichen lang sein können, nicht global definiert und unterscheidet sich tatsächlich, sodass dies ein Kandidat für eine Variable ist.
Michael Stum

40
@ Jonathan Parker, außer wenn sie nicht ( TRUE/ FALSE) sind
Brendan Long

82
Nur weil sich eine magische Zahl niemals ändern wird, heißt das nicht, dass sie nicht durch eine Konstante ersetzt werden sollte. Mein Code ist voll von globalen Konstanten wie HzPerMHz und msecPerSecond. Diese werden sich nie ändern, aber sie machen die Bedeutung klarer und bieten einen gewissen Schutz vor Tippfehlern.
Jeanne Pindar

43
@MarcusJ Sie könnten nicht falscher sein. Dies ist keine Ansichtssache, sondern eine hart erarbeitete Erfahrung vieler Programmierer. Ich kann Ihnen nicht sagen, wie oft ich in den letzten 40 Jahren der Programmierung einen früheren Programmierer verflucht habe, der keine Konstante definiert hat. Daher habe ich nur die direkte Verwendung einer Zahl entdeckt, die während der Codepflege verstanden werden musste , irgendwo in viel Code vergraben, dessen Bedeutung durch die Definition einer solchen Konstante deutlich geworden wäre. Jeder andere hochrangige Programmierer wird ebenfalls mehrere Horrorgeschichten in dieser Richtung haben.
ToolmakerSteve

145

Eine magische Zahl ist ein fest codierter Wert, der sich zu einem späteren Zeitpunkt ändern kann, der jedoch schwer zu aktualisieren ist.

Angenommen, Sie haben eine Seite, auf der die letzten 50 Bestellungen auf einer Übersichtsseite "Ihre Bestellungen" angezeigt werden. 50 ist hier die magische Zahl, da sie nicht durch Standard oder Konvention festgelegt wurde, sondern eine Zahl, die Sie aus den in der Spezifikation angegebenen Gründen erfunden haben.

Jetzt haben Sie die 50 an verschiedenen Stellen - Ihr SQL-Skript ( SELECT TOP 50 * FROM orders), Ihre Website (Ihre letzten 50 Bestellungen), Ihr Bestell-Login (for (i = 0; i < 50; i++) ) und möglicherweise vielen anderen Orten.

Was passiert nun, wenn jemand beschließt, 50 auf 25 zu ändern? oder 75? oder 153? Sie müssen jetzt die 50 an allen Stellen ersetzen, und es ist sehr wahrscheinlich, dass Sie sie verpassen. Suchen / Ersetzen funktioniert möglicherweise nicht, da 50 für andere Zwecke verwendet werden kann und das blinde Ersetzen von 50 durch 25 andere schlimme Nebenwirkungen haben kann (z. B. IhreSession.Timeout = 50 Anruf, der ebenfalls auf 25 eingestellt ist und Benutzer beginnen, zu häufige Zeitüberschreitungen zu melden).

Außerdem kann der Code schwer zu verstehen sein, dh " if a < 50 then bla" - wenn Sie mitten in einer komplizierten Funktion darauf stoßen, fragen sich andere Entwickler, die mit dem Code nicht vertraut sind, möglicherweise "WTF ist 50 ???"

Deshalb ist es am besten, solche mehrdeutigen und willkürlichen Zahlen an genau einer Stelle zu haben - " const int NumOrdersToDisplay = 50", weil dadurch der Code besser lesbar wird (")if a < NumOrdersToDisplay ", bedeutet dies auch, dass Sie ihn nur an einer genau definierten Stelle ändern müssen.

Orte, an denen magische Zahlen angemessen sind, sind alles, was durch einen Standard definiert wird, dh SmtpClient.DefaultPort = 25oder TCPPacketSize = whatever(nicht sicher, ob dies standardisiert ist). Auch alles, was nur innerhalb einer Funktion definiert ist, ist möglicherweise akzeptabel, dies hängt jedoch vom Kontext ab.


18
Auch wenn es sich nicht ändern kann, ist es immer noch eine schlechte Idee, weil nicht klar ist, was los ist.
Loren Pechtel

11
Es ist nicht immer unklar. SmtpClient.DefaultPort = 25ist möglicherweise deutlich er als SmtpClient.DefaultPort = DEFAULT_SMTP_PORT.
user253751

4
@immibis Ich nehme an, dass davon ausgegangen wird, dass es absolut keinen anderen Code gibt, der das Konzept von DEFAULT_SMTP_PORT verwendet. Wenn der Standard-SMTP-Port für diese Anwendung geändert wird, muss er an mehreren Stellen aktualisiert werden, was zu Inkonsistenzen führen kann.
Russ Bradberry

3
Es ist auch schwieriger, alle Verwendungen zu finden - Sie müssten in der 25gesamten Anwendung nach etwas suchen und sicherstellen, dass Sie nur die Vorkommen ändern 25, die für den SMTP-Port gelten, nicht die 25er, die z. B. die Breite einer Tabellenspalte oder die Zahl sind von Datensätzen, die auf einer Seite angezeigt werden sollen.
Michael Stum

2
In diesem Beispiel würde ich erwarten, dass der Code SmtpClient.DefaultPort verwendet, nicht 25. Sie müssten ihn also nur an einer Stelle ändern. Und die Portnummer wird wahrscheinlich gleich bleiben, es ist keine zufällige magische Nummer, sondern eine von zugewiesene Nummer IANA.
NJSG

34

Haben Sie sich den Wikipedia-Eintrag für magische Zahlen angesehen?

Es wird ein wenig detailliert auf alle Arten eingegangen, wie auf die magische Zahl Bezug genommen wird. Hier ist ein Zitat über magische Zahlen als schlechte Programmierpraxis

Der Begriff magische Zahl bezieht sich auch auf die schlechte Programmierpraxis, Zahlen ohne Erklärung direkt im Quellcode zu verwenden. In den meisten Fällen ist es dadurch schwieriger, Programme zu lesen, zu verstehen und zu warten. Obwohl die meisten Hilfslinien eine Ausnahme für die Zahlen Null und Eins machen, ist es eine gute Idee, alle anderen Zahlen im Code als benannte Konstanten zu definieren.


8
Gutes Beispiel für RTFW :)
Eva

Ich würde sagen, die Antwort ist alles andere als voll.
Skeeve

25

Magic Number Vs. Symbolische Konstante: Wann ersetzen?

Magie: Unbekannte Semantik

Symbolische Konstante -> Bietet sowohl die richtige semantische als auch den richtigen Kontext für die Verwendung

Semantik: Die Bedeutung oder der Zweck einer Sache.

"Erstellen Sie eine Konstante, benennen Sie sie nach der Bedeutung und ersetzen Sie die Zahl durch diese." - Martin Fowler

Erstens sind magische Zahlen nicht nur Zahlen. Jeder Grundwert kann "Magie" sein. Grundwerte sind manifestierte Entitäten wie Ganzzahlen, Real, Doubles, Floats, Datumsangaben, Zeichenfolgen, Boolesche Werte, Zeichen usw. Das Problem ist nicht der Datentyp, sondern der "magische" Aspekt des Werts, wie er in unserem Codetext erscheint.

Was meinen wir mit "Magie"? Um genau zu sein: Mit "Magie" wollen wir auf die Semantik (Bedeutung oder Zweck) des Wertes im Kontext unseres Codes verweisen; dass es unbekannt, unerkennbar, unklar oder verwirrend ist. Dies ist der Begriff "Magie". Ein Grundwert ist keine Magie, wenn seine semantische Bedeutung oder sein Zweck schnell und einfach aus dem Surround-Kontext ohne spezielle Hilfswörter (z. B. symbolische Konstante) schnell und einfach bekannt, klar und verständlich (nicht verwirrend) ist.

Daher identifizieren wir magische Zahlen, indem wir die Fähigkeit eines Codelesers messen, die Bedeutung und den Zweck eines Grundwerts aus seinem umgebenden Kontext zu kennen, klar zu sein und zu verstehen. Je weniger bekannt, weniger klar und verwirrter der Leser ist, desto "magischer" ist der Grundwert.

Hilfreiche Definitionen

  • verwirren: jemanden verwirren oder verwirren lassen.
  • verwirrt: jemanden (jemanden) verwirren und verwirren lassen.
  • ratlos: völlig verblüfft; sehr verwirrt.
  • verblüfft: total verwirrt oder ratlos.
  • verwirrt: unfähig zu verstehen; verwirrt.
  • verstehen: die beabsichtigte Bedeutung von (Wörtern, einer Sprache oder einem Sprecher) wahrnehmen.
  • Bedeutung: Was ist mit einem Wort, Text, Konzept oder einer Handlung gemeint?
  • gemeint: beabsichtigen zu vermitteln, anzuzeigen oder sich auf (eine bestimmte Sache oder einen bestimmten Begriff) zu beziehen; bedeuten.
  • bedeuten: ein Hinweis auf sein.
  • Anzeige: Ein Zeichen oder eine Information, die auf etwas hinweist.
  • anzeigen: darauf hinweisen; Show.
  • Zeichen: Ein Objekt, eine Qualität oder ein Ereignis, dessen Vorhandensein oder Auftreten das wahrscheinliche Vorhandensein oder Auftreten von etwas anderem anzeigt.

Grundlagen

Wir haben zwei Szenarien für unsere magischen Grundwerte. Nur die zweite ist für Programmierer und Code von vorrangiger Bedeutung:

  1. Ein einzelner Grundwert (z. B. Zahl), dessen Bedeutung unbekannt, nicht erkennbar, unklar oder verwirrend ist.
  2. Ein Grundwert (zB Zahl) im Kontext, dessen Bedeutung jedoch unbekannt, nicht erkennbar, unklar oder verwirrend bleibt.

Eine übergreifende Abhängigkeit von "Magie" besteht darin, dass der einzelne Grundwert (z. B. Zahl) keine allgemein bekannte Semantik (wie Pi) hat, sondern eine lokal bekannte Semantik (z. B. Ihr Programm), die aus dem Kontext nicht ganz klar hervorgeht oder missbraucht werden könnte in guten oder schlechten Kontexten.

Die Semantik der meisten Programmiersprachen erlaubt es uns nicht, einzelne Grundwerte zu verwenden, außer (vielleicht) als Daten (dh Datentabellen). Wenn wir auf "magische Zahlen" stoßen, tun wir dies im Allgemeinen in einem Kontext. Daher die Antwort auf

"Ersetze ich diese magische Zahl durch eine symbolische Konstante?"

ist:

"Wie schnell können Sie die semantische Bedeutung der Zahl (ihren Zweck, dort zu sein) in ihrem Kontext beurteilen und verstehen?"

Art von Magie, aber nicht ganz

Mit diesem Gedanken können wir schnell erkennen, dass eine Zahl wie Pi (3.14159) keine "magische Zahl" ist, wenn sie in den richtigen Kontext gestellt wird (z. B. 2 x 3.14159 x Radius oder 2 * Pi * r). Hier wird die Nummer 3.14159 ohne die symbolische Konstantenkennung mental als Pi erkannt.

Aufgrund der Länge und Komplexität der Zahl ersetzen wir 3.14159 im Allgemeinen durch einen symbolischen Konstantenbezeichner wie Pi. Die Aspekte der Länge und Komplexität von Pi (verbunden mit einem Bedürfnis nach Genauigkeit) bedeuten normalerweise, dass die symbolische Kennung oder Konstante weniger fehleranfällig ist. Das Erkennen von "Pi" als Name ist einfach ein bequemer Bonus, aber nicht der Hauptgrund für die Konstante.

Inzwischen wieder auf der Ranch

Wenn wir gängige Konstanten wie Pi beiseite lassen, konzentrieren wir uns hauptsächlich auf Zahlen mit speziellen Bedeutungen, die jedoch auf das Universum unseres Softwaresystems beschränkt sind. Eine solche Zahl könnte "2" sein (als ganzzahliger Grundwert).

Wenn ich die Nummer 2 alleine benutze, könnte meine erste Frage sein: Was bedeutet "2"? Die Bedeutung von "2" an sich ist unbekannt und ohne Kontext nicht erkennbar, so dass seine Verwendung unklar und verwirrend bleibt. Obwohl nur "2" in unserer Software aufgrund der Sprachsemantik nicht vorkommen wird, möchten wir sehen, dass "2" für sich genommen keine spezielle Semantik oder einen offensichtlichen Zweck hat, allein zu sein.

Stellen wir unsere einsame "2" in einen Kontext von: padding := 2 , wobei der Kontext ein "GUI-Container" ist. In diesem Zusammenhang bietet uns die Bedeutung von 2 (als Pixel oder andere grafische Einheit) eine schnelle Einschätzung der Semantik (Bedeutung und Zweck). Wir könnten hier anhalten und sagen, dass 2 in diesem Zusammenhang in Ordnung ist und wir nichts anderes wissen müssen. Vielleicht ist dies in unserem Software-Universum jedoch nicht die ganze Geschichte. Es steckt noch mehr dahinter, aber "padding = 2" als Kontext kann es nicht offenbaren.

Stellen wir uns weiter vor, dass 2 als Pixelauffüllung in unserem Programm in unserem gesamten System von der Sorte "default_padding" ist. Daher ist das Schreiben der Anweisung padding = 2nicht gut genug. Der Begriff "Standard" wird nicht offenbart. Nur wenn ich schreibe: padding = default_paddingals Kontext und dann anderswo: default_padding = 2Erkenne ich eine bessere und umfassendere Bedeutung (Semantik und Zweck) von 2 in unserem System vollständig.

Das obige Beispiel ist ziemlich gut, da "2" für sich genommen alles sein kann. Nur wenn wir den Bereich und den Bereich des Verstehens auf "mein Programm" beschränken, wobei 2 default_paddingin den GUI-UX-Teilen von "mein Programm" steht, machen wir endlich Sinn für "2" in seinem richtigen Kontext. Hier ist "2" eine "magische" Zahl, die default_paddingim Kontext der GUI UX von "my program" zu einer symbolischen Konstante herausgerechnet wird , damit sie default_paddingim größeren Kontext des einschließenden Codes so schnell wie möglich verwendet wird.

Somit ist jeder Grundwert, dessen Bedeutung (Semantik und Zweck) nicht ausreichend und schnell verstanden werden kann, ein guter Kandidat für eine symbolische Konstante anstelle des Grundwerts (z. B. magische Zahl).

Weitergehen

Zahlen auf einer Skala können auch semantisch sein. Stellen Sie sich zum Beispiel vor, wir machen ein D & D-Spiel, in dem wir die Vorstellung eines Monsters haben. Unser Monsterobjekt hat eine Funktion namens life_force, die eine ganze Zahl ist. Die Zahlen haben Bedeutungen, die ohne Worte zur Bedeutung nicht erkennbar oder klar sind. Wir beginnen also damit, willkürlich zu sagen:

  • full_life_force: INTEGER = 10 - Sehr lebendig (und unverletzt)
  • Minimum_life_force: INTEGER = 1 - Kaum am Leben (sehr verletzt)
  • tot: INTEGER = 0 - Tot
  • Untote: INTEGER = -1 - Min. Untote (fast tot)
  • Zombie: INTEGER = -10 - Max Untote (sehr Untote)

Aus den obigen symbolischen Konstanten erhalten wir ein mentales Bild der Lebendigkeit, des Todes und der "Untotheit" (und möglicher Konsequenzen oder Konsequenzen) für unsere Monster in unserem D & D-Spiel. Ohne diese Wörter (symbolische Konstanten) bleiben uns nur die Zahlen von -10 .. 10. Allein der Bereich ohne die Wörter lässt uns an einem Ort mit möglicherweise großer Verwirrung und möglicherweise mit Fehlern in unserem Spiel zurück, wenn verschiedene Teile des Spiels davon abhängen, was dieser Bereich von Zahlen für verschiedene Operationen wie attack_elvesoder bedeutet seek_magic_healing_potion.

Daher möchten wir bei der Suche nach und dem Ersetzen von "magischen Zahlen" sehr zweckmäßige Fragen zu den Zahlen im Kontext unserer Software stellen und sogar darüber, wie die Zahlen semantisch miteinander interagieren.

Fazit

Lassen Sie uns überprüfen, welche Fragen wir stellen sollten:

Sie könnten eine magische Zahl haben, wenn ...

  1. Kann der Grundwert in Ihrem Software-Universum eine besondere Bedeutung oder einen besonderen Zweck haben?
  2. Kann die spezielle Bedeutung oder der spezielle Zweck wahrscheinlich unbekannt, nicht erkennbar, unklar oder verwirrend sein, selbst in ihrem richtigen Kontext?
  3. Kann ein richtiger Grundwert mit falschen Konsequenzen im falschen Kontext missbräuchlich verwendet werden?
  4. Kann ein unangemessener Grundwert mit schlechten Konsequenzen im richtigen Kontext richtig verwendet werden?
  5. Hat der Grundwert eine semantische oder zweckmäßige Beziehung zu anderen Grundwerten in bestimmten Kontexten?
  6. Kann ein Grundwert an mehr als einer Stelle in unserem Code mit jeweils unterschiedlicher Semantik existieren, was unseren Leser verwirrt?

Untersuchen Sie eigenständige manifest konstante Grundwerte in Ihrem Codetext. Stellen Sie jede Frage langsam und nachdenklich über jede Instanz eines solchen Wertes. Betrachten Sie die Stärke Ihrer Antwort. Oft ist die Antwort nicht schwarz und weiß, sondern hat Schattierungen von missverstandener Bedeutung und Zweck, Lerngeschwindigkeit und Geschwindigkeit des Verstehens. Es muss auch überprüft werden, wie die Verbindung zur umgebenden Softwaremaschine hergestellt wird.

Am Ende ist die Antwort auf das Ersetzen die Antwort auf das Maß (in Ihrem Kopf) der Stärke oder Schwäche des Lesers, um die Verbindung herzustellen (z. B. "bekommen"). Je schneller sie Sinn und Zweck verstehen, desto weniger "Magie" haben Sie.

SCHLUSSFOLGERUNG: Ersetzen Sie Grundwerte nur dann durch symbolische Konstanten, wenn die Magie groß genug ist, um schwer zu erkennende Fehler aufgrund von Verwirrungen zu verursachen.


1
Vielen Dank. Während die statischen Analysetools, die meine Kollegen ständig installieren, sich immer wieder über magische Zahlen beschweren - aber wie soll ein Tool die Semantik verstehen? Das Ergebnis ist, dass ALLE Grundwerte durch symbolische Konstanten ersetzt werden. Da ich Ihrer Schlussfolgerung zustimme, finde ich dies weniger als ideal.
Chomeh

17

Eine magische Zahl ist eine Folge von Zeichen am Anfang eines Dateiformats oder eines Protokollaustauschs. Diese Nummer dient als Überprüfung der geistigen Gesundheit.

Beispiel: Öffnen Sie eine beliebige GIF-Datei, die Sie ganz am Anfang sehen: GIF89. "GIF89" ist die magische Zahl.

Andere Programme können die ersten Zeichen einer Datei lesen und GIFs richtig identifizieren.

Die Gefahr besteht darin, dass zufällige Binärdaten dieselben Zeichen enthalten können. Aber es ist sehr unwahrscheinlich.

Mit dem Protokollaustausch können Sie schnell feststellen, dass die aktuelle Nachricht, die an Sie weitergeleitet wird, beschädigt oder ungültig ist.

Magische Zahlen sind immer noch nützlich.


13
Ich glaube nicht, dass dies die magische Zahl ist, auf die er sich bezog
Marcio Aguiar

4
Vielleicht sollten Sie die von Ihnen hinzugefügten Tags "Dateiformat" und "Netzwerk" entfernen, da er eindeutig nicht über diese Art von magischen Zahlen spricht.
Landon

9
Es ist immer noch sehr nützlich zu wissen, dass magische Zahlen mehr als nur ein Codeproblem betreffen können. -Adam
Adam Davis

3
Wenn der Betreff lautete: "Was ist eine magische Zahl in Bezug auf den Quellcode?", Sollten die Tags nicht vorhanden sein. Dies hat er aber nicht angegeben. Meine zusätzlichen Informationen sind also gut. Ich denke Kyle, Landon und Marcio liegen falsch.
Brian R. Bondy

4
Es gab auch keine Möglichkeit festzustellen, nach welchem ​​er suchte. Da ich der erste Beitrag war, konnte ich nicht erraten, welchen er suchte.
Brian R. Bondy

12

Bei der Programmierung ist eine "magische Zahl" ein Wert, der einen symbolischen Namen erhalten sollte, aber stattdessen als Literal in den Code eingefügt wurde, normalerweise an mehr als einer Stelle.

Es ist aus demselben Grund schlecht, aus dem SPOT (Single Point of Truth) gut ist: Wenn Sie diese Konstante später ändern möchten, müssen Sie Ihren Code durchsuchen, um jede Instanz zu finden. Es ist auch schlecht, weil anderen Programmierern möglicherweise nicht klar ist, was diese Zahl darstellt, daher die "Magie".

Menschen gehen manchmal die Eliminierung magischer Zahlen weiter, indem sie diese Konstanten in separate Dateien verschieben, um als Konfiguration zu fungieren. Dies ist manchmal hilfreich, kann aber auch zu mehr Komplexität führen, als es wert ist.


Können Sie genauer sagen, warum das Eliminieren von Maginc-Zahlen nicht immer gut ist?
Marcio Aguiar

In mathematischen Formeln wie e ^ pi + 1 = 0
Jared Updike

5
Marcio: Wenn du Dinge wie "const int EIGHT = 8" machst; und dann ändern sich die Anforderungen und Sie erhalten "const int EIGHT = 9;"
jmucchiello

6
Entschuldigung, aber das ist einfach ein Beispiel für eine schlechte Benennung oder eine Basisverwendung für die Konstante.
Kzqai

1
@MarcioAguiar: Auf einigen Plattformen kann ein Ausdruck wie (foo[i]+foo[i+1]+foo[i+2]+1)/3viel schneller als eine Schleife ausgewertet werden. Wenn man 3den Code ersetzen würde, ohne den Code als Schleife neu zu schreiben, könnte jemand, der als ITEMS_TO_AVERAGEdefiniert angesehen wird, 3ihn ändern 5und den Code durchschnittlich mehr Elemente haben lassen. Im Gegensatz dazu würde jemand, der den Ausdruck mit dem Literal betrachtete 3, erkennen, dass dies 3die Anzahl der Elemente darstellt, die zusammen summiert werden.
Supercat

10

Eine magische Zahl kann auch eine Zahl mit einer speziellen, fest codierten Semantik sein. Zum Beispiel habe ich einmal ein System gesehen, in dem Datensatz-IDs> 0 normal behandelt wurden, 0 selbst "neuer Datensatz" war, -1 "dies ist der Stamm" und -99 "dies wurde im Stamm erstellt". 0 und -99 würden dazu führen, dass der WebService eine neue ID bereitstellt.

Das Schlechte daran ist, dass Sie ein Leerzeichen (das von vorzeichenbehafteten Ganzzahlen für Datensatz-IDs) für spezielle Fähigkeiten wiederverwenden. Vielleicht möchten Sie nie einen Datensatz mit der ID 0 oder mit einer negativen ID erstellen, aber selbst wenn nicht, könnte jede Person, die entweder den Code oder die Datenbank betrachtet, darauf stoßen und zunächst verwirrt sein. Es versteht sich von selbst, dass diese besonderen Werte nicht gut dokumentiert waren.

Wohl 22, 7, -12 und 620 zählen auch als magische Zahlen. ;-);


10

Ein Problem, das bei der Verwendung magischer Zahlen nicht erwähnt wurde ...

Wenn Sie sehr viele davon haben, stehen die Chancen ziemlich gut, dass Sie zwei verschiedene Zwecke haben , für die Sie magische Zahlen verwenden, bei denen die Werte zufällig gleich sind.

Und dann müssen Sie den Wert ändern ... für nur einen Zweck.


Das sieht nicht so wahrscheinlich aus, wenn man über Zahlen spricht (zumindest nicht für mich), aber ich bin mit Strings darauf gestoßen und es ist ein Hit: Zuerst muss man viel Code lesen, um zu sehen, wo er verwendet wird, als Sie Ich muss bemerken, dass es für verschiedene Dinge verwendet wird ... nicht mein Lieblingsbeschäftigung.
Tomislav Nakic-Alfirevic

4

Ich gehe davon aus, dass dies eine Antwort auf meine Antwort auf Ihre frühere Frage ist. Bei der Programmierung ist eine magische Zahl eine eingebettete numerische Konstante, die ohne Erklärung erscheint. Wenn es an zwei verschiedenen Stellen angezeigt wird, kann dies dazu führen, dass eine Instanz geändert wird und keine andere. Aus diesen beiden Gründen ist es wichtig, die numerischen Konstanten außerhalb der Orte, an denen sie verwendet werden, zu isolieren und zu definieren.


3

Ich habe den Begriff "magische Zahl" immer anders verwendet, als einen obskuren Wert, der in einer Datenstruktur gespeichert ist und als schnelle Gültigkeitsprüfung überprüft werden kann. Zum Beispiel enthalten gzip-Dateien 0x1f8b08 als ihre ersten drei Bytes, Java-Klassendateien beginnen mit 0xcafebabe usw.

In Dateiformaten sind häufig magische Zahlen eingebettet, da Dateien ziemlich promisku gesendet werden können und keine Metadaten darüber verloren gehen, wie sie erstellt wurden. Manchmal werden magische Zahlen jedoch auch für speicherinterne Datenstrukturen wie ioctl () -Aufrufe verwendet.

Eine schnelle Überprüfung der magischen Zahl vor der Verarbeitung der Datei oder Datenstruktur ermöglicht es, Fehler frühzeitig zu signalisieren, anstatt die möglicherweise langwierige Verarbeitung zu durchlaufen, um anzukündigen, dass die Eingabe vollständig war.


2

Es ist erwähnenswert, dass Sie manchmal nicht konfigurierbare "fest codierte" Nummern in Ihrem Code haben möchten. Es gibt eine Reihe berühmter Methoden , darunter 0x5F3759DF, die im optimierten inversen Quadratwurzel-Algorithmus verwendet werden.

In den seltenen Fällen, in denen ich die Notwendigkeit finde, solche magischen Zahlen zu verwenden, setze ich sie in meinem Code als Konstante und dokumentiere, warum sie verwendet werden, wie sie funktionieren und woher sie stammen.


1
Meiner Meinung nach bezieht sich der Geruch des magischen Zahlencodes speziell auf ungeklärte Konstanten. Solange Sie sie in eine benannte Konstante einfügen, sollte dies kein Problem sein.
Don Kirkby

2

Was ist mit der Initialisierung einer Variablen am Anfang der Klasse mit einem Standardwert? Zum Beispiel:

public class SomeClass {
    private int maxRows = 15000;
    ...
    // Inside another method
    for (int i = 0; i < maxRows; i++) {
        // Do something
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }

    public int getMaxRows() {
        return this.maxRows;
    }

In diesem Fall ist 15000 eine magische Zahl (laut CheckStyles). Für mich ist es in Ordnung, einen Standardwert festzulegen. Ich möchte nicht tun müssen:

private static final int DEFAULT_MAX_ROWS = 15000;
private int maxRows = DEFAULT_MAX_ROWS;

Erschwert das das Lesen? Ich habe das erst in Betracht gezogen, als ich CheckStyles installiert habe.


Ich denke, das wäre in Ordnung, wenn der Konstruktor den Wert initialisiert. Andernfalls, wenn der Wert außerhalb des Konstruktors initialisiert wird, sehe ich ihn nur als Ärger und als etwas schwerer zu lesen.
Thomas Eding

Ich denke, static finalKonstanten sind übertrieben, wenn Sie sie in einer Methode verwenden. Eine finalVariable, die oben in der Methode deklariert ist, ist meiner Meinung nach besser lesbar.
Eva

0

@ eed3si9n: Ich würde sogar vorschlagen, dass '1' eine magische Zahl ist. :-)

Ein Prinzip, das mit magischen Zahlen zusammenhängt, ist, dass jede Tatsache, mit der sich Ihr Code befasst, genau einmal deklariert werden sollte. Wenn Sie in Ihrem Code magische Zahlen verwenden (wie das Beispiel für die Kennwortlänge, das @marcio angegeben hat, können Sie diese Tatsache leicht duplizieren, und wenn Sie diese Tatsache verstehen, haben Sie ein Wartungsproblem.


5
IOW-Code sollte wie folgt geschrieben werden:factorial n = if n == BASE_CASE then BASE_VALUE else n * factorial (n - RECURSION_INPUT_CHANGE); RECURSION_INPUT_CHANGE = 1; BASE_CASE = 0; BASE_VALUE = 1
Thomas Eding

0

Was ist mit Rückgabevariablen?

Ich finde es besonders schwierig, gespeicherte Prozeduren zu implementieren .

Stellen Sie sich die nächste gespeicherte Prozedur vor (falsche Syntax, ich weiß, nur um ein Beispiel zu zeigen):

int procGetIdCompanyByName(string companyName);

Es gibt die ID des Unternehmens zurück, wenn es in einer bestimmten Tabelle vorhanden ist. Andernfalls wird -1 zurückgegeben. Irgendwie ist es eine magische Zahl. Einige der Empfehlungen, die ich bisher gelesen habe, besagen, dass ich wirklich so etwas entwerfen muss:

int procGetIdCompanyByName(string companyName, bool existsCompany);

Was sollte es übrigens zurückgeben, wenn das Unternehmen nicht existiert? Ok: es wird existesCompany als false setzen , aber auch -1 zurückgeben.

Eine weitere Option besteht darin, zwei separate Funktionen zu erstellen:

bool procCompanyExists(string companyName);
int procGetIdCompanyByName(string companyName);

Voraussetzung für die zweite gespeicherte Prozedur ist also, dass eine Firma existiert.

Aber ich habe Angst vor Parallelität, weil in diesem System ein Unternehmen von einem anderen Benutzer erstellt werden kann.

Das Fazit lautet übrigens: Was halten Sie von der Verwendung dieser Art von "magischen Zahlen", die relativ bekannt und sicher sind, um zu sagen, dass etwas nicht erfolgreich ist oder dass etwas nicht existiert?


Wenn in diesem speziellen Fall in der Dokumentation der Funktion angegeben ist, dass ein negativer Rückgabewert bedeutet, dass kein Unternehmen gefunden wurde, gibt es keinen Grund, eine Konstante zu verwenden.
Vincent Fourmond

-1

Ein weiterer Vorteil des Extrahierens einer magischen Zahl als Konstante bietet die Möglichkeit, die Geschäftsinformationen klar zu dokumentieren.

public class Foo {
    /** 
     * Max age in year to get child rate for airline tickets
     * 
     * The value of the constant is {@value}
     */
    public static final int MAX_AGE_FOR_CHILD_RATE = 2;

    public void computeRate() {
         if (person.getAge() < MAX_AGE_FOR_CHILD_RATE) {
               applyChildRate();
         }
    }
}
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.