Lesbarkeit versus Wartbarkeit, Sonderfall beim Schreiben verschachtelter Funktionsaufrufe

57

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 #.

Dominique
quelle
17
@gnat: Sie beziehen sich auf eine allgemeine Frage, während mich der erwähnte Fall verschachtelter Funktionsaufrufe und die Konsequenzen bei der Crash-Dump-Analyse besonders interessieren, aber danke für den Link, der einige interessante Informationen enthält.
Dominique
9
Beachten Sie, dass, wenn dieses Beispiel auf C ++ angewendet werden soll (da Sie erwähnen, dass dies in Ihrem Projekt verwendet wird), dies nicht nur eine Frage des Stils ist, da sich die Reihenfolge der Auswertung von HXund GXAufrufen 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.
Freitag,
4
Ist der Variablenname das, result_g1was Sie tatsächlich verwenden würden, oder repräsentiert dieser Wert tatsächlich etwas mit einem vernünftigen Namen? zB percentageIncreasePerSecond. Das wäre eigentlich mein Test, um mich zwischen den beiden zu entscheiden
Richard Tingle
3
Unabhängig von Ihrer Einstellung zum Kodierungsstil sollten Sie die bereits bestehende Konvention befolgen, es sei denn, dies ist eindeutig falsch (dies scheint in diesem Fall nicht der Fall zu sein).
n00b
4
@ t3chb0t Sie können frei abstimmen, wie Sie möchten, aber bitte beachten Sie, dass der Zweck der Auf- oder Abwärtsabstimmung einer Frage im Interesse der Anregung guter, nützlicher und themenbezogener Fragen auf dieser Website (und der Entmutigung von schlechten) besteht Um anzugeben, ob eine Frage nützlich und klar ist, ist es im Allgemeinen nicht hilfreich, aus anderen Gründen abzustimmen, z. B. um eine Abstimmung als Mittel zu verwenden, um Kritik an einem Beispielcode zu üben, der den Kontext der Frage unterstützt, um die Qualität der Website aufrechtzuerhalten : softwareengineering.stackexchange.com/help/privileges/vote-down
Ben Cottrell

Antworten:

111

Wenn Sie sich gezwungen fühlten, einen Einzeiler wie zu erweitern

 a = F(G1(H1(b1), H2(b2)), G2(c1));

Ich würde dir keine Vorwürfe machen. Das ist nicht nur schwer zu lesen, sondern auch schwer zu debuggen.

Warum?

  1. Es ist dicht
  2. Einige Debugger markieren nur das Ganze auf einmal
  3. Es ist frei von beschreibenden Namen

Wenn Sie es mit Zwischenergebnissen erweitern, erhalten Sie

 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);

und es ist immer noch schwer zu lesen. Warum? Es löst zwei der Probleme und führt ein viertes ein:

  1. Es ist dicht
  2. Einige Debugger markieren nur das Ganze auf einmal
  3. Es ist frei von beschreibenden Namen
  4. Es ist voll mit nicht beschreibenden Namen

Wenn Sie es mit Namen erweitern, die eine neue, gute, semantische Bedeutung hinzufügen, sogar noch besser! Ein guter Name hilft mir zu verstehen.

 var temperature = H1(b1);
 var humidity = H2(b2);
 var precipitation = G1(temperature, humidity);
 var dewPoint = G2(c1);
 var forecast = F(precipitation, dewPoint);

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_thisund result_thatweil 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:

int a = 
    F(
        G1(
            H1(b1), 
            H2(b2)
        ), 
        G2(c1)
    )
;

Es ist genauso gut lesbar, wenn nicht besser, als das mit den bedeutungslosen Ergebnisnamen (nicht, dass diese Funktionsnamen so gut sind).

  1. Es ist dicht
  2. Einige Debugger markieren nur das Ganze auf einmal
  3. Es ist frei von beschreibenden Namen
  4. Es ist voll mit nicht beschreibenden Namen

Wenn 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:

Bildbeschreibung hier eingeben

Wenn das nicht genug ist, stellen Sie G2()sich vor, Sie wurden an mehreren Stellen angerufen, und dann geschah Folgendes:

Exception in thread "main" java.lang.NullPointerException
    at composition.Example.G2(Example.java:34)
    at composition.Example.main(Example.java:18)

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:

var user = db.t_ST_User.Where(_user => string.Compare(domain,  
_user.domainName.Trim(), StringComparison.OrdinalIgnoreCase) == 0)
.Where(_user => string.Compare(samAccountName, _user.samAccountName.Trim(), 
StringComparison.OrdinalIgnoreCase) == 0).Where(_user => _user.deleted == false)
.FirstOrDefault();

