Um magische Zahlen zu vermeiden, hören wir oft, dass wir einem Literal einen aussagekräftigen Namen geben sollten. Sowie:
//THIS CODE COMES FROM THE CLEAN CODE BOOK
for (int j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
-------------------- Change to --------------------
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
Ich habe eine Dummy-Methode wie folgt:
Erklären Sie: Ich nehme an, ich habe eine Liste von Leuten, die bedient werden müssen, und standardmäßig geben wir 5 US-Dollar aus, um nur Lebensmittel zu kaufen, aber wenn wir mehr als eine Person haben, müssen wir Wasser und Lebensmittel kaufen, müssen wir mehr Geld ausgeben, vielleicht 6 US-Dollar. Ich werde meinen Code ändern, bitte konzentrieren Sie sich auf Literal 1 , meine Frage dazu.
public int getMoneyByPersons(){
if(persons.size() == 1){
// TODO - return money for one person
} else {
// TODO - calculate and return money for people.
}
}
Als ich meine Freunde bat, meinen Code zu überprüfen, sagte einer, dass die Angabe eines Namens für den Wert 1 zu einem saubereren Code führen würde, und der andere, dass wir hier keinen konstanten Namen benötigen, da der Wert für sich genommen von Bedeutung ist.
Meine Frage lautet also: Soll ich einen Namen für den Literalwert 1 angeben? Wann ist ein Wert eine magische Zahl und wann nicht? Wie kann ich den Kontext unterscheiden, um die beste Lösung auszuwählen?
persons
und was beschreibt es? Ihr Code enthält keinerlei Kommentare, daher ist es schwierig zu erraten, was er tut.if(getErrorCode().equals(4095)) ...
Antworten:
Nein. In diesem Beispiel ist 1 absolut aussagekräftig.
Was aber, wenn persons.size () Null ist? Scheint seltsam, dass
persons.getMoney()
für 0 und 2 funktioniert, aber nicht für 1.quelle
Warum enthält ein Codeteil diesen bestimmten Literalwert?
Wenn der Literalwert eine Bedeutung hat, die sich nicht aus dem Kontext ergibt, ist es hilfreich, diesem Wert einen Namen über eine Konstante oder Variable zu geben. Wenn der ursprüngliche Kontext später vergessen wird, kann Code mit aussagekräftigen Variablennamen besser verwaltet werden. Denken Sie daran, dass das Publikum für Ihren Code nicht in erster Linie der Compiler ist (der Compiler wird gerne mit schrecklichem Code arbeiten), sondern zukünftige Betreuer dieses Codes - die es zu schätzen wissen, wenn der Code etwas selbsterklärend ist.
In Ihrem ersten Beispiel die Bedeutung von Literalen wie
34
,4
,5
aus dem Zusammenhang nicht ersichtlich. Stattdessen haben einige dieser Werte in Ihrer Problemdomäne eine besondere Bedeutung. Es war daher gut, ihnen Namen zu geben.In Ihrem zweiten Beispiel wird die Bedeutung des Buchstabens
1
aus dem Kontext sehr deutlich. Die Eingabe eines Namens ist nicht hilfreich.Tatsächlich kann es auch schlecht sein, Namen für offensichtliche Werte einzufügen, da sie den tatsächlichen Wert verbergen.
Dies kann Fehler verschleiern, wenn der benannte Wert geändert wurde oder falsch war, insbesondere wenn dieselbe Variable in nicht verwandten Codeteilen wiederverwendet wird.
Ein Teil des Codes funktioniert möglicherweise auch für einen bestimmten Wert, ist jedoch im allgemeinen Fall möglicherweise falsch. Durch die Einführung einer unnötigen Abstraktion ist der Code offensichtlich nicht mehr korrekt.
Es gibt keine Größenbeschränkung für "offensichtliche" Literale, da dies vollständig vom Kontext abhängt. ZB kann das Literal
1024
im Kontext der Dateigrößenberechnung völlig offensichtlich sein, oder das Literal31
im Kontext einer Hash-Funktion oder das Literalpadding: 0.5em
im Kontext eines CSS-Stylesheets.quelle
Es gibt verschiedene Probleme mit diesem Codeteil, die sich übrigens wie folgt verkürzen lassen:
Es ist unklar, warum eine Person ein Sonderfall ist. Ich nehme an, dass es eine bestimmte Geschäftsregel gibt, die besagt, dass das Erhalten von Geld von einer Person sich grundlegend vom Erhalten von Geld von mehreren Personen unterscheidet. Ich muss jedoch in beide hineinschauen
getMoneyIfHasOnePerson
undgetMoney
in der Hoffnung zu verstehen, warum es unterschiedliche Fälle gibt.Der Name
getMoneyIfHasOnePerson
sieht nicht richtig aus. Vom Namen würde ich erwarten, dass die Methode prüft, ob es eine einzelne Person gibt, und wenn dies der Fall ist, Geld von ihm bekommt; Sonst nichts tun. In Ihrem Code ist dies nicht der Fall (oder Sie führen die Bedingung zweimal aus).Gibt es einen Grund,
List<Money>
eher eine als eine Sammlung zurückzugeben?Zurück zu Ihrer Frage, da unklar ist, warum es für eine Person eine Sonderbehandlung gibt, sollte die Ziffer 1 durch eine Konstante ersetzt werden, es sei denn , es gibt eine andere Möglichkeit, die Regeln explizit zu machen. Hier unterscheidet man sich nicht sehr von jeder anderen magischen Zahl. Sie könnten Geschäftsregeln haben, die besagen, dass die Sonderbehandlung für eine, zwei oder drei Personen oder nur für mehr als zwölf Personen gilt.
Sie tun alles, was Ihren Code expliziter macht.
Beispiel 1
Stellen Sie sich den folgenden Code vor:
Ist Null hier ein magischer Wert? Der Code ist ziemlich klar: Wenn die Sequenz keine Elemente enthält, verarbeiten wir ihn nicht und geben einen speziellen Wert zurück. Dieser Code kann aber auch so umgeschrieben werden:
Hier nicht mehr konstant, und der Code ist noch klarer.
Beispiel 2
Nehmen Sie einen weiteren Code:
Es dauert nicht allzu lange, um zu verstehen, was es in Sprachen wie JavaScript tut, die es nicht haben
round(value, precision)
überladen sind.Wenn Sie nun eine Konstante einführen möchten, wie würde sie heißen? Der nächste Begriff, den Sie bekommen können, ist
Precision
. So:Verbessert es die Lesbarkeit? Es könnte sein. Hier ist der Wert einer Konstante eher begrenzt, und Sie können sich fragen, ob Sie das Refactoring wirklich durchführen müssen. Das Schöne daran ist, dass die Genauigkeit jetzt nur einmal deklariert wird. Wenn sie sich also ändert, riskieren Sie nicht, einen Fehler zu machen, wie zum Beispiel:
Ändern des Werts an einem Ort und Vergessen des Werts an dem anderen Ort.
Beispiel 3
Aus diesen Beispielen können Sie den Eindruck gewinnen, dass Zahlen in jedem Fall durch Konstanten ersetzt werden sollten . Das ist nicht wahr. In einigen Situationen führt eine Konstante nicht zu einer Verbesserung des Codes.
Nehmen Sie den folgenden Code:
Wenn Sie versuchen, Nullen durch eine Variable zu ersetzen, besteht die Schwierigkeit darin, einen aussagekräftigen Namen zu finden. Wie würdest du es nennen?
ZeroPosition
?Base
?Default
? Das Einführen einer Konstante hier würde den Code in keiner Weise verbessern. Es würde es etwas länger machen, und genau das.Solche Fälle sind jedoch selten. Wenn Sie also eine Nummer im Code finden, bemühen Sie sich, herauszufinden, wie der Code überarbeitet werden kann. Fragen Sie sich, ob die Nummer eine geschäftliche Bedeutung hat. Wenn ja, ist eine Konstante obligatorisch. Wenn nein, wie würden Sie die Nummer nennen? Wenn Sie einen aussagekräftigen Namen finden, ist das großartig. Wenn nicht, haben Sie wahrscheinlich einen Fall gefunden, in dem die Konstante nicht erforderlich ist.
quelle
Sie können eine Funktion erstellen, die einen einzelnen Parameter verwendet und das vierte mal geteilt durch das fünffache zurückgibt. Dabei wird ein sauberer Alias für die Funktionsweise angegeben, während das erste Beispiel verwendet wird.
Ich biete nur meine eigene gewohnte Strategie an, aber vielleicht lerne ich auch etwas.
Was ich denke ist.
Tut mir leid, wenn ich nicht in der Basis bin, aber ich bin nur ein Javascript-Entwickler. Ich bin mir nicht sicher, welche Komposition ich dafür verantwortlich gemacht habe. Ich denke nicht, dass alles in einem Array oder einer Liste enthalten sein muss, aber eine Länge würde viel Sinn ergeben. Und die * 4 würde die gute Konstante machen, da ihr Ursprung nebulös ist.
quelle
Diese Nummer 1, könnte es eine andere Nummer sein? Könnte es 2 oder 3 sein, oder gibt es logische Gründe, warum es 1 sein muss? Wenn es 1 sein muss, ist die Verwendung von 1 in Ordnung. Ansonsten können Sie eine Konstante definieren. Nennen Sie diese Konstante nicht EINS. (Ich habe das getan gesehen).
60 Sekunden in einer Minute - brauchen Sie eine Konstante? Nun, es sind 60 Sekunden, nicht 50 oder 70. Und jeder weiß es. Das kann also eine Nummer bleiben.
Pro Seite werden 60 Elemente gedruckt - diese Zahl hätte leicht 59 oder 55 oder 70 betragen können. Wenn Sie die Schriftgröße ändern, wird sie möglicherweise zu 55 oder 70. Hier ist also eher eine aussagekräftige Konstante gefragt.
Es ist auch eine Frage, wie klar die Bedeutung ist. Wenn Sie "Minuten = Sekunden / 60" schreiben, ist das klar. Wenn Sie "x = y / 60" schreiben, ist das nicht klar. Es müssen einige aussagekräftige Namen irgendwo.
Es gibt eine absolute Regel: Es gibt keine absoluten Regeln. Mit etwas Übung werden Sie herausfinden, wann Sie Zahlen verwenden müssen und wann Sie benannte Konstanten verwenden müssen. Tu es nicht, weil es in einem Buch steht - bis du verstehst, warum es das sagt.
quelle
minutes*60
, manchmal zu verwenden , selbsthours*3600
wenn ich es brauche, ohne zusätzliche Konstanten zu deklarieren. Seit Tagen würde ich wahrscheinlich schreibend*24*3600
oderd*24*60*60
weil86400
es nahe am Rand ist, wo jemand diese magische Zahl nicht auf einen Blick erkennt.Ich habe eine ganze Menge Code gesehen, wie im (modifizierten) OP bei DB-Abrufen. Die Abfrage gibt eine Liste zurück, aber die Geschäftsregeln besagen, dass es nur ein Element geben kann. Und dann änderte sich natürlich etwas für "nur diesen einen Fall" in eine Liste mit mehr als einem Element. (Ja, ich habe ein paar Mal gesagt. Es ist fast so, als ob sie ... nm)
Anstatt also eine Konstante zu erstellen, würde ich (in einer sauberen Codemethode) eine Methode erstellen, um einen Namen zu vergeben oder um zu verdeutlichen, was die Bedingung erkennen soll (und umzufassen, wie sie es erkennt):
quelle