Wie vermeide ich tiefe Einschnitte? [geschlossen]

17

Welche Schritte und Maßnahmen kann ich ergreifen, um tiefe Einrückungen in meinem Code zu verhindern?

Tamara Wijsman
quelle
2
Viele Leute werden hier über Refactoring sprechen. Vielleicht ist das zu viel verlangt, aber wenn Sie einen (nicht zu langen) Code gepostet haben, der tief eingerückt ist, und die Leute Ihnen zeigen könnten, wie sie ihn umgestalten würden. Natürlich macht das die
Fragensprache
3
Verwenden Sie eine kleinere Registerbreite.
mipadi
6
Pfeilspitzen- Anti-Muster. Google es, jede Menge Tipps
NimChimpsky
2
Stoppen Sie die Verwendung von Python: D
back2dos
Es ist Zeit, sich Ihre Steuerung und Schleifenlogik anzuschauen. Wahrscheinlich ist Ihr Code komplizierter als nötig, und eine Neukonzeptualisierung des Problems führt zu viel kürzerem Code. Lerne guten Code und lerne die Techniken.
Macneil

Antworten:

14

Tiefes Einrücken ist normalerweise kein Problem, wenn jede Funktion / Methode in Ihrem Programm nur eine einzige Aktion ausführt. Gelegentlich es könnte zu nisten conditionals ein paar Ebenen tief notwendig sein, aber ich kann ehrlich sagen , dass ich nur ein paar Mal in 12+ Jahre tief eingekerbt Code Kodierung geschrieben habe.

Chinmay Kanchi
quelle
26

Das Beste, was Sie tun können, ist Methoden zu extrahieren:

int Step1(int state)
{
    if (state == 100)
    {
        return Step2(state);
    }
    else
    {
        return Step3(state);
    }
}

int Step2(int state)
{
    if (state != 100)
    {
        throw new InvalidStateException(2, state);
    }

    // ....
}
ChaosPandion
quelle
2
Dies funktioniert auch bei komplexen ifBedingungen. Im Extremfall erhalten Sie ausführbaren Pseudocode.
Alan Plum
Das andere Beste, was wir tun können, ist wahrscheinlich, unnötige elseBlöcke fallen zu lassen.
Sepehr
16

Vielleicht könnten Sie Schutzklauseln in Betracht ziehen ?

Anstatt von

public void DoSomething(int value){
    if (someCondition){
           if(someOtherCondition){
                if(yetAnotherCondition){
                       //Finally execute some code
                }
           }
    }
} 

Tun

public void DoSomething(int value){
    if(!(someCondition && someOtherCondition && yetAnotherCondition)){
        return;
        //Maybe throw exception if all preconditions must be true
    }
    //All preconditions are safe execute code
}

Wenn Sie jemals eine Chance bekommen, empfehlen wir Ihnen, Code Complete von Steve McConnell zu lesen. Er hat viele gute Ratschläge zu diesen Themen.

http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_6

Weitere Informationen zu "Schutzklauseln" finden Sie unter: https://sourcemaking.com/refactoring/replace-nested-conditional-with-guard-clauses

Jason Turan
quelle
8

Invertiere dein ifs.

Anstatt von:

if (foo != null)
{
    something;
    something;
    if (x)
    {        
       something;
    }
    something;
}
else
{
    boohoo;
}

Ich würde schreiben:

if (foo == null)
{
    boohoo;
    return;
}
something;
something;
if (x)
{        
   something;
}
something;

Gleiches gilt für if- elseBlöcke. Wenn elsekürzer / weniger verschachtelt ist, machen Sie sie wieder rückgängig.

Überprüfen Sie die Parameterwerte an einer Stelle

Überprüfen Sie alle Parameter auf unzulässige Werte, sobald Sie Ihre Methode eingeben, und vergewissern Sie sich dann, dass Sie sicher sind. Es sorgt für besser lesbaren Code, erspart Ihnen jedoch später das Aufstapeln von bedingten Blöcken und das Verteilen dieser Überprüfungen auf die gesamte Subroutine.

Konrad Morawski
quelle
1
Hat dieser Stil einen bestimmten Namen?
Thomas Lauria
@ThomasLauria nicht das ich wüsste. Es ist nur früh zu beenden. Ifs am Anfang des Codes, die den Ausführungsfluss aufgrund einer nicht erfüllten Bedingung anhalten, werden auch als Schutzklauseln bezeichnet , wie @JasonTuran hervorhob. Und das scheint so nah wie möglich an einem eindeutigen Namen zu sein.
Konrad Morawski
Vor einigen Jahren sagte mir mein Vorgesetzter, dass dieser Stil als "lineare Programmierung" bezeichnet wurde, aber ich denke, dies war ein Phantasma von ihm;)
Thomas Lauria
4