Ich hasse es, diesen Strom von Lärm zu betrachten, auch wenn kein Zeilenumbruch erforderlich ist. So sieht es in diesem Stil aus:

var user = db
    .t_ST_User
    .Where(
        _user => string.Compare(
            domain, 
            _user.domainName.Trim(), 
            StringComparison.OrdinalIgnoreCase
        ) == 0
    )
    .Where(
        _user => string.Compare(
            samAccountName, 
            _user.samAccountName.Trim(), 
            StringComparison.OrdinalIgnoreCase
        ) == 0
    )
    .Where(_user => _user.deleted == false)
    .FirstOrDefault()
;

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.

kandierte_orange
quelle
20
@Steve und ich sage dir nicht, nicht zu. Ich bitte um einen aussagekräftigen Namen. Allzu oft habe ich den Zwischenstil gedankenlos gesehen. Falsche Namen verbrennen mein Gehirn weitaus mehr als spärlicher Code pro Zeile. Ich lasse mich nicht von Überlegungen zur Breite oder Länge motivieren, meinen Code dichter oder meine Namen kürzer zu machen. Ich lasse mich motivieren, mehr zu zersetzen. Wenn gute Namen einfach nicht vorkommen, sollten Sie diese Problemumgehung in Betracht ziehen, um sinnlosen Lärm zu vermeiden.
candied_orange
6
Ich füge deinem Post hinzu: Ich habe eine kleine Faustregel: Wenn du es nicht benennen kannst, könnte es ein Zeichen dafür sein, dass es nicht gut definiert ist. Ich verwende es für Entitäten, Eigenschaften, Variablen, Module, Menüs, Hilfsklassen, Methoden usw. In zahlreichen Situationen hat diese winzige Regel einen schwerwiegenden Konstruktionsfehler aufgedeckt. In gewisser Weise trägt eine gute Benennung nicht nur zur Lesbarkeit und Wartbarkeit bei, sondern hilft Ihnen auch, das Design zu überprüfen. Natürlich gibt es zu jeder einfachen Regel Ausnahmen.
Alireza
4
Die erweiterte Version sieht hässlich aus. Es ist zu viel Leerraum vorhanden, der den effektiven Wert verringert, da alles, was mit ihm phasenweise verbunden ist, nichts bedeutet.
Mateen Ulhaq
5
@MateenUlhaq Das einzige zusätzliche Leerzeichen sind ein paar Zeilenumbrüche und Einrückungen, und alles ist sorgfältig an sinnvollen Grenzen platziert. Ihr Kommentar setzt stattdessen Leerzeichen an nicht aussagekräftige Grenzen. Ich schlage vor, Sie schauen etwas näher und offener.
jpmc26
3
Im Gegensatz zu @MateenUlhaq bin ich in diesem Beispiel mit solchen Funktionsnamen auf dem Zaun über das Leerzeichen, aber mit echten Funktionsnamen (die mehr als zwei Zeichen lang sind, richtig?) Könnte es das sein, wonach ich streben würde.
Leichtigkeit Rennen mit Monica
50

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.

Dem stimme ich überhaupt nicht zu. Wenn Sie sich nur Ihre beiden Codebeispiele ansehen, wird dies als falsch bezeichnet:

var a = F(G1(H1(b1), H2(b2)), G2(c1));

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.

