Mein Codierungsstil für verschachtelte Funktionsaufrufe ist der folgende:
var result_h1 = H1(b1);
var result_h2 = H2(b2);
var result_g1 = G1(result_h1, result_h2);
var result_g2 = G2(c1);
var a = F(result_g1, result_g2);
Ich habe kürzlich zu einer Abteilung gewechselt, in der der folgende Codierungsstil sehr häufig verwendet wird:
var a = F(G1(H1(b1), H2(b2)), G2(c1));
Das Ergebnis meiner Art der Codierung ist, dass Visual Studio im Falle einer Absturzfunktion den entsprechenden Speicherauszug öffnen und die Zeile angeben kann, in der das Problem auftritt (ich bin besonders besorgt über Zugriffsverletzungen).
Ich befürchte, dass ich im Falle eines Absturzes aufgrund desselben auf die erste Weise programmierten Problems nicht wissen kann, welche Funktion den Absturz verursacht hat.
Auf der anderen Seite erhalten Sie umso mehr Logik auf einer Seite, je mehr Verarbeitungsschritte Sie in eine Zeile einfügen, wodurch die Lesbarkeit verbessert wird.
Ist meine Angst richtig oder fehlt mir etwas, und im Allgemeinen, was in einem kommerziellen Umfeld bevorzugt wird? Lesbarkeit oder Wartbarkeit?
Ich weiß nicht, ob es relevant ist, aber wir arbeiten in C ++ (STL) / C #.
quelle
HX
undGX
Aufrufen im Einzeiler ändern kann Die Reihenfolge der Auswertung von Funktionsargumenten ist nicht festgelegt. Wenn Sie aus irgendeinem Grund von der Reihenfolge der Nebenwirkungen (wissentlich oder unwissentlich) in den Aufrufen abhängen, kann dieses „Umgestalten des Stils“ mehr bewirken als nur die Lesbarkeit / Wartung.result_g1
was Sie tatsächlich verwenden würden, oder repräsentiert dieser Wert tatsächlich etwas mit einem vernünftigen Namen? zBpercentageIncreasePerSecond
. Das wäre eigentlich mein Test, um mich zwischen den beiden zu entscheidenAntworten:
Wenn Sie sich gezwungen fühlten, einen Einzeiler wie zu erweitern
Ich würde dir keine Vorwürfe machen. Das ist nicht nur schwer zu lesen, sondern auch schwer zu debuggen.
Warum?
Wenn Sie es mit Zwischenergebnissen erweitern, erhalten Sie
und es ist immer noch schwer zu lesen. Warum? Es löst zwei der Probleme und führt ein viertes ein:
Es ist dichtEinige Debugger markieren nur das Ganze auf einmalWenn Sie es mit Namen erweitern, die eine neue, gute, semantische Bedeutung hinzufügen, sogar noch besser! Ein guter Name hilft mir zu verstehen.
Zumindest erzählt dies eine Geschichte. Es behebt die Probleme und ist eindeutig besser als alles andere, was hier angeboten wird, aber es erfordert, dass Sie sich die Namen einfallen lassen.
Wenn du es mit bedeutungslosen Namen machst wie
result_this
undresult_that
weil dir einfach keine guten Namen einfallen, würde ich es wirklich vorziehen, wenn du uns die bedeutungslose Namensunordnung ersparst und sie mit ein paar guten alten Leerzeichen erweiterst:Es ist genauso gut lesbar, wenn nicht besser, als das mit den bedeutungslosen Ergebnisnamen (nicht, dass diese Funktionsnamen so gut sind).
Es ist dichtEinige Debugger markieren nur das Ganze auf einmalEs ist voll mit nicht beschreibenden NamenWenn dir keine guten Namen einfallen, ist das so gut wie es nur geht.
Aus irgendeinem Grund lieben Debugger neue Zeilen, daher sollten Sie feststellen, dass das Debuggen nicht schwierig ist:
Wenn das nicht genug ist, stellen Sie
G2()
sich vor, Sie wurden an mehreren Stellen angerufen, und dann geschah Folgendes:Ich finde es schön, dass jeder
G2()
Anruf auf einer eigenen Leitung geführt wird und Sie so direkt zum beleidigenden Hauptanruf weitergeleitet werden.Verwenden Sie daher bitte nicht die Probleme 1 und 2 als Entschuldigung, um uns mit Problem 4 zu beschäftigen. Verwenden Sie gute Namen, wenn Sie an sie denken können. Vermeiden Sie sinnlose Namen, wenn Sie nicht können.
Lightness Races in Orbits Kommentar weist zu Recht darauf hin, dass diese Funktionen künstlich sind und selbst tote, arme Namen haben. Hier ist ein Beispiel für die Anwendung dieses Stils auf Code aus der freien Wildbahn:
Ich hasse es, diesen Strom von Lärm zu betrachten, auch wenn kein Zeilenumbruch erforderlich ist. So sieht es in diesem Stil aus:
Wie Sie sehen, funktioniert dieser Stil gut mit dem Funktionscode, der sich in den objektorientierten Raum bewegt. Wenn Sie sich gute Namen einfallen lassen, um das im Zwischenstil zu tun, dann haben Sie mehr Kraft. Bis dahin benutze ich das. Aber bitte finden Sie auf jeden Fall einen Weg, um bedeutungslose Ergebnisnamen zu vermeiden. Sie machen meine Augen weh.
quelle
Dem stimme ich überhaupt nicht zu. Wenn Sie sich nur Ihre beiden Codebeispiele ansehen, wird dies als falsch bezeichnet:
ist zu lesen zu hören. "Lesbarkeit" bedeutet nicht Informationsdichte; es bedeutet "einfach zu lesen, zu verstehen und zu warten".
Manchmal ist der Code einfach und es ist sinnvoll, eine einzelne Zeile zu verwenden. In anderen Fällen wird das Lesen dadurch nur erschwert, da es keinen offensichtlichen Vorteil hat, mehr auf eine Zeile zu schreiben.
Ich möchte Sie jedoch auch darauf hinweisen, dass "einfach zu diagnostizierende Abstürze" eine einfache Wartung des Codes bedeuten. Code, der nicht abstürzt, ist weitaus einfacher zu warten. "Pflegeleicht" wird in erster Linie durch den Code erreicht, der leicht zu lesen und zu verstehen ist und durch eine Reihe von automatisierten Tests abgesichert ist.
Wenn Sie also einen einzelnen Ausdruck in einen mehrzeiligen Ausdruck mit vielen Variablen umwandeln, nur weil Ihr Code häufig abstürzt und Sie bessere Debuginformationen benötigen, hören Sie auf, dies zu tun, und machen Sie den Code stattdessen robuster. Sie sollten es vorziehen, Code zu schreiben, für den kein Debugging erforderlich ist, statt Code, der einfach zu debuggen ist.
quelle
F(G1(H1(b1), H2(b2)), G2(c1))
das schwer zu lesen ist, hat dies nichts mit zu dichtem Gedränge zu tun. (Ich bin mir nicht sicher, ob Sie das sagen wollten, aber es könnte so interpretiert werden.) Das Verschachteln von drei oder vier Funktionen in einer einzigen Zeile kann perfekt lesbar sein, insbesondere wenn einige der Funktionen einfache Infix-Operatoren sind. Es sind die nicht beschreibenden Namen, die hier das Problem sind, aber dieses Problem ist noch schlimmer in der mehrzeiligen Version, in der noch mehr nicht beschreibende Namen eingeführt werden. Das Hinzufügen von nur einer Kesselplatte trägt fast nie zur Lesbarkeit bei.G1
3 Parameter oder nur 2 verwendet werden undG2
ein weiterer Parameter istF
. Ich muss schielen und die Klammern zählen.F (G1 (H1 b1) (H2 b2)) (G2 c1)
result_h1
kann. Sie kann nicht wiederverwendet werden, wenn sie nicht vorhanden ist, und der Abstand zwischen den 4 Variablen ist offensichtlich.Ihr erstes Beispiel, das Einfachzuweisungsformular, ist nicht lesbar, da die gewählten Namen absolut bedeutungslos sind. Das könnte ein Artefakt sein, wenn Sie versuchen, interne Informationen von Ihrer Seite nicht preiszugeben. Der wahre Code könnte in dieser Hinsicht in Ordnung sein, können wir nicht sagen. Auf jeden Fall ist es aufgrund der extrem geringen Informationsdichte langwierig, was sich im Allgemeinen nicht für ein leichtes Verständnis eignet.
Ihr zweites Beispiel ist zu einem absurden Grad zusammengefasst. Wenn die Funktionen nützliche Namen hätten, wäre das vielleicht in Ordnung und gut lesbar, weil es nicht zu viel davon gibt, aber wie es ist, ist es in der anderen Richtung verwirrend.
Nachdem Sie aussagekräftige Namen eingegeben haben, können Sie prüfen, ob eine der Formen natürlich erscheint oder ob es eine goldene Mitte gibt, auf die Sie schießen müssen.
Jetzt, wo Sie lesbaren Code haben, werden die meisten Fehler offensichtlich sein, und die anderen haben es zumindest schwerer, sich vor Ihnen zu verstecken.
quelle
Wie immer ist das Scheitern in Bezug auf die Lesbarkeit extrem . Sie können jeden guten Programmierratschlag annehmen , ihn in eine religiöse Regel verwandeln und ihn verwenden, um völlig unlesbaren Code zu erstellen. (Wenn Sie mir diesbezüglich nicht glauben , schauen Sie sich diese beiden IOCCC- Gewinner Borsanyi und Goren an und sehen Sie sich an, wie unterschiedlich sie Funktionen verwenden, um den Code vollständig unlesbar zu machen. Hinweis: Borsanyi verwendet genau eine Funktion, Goren, viel, viel mehr ...)
In Ihrem Fall sind die beiden Extreme: 1) nur einzelne Ausdrucksanweisungen verwenden und 2) alles zu großen, knappen und komplexen Anweisungen zusammenfügen. Bei beiden extremen Vorgehensweisen ist Ihr Code nicht mehr lesbar.
Ihre Aufgabe als Programmierer ist es , ein Gleichgewicht zu finden . Für jede Anweisung, die Sie schreiben, ist es Ihre Aufgabe, die Frage zu beantworten: "Ist diese Anweisung leicht zu verstehen und dient sie dazu, meine Funktion lesbar zu machen?"
Der Punkt ist, dass es keine messbare Aussagekomplexität gibt, die entscheiden kann, was gut ist, in eine einzige Aussage aufgenommen zu werden. Nehmen Sie zum Beispiel die Zeile:
Dies ist eine recht komplexe Aussage, aber jeder Programmierer, der sein Geld wert ist, sollte in der Lage sein, sofort zu verstehen, was dies tut. Es ist ein ziemlich bekanntes Muster. Als solches ist es viel lesbarer als das Äquivalent
das bricht das bekannte Muster in eine scheinbar bedeutungslose Anzahl von einfachen Schritten. Allerdings die Aussage aus deiner Frage
scheint mir zu kompliziert, obwohl es eine Operation weniger als die Entfernungsberechnung ist . Natürlich ist das eine direkte Folge von mir nichts zu wissen , über
F()
,G1()
,G2()
,H1()
, oderH2()
. Ich könnte anders entscheiden, wenn ich mehr über sie wüsste. Aber genau das ist das Problem: Die sinnvolle Komplexität einer Aussage hängt stark vom Kontext und den damit verbundenen Operationen ab. Und Sie als Programmierer müssen sich diesen Kontext ansehen und entscheiden, was in eine einzelne Anweisung aufgenommen werden soll. Wenn Sie Wert auf Lesbarkeit legen, können Sie diese Verantwortung nicht auf statische Regeln übertragen.quelle
@Dominique, ich denke in der Analyse Ihrer Frage machen Sie den Fehler, dass "Lesbarkeit" und "Wartbarkeit" zwei getrennte Dinge sind.
Ist es möglich, dass Code gewartet, aber nicht gelesen werden kann? Wenn Code hingegen sehr gut lesbar ist, warum sollte er aufgrund seiner Lesbarkeit nicht mehr verwaltbar sein? Ich habe noch nie von einem Programmierer gehört, der diese Faktoren gegeneinander ausspielte und sich für den einen oder anderen entscheiden musste!
In Bezug auf die Entscheidung, ob Zwischenvariablen für verschachtelte Funktionsaufrufe verwendet werden sollen, würde ich im Fall von 3 gegebenen Variablen, Aufrufen von 5 separaten Funktionen und einigen Aufrufen, die 3 tief verschachtelt sind, dazu tendieren, zumindest einige Zwischenvariablen zu verwenden, um dies aufzuschlüsseln. wie du getan hast.
Aber ich gehe sicher nicht so weit zu sagen, dass Funktionsaufrufe niemals verschachtelt werden dürfen. Es ist eine Frage des Urteils unter den gegebenen Umständen.
Ich würde sagen, die folgenden Punkte betreffen das Urteil:
Wenn die aufgerufenen Funktionen mathematische Standardoperationen darstellen, können sie besser verschachtelt werden als Funktionen, die eine undurchsichtige Domänenlogik darstellen, deren Ergebnisse nicht vorhersehbar sind und vom Leser nicht unbedingt mental bewertet werden können.
Eine Funktion mit einem einzelnen Parameter kann besser an einem Nest teilnehmen (entweder als innere oder äußere Funktion) als eine Funktion mit mehreren Parametern. Das Mischen von Funktionen verschiedener Aritäten auf verschiedenen Verschachtelungsebenen kann dazu führen, dass der Code wie ein Schweineohr aussieht.
Ein Nest von Funktionen, die Programmierer auf eine bestimmte Art und Weise zu sehen gewohnt sind - vielleicht weil es eine mathematische Standardtechnik oder -gleichung darstellt, die eine Standardimplementierung hat -, ist möglicherweise schwieriger zu lesen und zu überprüfen, ob sie in Zwischenvariablen zerlegt sind.
Ein kleines Nest von Funktionsaufrufen, das einfache Funktionen ausführt und bereits lesbar ist und dann übermäßig und zerstäubt zerlegt wird, ist möglicherweise schwieriger zu lesen als einer, der überhaupt nicht zerlegt wurde.
quelle
Beide sind suboptimal. Beachten Sie die Kommentare.
Oder eher spezifische als allgemeine Funktionen:
Berücksichtigen Sie bei der Entscheidung, welche Ergebnisse buchstabiert werden sollen, die Kosten (Kopie vs. Referenz, L-Wert vs. R-Wert), die Lesbarkeit und das Risiko für jede Aussage einzeln.
Es ist beispielsweise kein Mehrwert, einfache Einheiten- / Typumrechnungen in eigene Zeilen zu verschieben, da diese leicht zu lesen sind und äußerst unwahrscheinlich ausfallen:
In Bezug auf die Analyse von Absturzabbildern ist die Validierung von Eingaben in der Regel weitaus wichtiger: Es ist sehr wahrscheinlich, dass der eigentliche Absturz innerhalb dieser Funktionen und nicht innerhalb der aufrufenden Zeile auftritt, und selbst wenn dies nicht der Fall ist, müssen Sie normalerweise nicht genau wissen, wo Dinge explodierten. Es ist viel wichtiger zu wissen, wo Dinge auseinanderzufallen begannen, als zu wissen, wo sie schließlich explodierten, was die Validierung von Eingaben einfängt.
quelle
Lesbarkeit ist der Hauptteil der Wartbarkeit. Bezweifle ich Wählen Sie ein großes Projekt in einer Sprache aus, die Sie nicht kennen (wahrscheinlich sowohl die Programmiersprache als auch die Sprache der Programmierer), und sehen Sie, wie Sie es umgestalten würden ...
Ich würde die Lesbarkeit auf einen Wert zwischen 80 und 90 setzen. Die anderen 10 bis 20 Prozent sind für Refactoring geeignet.
Das heißt, Sie übergeben effektiv 2 Variablen an Ihre endgültige Funktion (F). Diese 2 Variablen werden mit 3 anderen Variablen erstellt. Es wäre besser gewesen, b1, b2 und c1 an F zu übergeben. Wenn F bereits vorhanden ist, erstellen Sie D, das die Komposition für F ausführt und das Ergebnis zurückgibt. An diesem Punkt geht es nur darum, D einen guten Namen zu geben, und es spielt keine Rolle, welchen Stil Sie verwenden.
Auf einem verwandten nicht, sagen Sie, dass mehr Logik auf der Seite die Lesbarkeit fördert. Das ist falsch, die Metrik ist nicht die Seite, sondern die Methode, und je weniger Logik eine Methode enthält, desto lesbarer ist sie.
Lesbar bedeutet, dass der Programmierer die Logik (Eingabe, Ausgabe und Algorithmus) im Kopf behalten kann. Je mehr es tut, desto WENIGER kann es ein Programmierer verstehen. Informieren Sie sich über die zyklomatische Komplexität.
quelle
Unabhängig davon, ob Sie sich in C # oder C ++ befinden, besteht eine mögliche Lösung darin, die Funktionen zu verpacken, solange Sie sich in einem Debugbuild befinden
Sie können Online-Ausdrücke schreiben und trotzdem feststellen, wo das Problem liegt, indem Sie sich einfach die Stapelablaufverfolgung ansehen.
Wenn Sie dieselbe Funktion mehrmals in derselben Zeile aufrufen, können Sie natürlich nicht wissen, welche Funktion Sie verwenden. Sie können sie jedoch trotzdem identifizieren:
Dies ist keine Wunderwaffe, aber auf halbem Weg nicht so schlimm.
Ganz zu schweigen davon, dass das Umbrechen von Funktionsgruppen für die Lesbarkeit des Codes sogar noch vorteilhafter sein kann:
quelle
Meiner Meinung nach ist selbstdokumentierender Code sowohl für die Wartbarkeit als auch für die Lesbarkeit besser, unabhängig von der Sprache.
Die obige Aussage ist dicht, aber "selbstdokumentierend":
Wenn es in Phasen unterteilt wird (dies ist für das Testen sicherlich einfacher), verliert es den gesamten Kontext, wie oben angegeben:
Und offensichtlich ist es von unschätzbarem Wert, Variablen- und Funktionsnamen zu verwenden, die ihren Zweck eindeutig angeben.
Selbst "wenn" -Blöcke können in der Selbstdokumentation gut oder schlecht sein. Das ist schlecht, weil Sie die ersten beiden Bedingungen nicht einfach zwingen können, die dritte zu testen ... alle haben nichts miteinander zu tun:
Dieser macht mehr "kollektiven" Sinn und ist einfacher, Testbedingungen zu erstellen:
Und diese Aussage ist nur eine zufällige Zeichenfolge, betrachtet aus einer selbstdokumentierenden Perspektive:
Angesichts der obigen Aussage ist die Wartbarkeit immer noch eine große Herausforderung, wenn die Funktionen H1 und H2 dieselben "Systemstatusvariablen" ändern, anstatt zu einer einzigen "H" -Funktion zusammengefasst zu werden, da irgendwann jemand H1 ändern wird, ohne überhaupt zu glauben, dass es eine gibt H2-Funktion zu betrachten und könnte H2 brechen.
Ich halte gutes Code-Design für eine große Herausforderung, da es keine festen Regeln gibt, die systematisch erkannt und durchgesetzt werden können.
quelle