it-swarm.com.de

Verwendung von magischen Strings / Zahlen

Dies ist ein etwas kontroverses Thema, und ich denke, es gibt so viele Meinungen wie Programmierer. Aus diesem Grund möchte ich wissen, wie die Geschäftspraktiken (oder Ihre Arbeitsplätze) üblich sind.

An meinem Arbeitsplatz haben wir strenge Kodierungsrichtlinien. Ein Abschnitt davon ist magischen Strings/Zahlen gewidmet. Es heißt (für C #):

Verwenden Sie in Ihrem Code keine anderen numerischen Werte als Zeichen oder Zeichenfolgen, außer um symbolische Konstanten zu definieren. Verwenden Sie das folgende Muster, um Konstanten zu definieren:

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

Es gibt Ausnahmen: Die Werte 0, 1 und null können fast immer sicher verwendet werden. Sehr oft sind auch die Werte 2 und -1 in Ordnung. Zeichenfolgen, die zum Protokollieren oder Nachverfolgen bestimmt sind, sind von dieser Regel ausgenommen. Literale sind zulässig, wenn ihre Bedeutung aus dem Kontext hervorgeht und keinen zukünftigen Änderungen unterliegt.

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

Eine ideale Situation wäre ein offizielles Forschungspapier, das Auswirkungen auf die Lesbarkeit/Wartbarkeit des Codes zeigt, wenn:

  • Magische Zahlen/Strings sind überall
  • Magische Zeichenfolgen/Zahlen werden vernünftigerweise (oder in unterschiedlichem Umfang) durch konstante Deklarationen ersetzt - und bitte schreien Sie mich nicht an, weil ich "vernünftig" verwende. Ich weiß, dass jeder eine andere Vorstellung davon hat, was "vernünftig" ist
  • Magische Zeichenfolgen/Zahlen werden im Übermaß und an Stellen platziert, an denen sie nicht sein müssten (siehe mein Beispiel unten).

Ich möchte dies tun, um einige wissenschaftlich fundierte Argumente zu haben, wenn ich mit einem meiner Kollegen diskutiere, der so weit geht, Konstanten zu deklarieren wie:

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

Ein anderes Beispiel wäre (und dieses ist in JavaScript):

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

Kleben Sie DOM-IDs auf Ihre Javascript-Datei, wenn diese ID nur an einer Stelle verwendet wird?

Ich habe folgende Themen gelesen:
StackExchange
StackOverflow
Bytes IT Community
Es gibt viel mehr Artikel, und nach dem Lesen dieser tauchen einige Muster auf.

Meine Frage ist also, ob wir magische Zeichenfolgen und Zahlen in unserem Code verwenden sollen. Ich suche speziell nach Expertenantworten, die nach Möglichkeit durch Referenzen gestützt werden.

33

... wenn ich mit einem meiner Kollegen streite, der so weit geht, Konstanten zu deklarieren wie:

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

Das Argument, das Sie mit Ihrem Kollegen vorbringen müssen, ist nicht die Benennung eines wörtlichen Leerzeichens als Space, sondern seine schlechte Namenswahl für seine Konstanten.

Angenommen, die Aufgabe Ihres Codes besteht darin, einen Datensatzstrom zu analysieren, der Felder enthält, die durch Semikolons (a;b;c) Getrennt sind und selbst durch Leerzeichen (a;b;c d;e;f) Getrennt sind. Wenn jemand, der Ihre Spezifikation geschrieben hat, Sie in einem Monat anruft und sagt: "Wir haben uns geirrt, die Felder in den Datensätzen sind durch Pipe-Symbole (a|b|c d|e|f) Getrennt." Was tun Sie?

Unter dem Wert-als-Name-Schema, das Ihr Kollege bevorzugt, müssten Sie den Wert des Literal ändern (SemiColon = '|') Und mit Code leben, der weiterhin SemiColon für etwas verwendet, das nicht 'ist. Es ist wirklich kein Semikolon mehr. Das führt zu negative Kommentare in Code-Reviews . Um dies zu verringern, können Sie den Namen des Literal in PipeSymbol ändern und jedes Vorkommen von SemiColon in PipeSymbol ändern. Bei dieser Rate hätten Sie genauso gut ein wörtliches Semikolon (';') Verwenden können, da Sie jede Verwendung einzeln bewerten müssen und die gleiche Anzahl von Änderungen vornehmen müssen.

Bezeichner für Konstanten müssen beschreiben, was der Wert tut, nicht was der Wert ist, und dort hat Ihr Kollege eine Linkskurve ins Unkraut gemacht . In der oben beschriebenen Feldaufteilungsanwendung ist der Zweck des Semikolons ein Feldtrennzeichen, und die Konstanten sollten entsprechend benannt werden:

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

Auf diese Weise ändern Sie beim Ändern des Feldtrennzeichens genau eine Codezeile, die Deklaration der Konstante. Jemand, der sich die Änderung ansieht, sieht nur diese eine Zeile und wird sofort verstehen, dass sich das Feldtrennzeichen von einem Semikolon in ein Pipe-Symbol geändert hat. Der Rest des Codes, der nicht geändert werden musste, weil er eine Konstante verwendete, bleibt derselbe, und der Leser muss ihn nicht durchforsten, um zu sehen, was sonst noch damit gemacht wurde.

90
Blrfl

Das Definieren von Semikolon als Konstante ist redundant, da Semikolon für sich genommen bereits konstant ist. Es wird sich nie ändern.

Es ist nicht so, dass eines Tages jemand "Änderung der Terminologie, + ist jetzt das neue Semikolon" ankündigen wird, und Ihr Kollege wird sich freuen, nur um die Konstante zu aktualisieren (sie haben mich ausgelacht - sehen Sie sie jetzt an). .

Es gibt auch eine Frage der Konsistenz. Ich garantiere, dass seine NumberTen -Konstante NICHT von jedem verwendet wird (die meisten Programmierer sind nicht verrückt), daher wird sie sowieso nicht dem Zweck dienen, den sie erwartet hatte. Wenn die Apokalypse kommt und "zehn" global auf 9 neu skaliert wird, reicht das Aktualisieren der Konstante NICHT aus, da Sie immer noch einen Haufen Literal 10 In Ihrem Code haben, sodass das System jetzt wird völlig unvorhersehbar, selbst im Rahmen einer revolutionären Annahme, dass "zehn" "9" bedeutet.

Das Speichern aller Einstellungen als Konstanten ist auch etwas, worüber ich mir Gedanken machen würde. Man sollte das nicht leichtfertig machen.

Welche Beispiele für diese Art der Nutzung haben wir bisher gesammelt? Leitungsabschluss ... maximale Anzahl von Wiederholungen ... maximale Anzahl von Rädern ... sind wir sicher, dass sich diese niemals ändern werden?

Die Kosten bestehen darin, dass das Ändern der Standardeinstellungen das Neukompilieren einer Anwendung und in einigen Fällen sogar ihrer Abhängigkeiten erfordert (da numerische Konstantenwerte beim Kompilieren möglicherweise fest codiert werden).

Es gibt auch den Test- und Verspottungsaspekt. Sie haben die Verbindungszeichenfolge als Konstante definiert, aber jetzt können Sie den Datenbankzugriff in Ihrem Komponententest nicht verspotten (eine gefälschte Verbindung herstellen).

8
Konrad Morawski
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Ihr Kollege strebt also einen täglichen WTF-Eintrag an. Diese Definitionen sind albern und überflüssig. Wie jedoch von anderen betont wurde, wären die folgenden Definitionen nicht albern oder überflüssig:

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

"Magische" Zahlen und Zeichenfolgen sind Konstanten, deren Bedeutung über ihren unmittelbaren, wörtlichen Wert hinausgeht. Wenn die Konstante 10 hat eine Bedeutung jenseits von "zehn Dingen" (z. B. als Code für eine bestimmte Operation oder Fehlerbedingung). Dann wird es zu "Magie" und sollte durch eine symbolische Konstante ersetzt werden, die diese abstrakte Bedeutung beschreibt.

Symbolische Konstanten beschreiben nicht nur die Absicht klar, sondern ersparen Ihnen auch Kopfschmerzen, wenn Sie ein Literal falsch schreiben. Eine einfache Umsetzung von "CVS" zu "CSV" in einer Codezeile durchlief Unit-Tests und Qualitätssicherung und gelangte in die Produktion, wo ein bestimmter Vorgang fehlschlug. Ja, offensichtlich waren die Geräte- und QS-Tests unvollständig und das ist ein eigenes Problem, aber die Verwendung einer symbolischen Konstante hätte dieses bisschen Sodbrennen insgesamt vermieden.

5
John Bode

Daran sollte nichts umstritten sein. Es geht nicht darum, ob magische Zahlen verwendet werden sollen oder nicht, es geht darum, lesbaren Code zu haben.
Betrachten Sie den Unterschied zwischen: if(request.StatusCode == 1) und if(request.HasSucceeded). In diesem Fall würde ich behaupten, dass Letzteres weitaus besser lesbar ist, aber das bedeutet nicht, dass Sie niemals Code wie int MaxNumberOfWheels = 18 Haben können.

P.: Deshalb hasse ich Codierungsrichtlinien. Entwickler sollten ausgereift genug sein, um solche Entscheidungen treffen zu können. Sie sollten es nicht einem Text überlassen, der von Gott weiß, wer.

3
Stefan Billiet