David Arno
quelle
37
Auch wenn ich zustimme, dass 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.
links ungefähr
23
@leftaroundabout: Für mich besteht die Schwierigkeit darin, dass es nicht offensichtlich ist, ob G13 Parameter oder nur 2 verwendet werden und G2ein weiterer Parameter ist F. Ich muss schielen und die Klammern zählen.
Matthieu M.
4
@MatthieuM. Dies kann ein Problem sein, aber wenn die Funktionen bekannt sind, ist es oft offensichtlich, welche Argumente erforderlich sind. Wie ich bereits sagte, ist es für Infix-Funktionen sofort klar, dass sie zwei Argumente annehmen. (Die in Klammern F (G1 (H1 b1) (H2 b2)) (G2 c1)
gesetzte Tupelsyntax
5
Persönlich bevorzuge ich die kompaktere Form, solange sie wie in meinem vorherigen Kommentar gestaltet ist, da sie weniger Status garantiert, den man im Kopf behalten result_h1kann. Sie kann nicht wiederverwendet werden, wenn sie nicht vorhanden ist, und der Abstand zwischen den 4 Variablen ist offensichtlich.
Izkata
8
Ich habe festgestellt, dass Code, der im Allgemeinen leicht zu debuggen ist, kein Debugging erfordert.
Rob K
25

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.

Deduplizierer
quelle
17

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:

double d = sqrt(square(x1 - x0) + square(y1 - y0));

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

double dx = x1 - x0;
double dy = y1 - y0;
double dxSquare = square(dx);
double dySquare = square(dy);
double dSquare = dxSquare + dySquare;
double d = sqrt(dSquare);

das bricht das bekannte Muster in eine scheinbar bedeutungslose Anzahl von einfachen Schritten. Allerdings die Aussage aus deiner Frage

var a = F(G1(H1(b1), H2(b2)), G2(c1));

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(), oder H2(). 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.

cmaster
quelle
14

@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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

Steve
quelle
3
+1 zu "Ist es möglich, dass der Code gewartet, aber nicht gelesen werden kann?" Das war auch mein erster Gedanke.
RonJohn
4

Beide sind suboptimal. Beachten Sie die Kommentare.

// Calculating torque according to Newton/Dominique, 4th ed. pg 235
var a = F(G1(H1(b1), H2(b2)), G2(c1));

Oder eher spezifische als allgemeine Funktionen:

var a = Torque_NewtonDominique(b1,b2,c1);

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:

var radians = ExtractAngle(c1.Normalize())
var a = Torque(b1.ToNewton(),b2.ToMeters(),radians);

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.

Peter
quelle
Zu den Kosten eines Arguments: Es gibt zwei Optimierungsregeln. 1) Tu es nicht. 2) (nur für Experten) Noch nicht .
RubberDuck
1

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.

jmoreno
quelle
1
Ich stimme allem zu, was Sie zur Lesbarkeit sagen. Aber ich bin nicht einverstanden , dass eine logische Operation in getrennte Verfahren Risse, notwendigerweise macht es besser lesbar als sie in getrennte Linien Cracken (beide Techniken , die können , wenn überstrapaziert, einfache Logik weniger lesbar machen, und machen das gesamte Programm mehr überladen) - Wenn Sie Dinge zu weit in Methoden zerlegen, emulieren Sie letztendlich Assembler-Makros und verlieren den Blick dafür, wie sie sich als Ganzes integrieren. Auch bei dieser getrennten Methode würden Sie immer noch vor dem gleichen Problem stehen: Verschachteln Sie die Aufrufe oder teilen Sie sie in Zwischenvariablen auf.
Steve
@Steve: Ich habe nicht gesagt, es immer zu tun, aber wenn Sie überlegen, 5 Zeilen zu verwenden, um einen einzelnen Wert zu erhalten, besteht eine gute Chance, dass eine Funktion besser ist. Was die Mehrfachzeilen und die komplexe Zeile betrifft: Wenn es sich um eine Funktion mit einem guten Namen handelt, funktionieren beide gleich gut.
Jmoreno
1

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

var a = F(G1(H1(b1), H2(b2)), G2(c1));

Sie können Online-Ausdrücke schreiben und trotzdem feststellen, wo das Problem liegt, indem Sie sich einfach die Stapelablaufverfolgung ansehen.

returnType F( params)
{
    returnType RealF( params);
}

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:

  • Funktionsparameter betrachten
  • Wenn die Parameter identisch sind und die Funktion keine Nebenwirkungen hat, werden zwei identische Aufrufe zu zwei identischen Aufrufen usw.

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:

type CallingGBecauseFTheorem( T b1, C b2)
{
     return G1( H1( b1), H2( b2));
}

var a = F( CallingGBecauseFTheorem( b1,b2), G2( c1));
Spielentwickler
quelle
1

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":

double d = sqrt(square(x1 - x0) + square(y1 - y0));

Wenn es in Phasen unterteilt wird (dies ist für das Testen sicherlich einfacher), verliert es den gesamten Kontext, wie oben angegeben:

double dx = x1 - x0;
double dy = y1 - y0;
double dxSquare = square(dx);
double dySquare = square(dy);
double dSquare = dxSquare + dySquare;
double d = sqrt(dSquare);

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:

if (Bill is the boss) && (i == 3) && (the carnival is next weekend)

Dieser macht mehr "kollektiven" Sinn und ist einfacher, Testbedingungen zu erstellen:

if (iRowCount == 2) || (iRowCount == 50) || (iRowCount > 100)

Und diese Aussage ist nur eine zufällige Zeichenfolge, betrachtet aus einer selbstdokumentierenden Perspektive:

var a = F(G1(H1(b1), H2(b2)), G2(c1));

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.

Ozymandias
quelle