Ich hatte eine Diskussion mit einem Kollegen über das Brechen einer return
Anweisung und die Anweisung, die den Rückgabewert in zwei Zeilen berechnet.
Beispielsweise
private string GetFormattedValue()
{
var formattedString = format != null ? string.Format(format, value) : value.ToString();
return formattedString;
}
anstatt
private string GetFormattedValue()
{
return format != null ? string.Format(format, value) : value.ToString();
}
Was den Code betrifft, sehe ich in der ersten Variante keinen wirklichen Wert. Für mich ist letzteres klarer, insbesondere für Methoden, die so kurz sind. Sein Argument war, dass die frühere Variante einfacher zu debuggen ist - was ein kleiner Vorteil ist, da VisualStudio eine sehr detaillierte Überprüfung der Anweisungen ermöglicht, wenn die Ausführung aufgrund eines Haltepunkts gestoppt wird.
Meine Frage ist, ob es immer noch sinnvoll ist, weniger klaren Code zu schreiben, um das Debuggen zu vereinfachen. Gibt es weitere Argumente für die Variante mit der aufgeteilten Berechnung und return
Anweisung?
quelle
private string GetFormattedValue() => string.Format(format ?? "{0}", value);
Antworten:
Das Einführen von erklärenden Variablen ist ein bekanntes Refactoring, das manchmal dazu beiträgt, komplizierte Ausdrücke besser lesbar zu machen. Im gezeigten Fall jedoch
Darüber hinaus können neuere Versionen des Visual Studio - Debugger den Rückgabewert einer Funktion in den meisten Fällen zeigen , ohne eine überflüssige Variable einzuführen (aber Vorsicht, es gibt einige Einschränkungen, einen Blick auf haben diese ältere SO Post und die verschiedenen Antworten ).
In diesem speziellen Fall stimme ich Ihnen jedoch zu, dass eine erklärende Variable in der Tat die Codequalität verbessern kann.
quelle
result
als Name der Variablen. Nicht mehr so viel länger und einfacher zu debuggenresult
fügt dem Code oft nur Rauschen hinzu und erhöht selten die Lesbarkeit, was genau der Punkt ist, auf den ich antworte. Dies kann in einem Kontext gerechtfertigt sein, in dem es beim Debuggen hilft, aber ich würde es vermeiden, wenn ich einen Debugger verwende, der keine separate Variable benötigt.result
vermittelt die Information, dass dies der Wert ist, der sich aus der Funktion ergibt, so dass Sie ihn ansehen können, bevor die Funktion zurückkehrt.Angesichts der Tatsachen, dass:
a) Es gibt keine Auswirkung auf den endgültigen Code, da der Compiler die Variable entfernt.
b) Wenn es separat ist, wird die Debugging-Fähigkeit verbessert.
Ich persönlich bin zu dem Schluss gekommen, dass es eine gute Praxis ist, sie 99% der Zeit zu trennen.
Dies hat keine wesentlichen Nachteile. Das Argument, dass Code aufgebläht wird, ist eine falsche Bezeichnung, da aufgeblähter Code im Vergleich zu unlesbarem oder schwer zu debuggendem Code ein triviales Problem darstellt. Darüber hinaus kann diese Methode selbst keinen verwirrenden Code erstellen, was ganz dem Entwickler überlassen bleibt.
quelle
Oft ist es sehr hilfreich, eine Variable einzuführen, um nur ein Ergebnis zu benennen, wenn der Code selbstdokumentierender wird. In diesem Fall ist dies kein Faktor, da der Variablenname dem Methodennamen sehr ähnlich ist.
Beachten Sie, dass einzeilige Methoden keinen inhärenten Wert haben. Wenn eine Änderung mehr Zeilen einführt, aber den Code klarer macht, ist dies eine gute Änderung.
Im Allgemeinen hängen diese Entscheidungen jedoch stark von Ihren persönlichen Vorlieben ab. ZB finde ich beide Lösungen verwirrend, weil der bedingte Operator unnötig verwendet wird. Ich hätte eine if-Anweisung vorgezogen. In Ihrem Team haben Sie jedoch möglicherweise andere Konventionen vereinbart. Tun Sie dann, was Ihre Konventionen andeuten. Wenn die Konventionen zu einem solchen Fall keine Aussage machen, beachten Sie, dass dies eine äußerst geringfügige Änderung ist, die auf lange Sicht keine Rolle spielt. Wenn dieses Muster wiederholt auftritt, leiten Sie möglicherweise eine Diskussion darüber ein, wie Sie als Team diese Fälle behandeln möchten. Aber das spaltet die Haare zwischen "gutem Code" und "vielleicht ein bisschen besserem Code".
quelle
?
und a:
benutze ichif() {
und} else {
- - - -\\ :)
Als Antwort auf Ihre Fragen:
Meine Frage ist, ob es immer noch sinnvoll ist, weniger klaren Code zu schreiben, um das Debuggen zu vereinfachen.
Ja. In der Tat, einen Teil Ihrer früheren Aussage scheint mir (keine Beleidigung) ein zu wenig kurzsichtig (siehe fett unten) " Sein Argument auch immer war , dass die frühere Variante einfacher zu debuggen ist - was ziemlich ein kleines Verdienst ist , da Visual Studio ermöglicht uns eine sehr detaillierte Einsichtnahme in die Anweisungen, wenn die Ausführung aufgrund einer Unterbrechungsstelle gestoppt wird. "
Das Debuggen zu vereinfachen ist (fast) nie von " geringem Wert", da nach Schätzungen 50% der Zeit eines Programmierers für das Debuggen aufgewendet wird ( Reversible Debugging Software ).
Gibt es weitere Argumente für die Variante mit der Splitberechnung und der Return-Anweisung?
Ja. Einige Entwickler würden argumentieren, dass die Aufteilungsberechnung einfacher zu lesen ist. Dies hilft natürlich beim Debuggen, hilft aber auch, wenn jemand versucht, Geschäftsregeln zu entschlüsseln, die Ihr Code möglicherweise ausführt oder anwendet.
ANMERKUNG: Geschäftsregeln können in einer Datenbank möglicherweise besser bereitgestellt werden, da sie sich häufig ändern können. Dennoch ist eine eindeutige Kodierung in diesem Bereich nach wie vor von größter Bedeutung. ( So erstellen Sie eine Business Rules Engine )
quelle
Ich würde noch weiter gehen:
Warum?
Die Verwendung von ternären Operatoren für komplexere Logik wäre nicht lesbar. Daher würden Sie einen Stil wie den oben genannten für komplexere Anweisungen verwenden. Indem Sie diesen Stil immer verwenden, ist Ihr Code konsistent und für einen Menschen einfacher zu analysieren. Durch die Einführung dieser Art von Konsistenz (und die Verwendung von Code-Lints und anderen Tests) können Sie außerdem
goto fail
Tippfehler vermeiden .Ein weiterer Vorteil ist, dass Sie in Ihrem Bericht zur Codeabdeckung darüber informiert werden, wenn Sie vergessen haben, einen Test für
format
nicht null anzugeben. Dies wäre beim ternären Operator nicht der Fall.Meine bevorzugte Alternative - wenn Sie in der Gruppe "So schnell wie möglich eine Rendite erzielen" sind und nicht gegen Mehrfachrenditen einer Methode:
Sie können sich also die letzte Rückgabe ansehen, um die Standardeinstellung zu ermitteln.
Es ist jedoch wichtig, konsistent zu sein und alle Ihre Methoden der einen oder anderen Konvention zu folgen.
quelle
value.ToString()
unnötig aufgerufen wird, wenn das Format nicht null ist. Im Allgemeinen kann dies nicht-triviale Berechnungen umfassen und länger dauern als die Version, die eine Formatzeichenfolge enthält. Angenommen, avalue
speichert PI mit einer Million Dezimalstellen und eine Formatzeichenfolge, die nur die ersten Ziffern anfordert.private string GetFormattedValue() => string.Format(format ?? "{0}", value);
Gleicher Effekt? Verwenden Sie Unit-Tests, um die Korrektheit sicherzustellen, anstatt sich auf den Debugger zu verlassen.Ich denke nicht, dass eine solche Technik durch die Notwendigkeit des Debuggens gerechtfertigt werden kann. Ich bin selbst tausendmal auf diesen Ansatz gestoßen und mache das von Zeit zu Zeit, aber ich denke immer daran, was Martin Fowler über das Debuggen gesagt hat :
quelle
Ich denke, einige Leute, wie der Ternäroperator, sind in Fragen verstrickt, die die Frage berühren. Ja, viele Leute hassen es, also ist es vielleicht gut, es trotzdem zu erwähnen.
In Bezug auf den Fokus Ihrer Frage wird die zurückgegebene Anweisung so verschoben, dass sie von einer Variablen referenziert wird ...
Diese Frage geht von zwei Annahmen aus, mit denen ich nicht einverstanden bin:
Dass die zweite Variante klarer oder leichter zu lesen ist (ich sage das Gegenteil ist wahr), und
dass jeder Visual Studio verwendet. Ich habe Visual Studio oft verwendet und kann es problemlos verwenden, aber ich verwende normalerweise etwas anderes. Eine Entwicklungsumgebung, die eine bestimmte IDE erzwingt, ist eine, der ich skeptisch gegenüber sein würde.
Das Aufteilen auf eine benannte Variable erschwert selten das Lesen, fast immer das Gegenteil. Die spezifische Art und Weise, in der jemand dies tut, könnte Probleme verursachen, beispielsweise wenn ein Overlord der Selbstdokumentation dies tut,
var thisVariableIsTheFormattedResultAndWillBeTheReturnValue = ...
dann ist dies offensichtlich schlecht, aber dies ist ein separates Problem.var formattedText = ...
ist gut.In diesem speziellen Fall und möglicherweise in vielen Fällen, da es sich um Einzeiler handelt, sagt Ihnen die Variable nicht viel, was der Funktionsname noch nicht sagt. Daher fügt die Variable nicht so viel hinzu. Das Debugging-Argument könnte immer noch stimmen, aber auch in diesem speziellen Fall sehe ich nichts, worauf Sie sich beim Debuggen konzentrieren könnten, und es kann später jederzeit leicht geändert werden, wenn jemand das Format für das Debuggen oder etwas anderes benötigt.
Im Allgemeinen, und Sie haben nach der allgemeinen Regel gefragt (Ihr Beispiel war nur das, ein Beispiel für eine verallgemeinerte Form), sind alle Punkte, die für Variante 1 (2-Liner) gemacht wurden, korrekt. Das sind gute Richtlinien. Leitlinien müssen jedoch flexibel sein. Zum Beispiel hat das Projekt, an dem ich gerade arbeite, ein Maximum von 80 Zeichen pro Zeile, also teile ich viele Zeilen auf, aber ich finde normalerweise Zeilen von 81 bis 85 Zeichen, die sich nur umständlich aufteilen oder die Lesbarkeit verringern lassen, und ich lasse sie übrig das Limit.
Da es unwahrscheinlich ist, dass ein Mehrwert erzielt wird, würde ich für das angegebene Beispiel keine zwei Zeilen schreiben. Ich würde Variante 2 (den 1-Liner) machen, weil die Punkte nicht stark genug sind, um in diesem Fall etwas anderes zu machen.
quelle