Normalerweise habe ich gesehen, dass tief eingerückter Code normalerweise problematischer Code ist. Wenn Sie mit diesem Problem konfrontiert sind, treten Sie zurück und prüfen Sie, ob Ihre Funktion zu viele Aufgaben erfüllt.

Zur Beantwortung Ihrer Frage, ob eine so tiefe Einrückung erforderlich ist, schlage ich vor, dass Sie sie dort lassen. Aus dem einfachen Grund, dass in einem solchen Code der Einzug hilfreich ist, da es sich wahrscheinlich um ein sehr langes Stück Code handelt.

Vaibhav
quelle
2

Teilen Sie verschachtelte Komponenten (insbesondere wiederholte) in separate Funktionen auf (dies ist einfacher, wenn Ihre Sprache Closures unterstützt) oder ersetzen Sie eine Reihe von verschachtelten Schleifen durch eine Rekursion.

Ziehen Sie statt vier auch zwei Leerzeichen ein.

Hoa Long Tam
quelle
5
Sobald Sie den Schritt des Änderns Ihrer Registerbreite gegangen sind,
stecken
Zwei-Leerzeichen-Tabs sind das harte Zeug ....
David Thornley
6
Das Ändern des Einzugs ist nur eine Möglichkeit, das Problem zu verbergen, keine Lösung
Murph
1

Ich sehe tiefe Einkerbungen nicht als ein kategorisches Problem, das beseitigt werden muss (noch sehe ich Refactoring als die wahre Antwort auf alles).

In der Regel schreibe ich anstelle von verschachtelten ifs gerne logische Anweisungen:

if (foo && bar && baz) 

eher, als

if foo 
 if bar
   if baz
Paul Nathan
quelle
Das Problem ist, dass es auch For- und While-Schleifen gibt, die nicht unter diese Regel fallen.
Tamara Wijsman,
@TomWij: Ich versuche nicht, einen kategorischen Imperativ über den Stil zu erzwingen.
Paul Nathan
1
??? `` `` `
Tamara Wijsman
1

Ich habe es selbst nicht geglaubt, aber laut Code Complete ist dies ein geeigneter Ort break(wenn Ihr Team an Bord ist). Ich würde mir vorstellen, dass dies mit C ++ - Programmierern akzeptabler ist, wenn breaksie in switchAnweisungen verwendet werden, als mit Delphi-Programmierern break, wenn Sie keine Lust haben, eine whileSchleife zu schreiben .

Peter Turner
quelle
0

Einrückung ist in der Tat ein Kampfgedanke. Was ich gelernt habe, ist, die Methode zuerst in Teile zu teilen und dann mit einem seltsamen Trick alle folgenden Teile zu überspringen, wenn ein Teil fehlschlägt. Hier ist ein Beispiel :

Anstatt von :

 {if (networkCardIsOn() == true)
     {if (PingToServer() == true)
        {if (AccesLogin(login,pass) == true)
             {if (nextCondition == true)
                ...
         }
     }
 }

Ich schreibe derzeit:

 {vbContinue = true;

 if (vbContinue) {
       vbContinue = networkCardIsOn();
       if (vbContinue == false) {
             code to Handle This Error();
       } 
 }

 if (vbContinue) {
       vbContinue = PingToServer();
       if (vbContinue == false) {
             code to HandleThisError2();
       } 
 }

 if (vbContinue) {
       vbContinue = AccesLogin(login,pass);
      if (vbContinue == false) {
             HandleThisErrorToo();
       } 
 }
 ...

Auf den ersten Blick ist mir das seltsam vorgekommen, aber seit ich das benutze, haben sich die Wartungskosten halbiert und mein Gehirn ist am Ende des Tages kühler.

Tatsächlich besteht der durch diese "Technik" eingeführte Vorteil darin, dass die Codekomplexität wirklich geteilt wird, weil der Code weniger dicht ist.

Während Sie den Code lesen, müssen Sie sich an nichts über die vergangenen Bedingungen erinnern: Wenn Sie sich an der Stelle X im Code befinden, sind die vorherigen Schritte bestanden und erfolgreich.

Ein weiterer Vorteil ist, dass der "Fluchtweg und die Fluchtbedingung" von allen verschachtelten "if-else" vereinfacht wird.

Pierre Watelet
quelle
Können Sie näher erläutern, "die Wartungskosten wurden durch die Hälfte geteilt". Und woher wissen Sie wirklich, welche, wenn die Ausführung angehalten wird?
Chris
Ich habe etwas bearbeitet. Ich hoffe, ich beantworte Ihre Fragen ...
Pierre Watelet
2
Wenn du auch nur einfach gehen willst, hast du eine goto error_handling-Zeile.
Paul Nathan
Das ist nicht nett. Sorry, aber es ist einfach nicht.
Murph
3
anstatt einen try catch zu emulieren, warum nicht einen direkt verwenden?
Newtopian