Verschachtelte Bedingungen sind die häufigste Form von schwer lesbarem Code — und die am leichtesten zu behebende. Der Grund für die Schwierigkeit ist messbar: Bei jeder Zeile in einem Block muss der Leser alle umgebenden Bedingungen im Kopf behalten.
public string Verarbeite(Bestellung bestellung)
{
if (bestellung != null)
{
if (bestellung.Positionen.Count > 0)
{
if (bestellung.Kunde != null)
{
if (bestellung.Kunde.IstAktiv)
{
return Abschliessen(bestellung); // ← vier Bedingungen tief
}
else return "Kunde gesperrt";
}
else return "Kein Kunde";
}
else return "Keine Positionen";
}
else return "Keine Bestellung";
}Die eigentliche Aufgabe — Abschliessen aufrufen — steht ganz innen, am weitesten rechts. Die Sonderfälle stehen aussen, und ihre else-Zweige sind vom zugehörigen if durch den gesamten Rumpf getrennt.
Mit Guard Clauses kehrt sich das um: Sonderfälle zuerst, jeder mit sofortigem Ausstieg.
public string Verarbeite(Bestellung bestellung)
{
if (bestellung == null) return "Keine Bestellung";
if (bestellung.Positionen.Count == 0) return "Keine Positionen";
if (bestellung.Kunde == null) return "Kein Kunde";
if (!bestellung.Kunde.IstAktiv) return "Kunde gesperrt";
return Abschliessen(bestellung);
}Was dabei gewonnen ist
Jede Bedingung steht direkt neben ihrer Folge. Der Normalfall steht am linken Rand, nicht ganz rechts. Und ein fünfter Sonderfall ist eine Zeile — nicht eine weitere Verschachtelungsebene.
Die alte Regel «ein Ausstieg pro Methode»
Sie stammt aus einer Zeit, in der Sprachen keine finally-Blöcke und keine automatische Speicherverwaltung hatten; ein früher return sprang dann an der Aufräumarbeit vorbei. In C# gibt es using, finally und den Garbage Collector — die Begründung ist entfallen, die Regel hat sie überlebt.
Heute gilt das Gegenteil: Steig früh aus, wenn nichts mehr zu tun ist.
Schleifen mit Flags
Dasselbe Muster in einer anderen Verkleidung:
Flag und Verschachtelung
var gefunden = false;
Kunde treffer = null;
foreach (var kunde in kunden)
{
if (!gefunden)
{
if (kunde.Plz == plz)
{
if (kunde.IstAktiv)
{
treffer = kunde;
gefunden = true;
}
}
}
}LINQ
var treffer = kunden
.FirstOrDefault(k => k.Plz == plz
&& k.IstAktiv);Links muss der Leser den Zustand zweier Variablen über zwölf Zeilen mitverfolgen. Rechts steht die Frage selbst da: der erste aktive Kunde mit dieser PLZ.
LINQ ist kein Selbstzweck
Eine foreach-Schleife mit drei Anweisungen im Rumpf ist völlig in Ordnung. LINQ lohnt sich, wo eine Schleife in Wahrheit eine Frage stellt — filtern, finden, summieren, gruppieren. Wo sie etwas tut, bleibt foreach klarer; ForEach mit Nebenwirkungen in einer LINQ-Kette ist der schlechteste beider Welten.
Wann eine Methode zu verzweigt ist
Es gibt eine Zahl dafür: die zyklomatische Komplexität — grob die Anzahl unabhängiger Pfade durch eine Methode, also 1 plus die Anzahl der Verzweigungen.
Als Orientierung: bis etwa 10 unauffällig, ab 15 lohnt ein Blick, ab 20 findet niemand mehr alle Fälle. Der eingebaute Analyzer meldet das als CA1502, Rider und SonarQube zeigen es direkt an.
Die Zahl ist kein Ziel, aber ein guter Alarm: Sie steigt genau dann, wenn eine Methode anfängt, mehrere Entscheidungen gleichzeitig zu treffen.
Kurz nachgedacht
Zählt nicht — nur zum Prüfen, ob es angekommen ist.
1.Warum ist die Regel «nur ein return pro Methode» heute überholt?