Best practice – If Statements

Erst neulich habe ich mit Kollegen über ihre Vorgehensweise beim Schreiben von if Statements im Code unterhalten. Die Meinungen gingen nicht sehr weit auseinander aber waren dennoch aufschlussreich. Herausgestellt haben sich dabei folgende Vorlieben bei der Entwicklung:

  • Eine positive Aussage im Statementblock sollte einer negativen vorgezogen werden. Somit vermeidet man eine doppelte Verneinung.
  • Zu tiefe Verschachtelung vermeiden. z.B. early returns.
  • Wiederholungen in aussagekräftige Methoden extrahieren.
  • Das zuerst erwartete Statement auch zuerst behandeln.

 

Doppelte Verneinung ist ein Problem? Ja betrachten wir folgende Snippets:

// Doppelte Verneinung
if ( !IsInvalid( myValue ) )
{
   // ...
}

// Positive Auswertungen lesen sich leichter ( und leichter verneinen )
if ( IsValid( myValue ) )
{

}

 

Gehen wir von folgenden Codesnippet aus ohne dabei die Logik auf Vollständigkeit zu betrachten:

if (currentOperator != ' ')
{
 if (currentOperator.Equals('*'))
 {
  currentNumberDouble = MultiplyNumbers(currentNumberString, temporaryNumberString);
  if (operatorOnHold.Equals('+'))
  {
   total += currentNumberDouble;
  }
  else if (operatorOnHold.Equals('-'))
  {
   total -= currentNumberDouble;
  }
  else
  {
   total = currentNumberDouble;
  }
 }
 else if (currentOperator.Equals('/'))
 {
  currentNumberDouble = DivideNumbers(temporaryNumberString, currentNumberString);
  if (operatorOnHold.Equals('+'))
  {
   total += currentNumberDouble;
  }
  else if (operatorOnHold.Equals('-'))
  {
   total -= currentNumberDouble;
  }
  else
  {
   total = currentNumberDouble;
  }
 }
}

Eine zu tiefe Verschachtelung lässt sich hier vermeiden indem man nach dem ersten Statement die Methode verlässt. Das lässt sich für Entwickler auch leichter lesen, da die Abbruchbedingung direkt klar gemacht wird. ( Regel 2 & Regel 4 )

if (IsInvalidOperator(currentOperator))
{
    return;
}
//...

Anstatt jeden Operator mit einem Zeichen zu vergleichen und somit zu erwarten, dass andere Entwickler den Context genau kennen, arbeitet man besser mit Methoden in Statements. ( Regel 1 & Regel 3 )

if (IsMultiplication(currentOperator))
{
 currentNumberDouble = MultiplyNumbers(currentNumberString, temporaryNumberString);
 if (IsAddition(operatorOnHold))
 {
  total += currentNumberDouble;
 }
 else if (IsSubtraction(operatorOnHold))
 {
  total -= currentNumberDouble;
 }
 else
 {
  total = currentNumberDouble;
 }
}
else if (IsDivide(currentOperator))
{
 currentNumberDouble = DivideNumbers(temporaryNumberString, currentNumberString);
 if (IsAddition(operatorOnHold))
 {
  total += currentNumberDouble;
 }
 else if (IsSubtraction(operatorOnHold))
 {
  total -= currentNumberDouble;
 }
 else
 {
  total = currentNumberDouble;
 }
}

Somit hätten wir auch die Überprüfungen der Operator nicht als doppelten Code überall in unserer Methode verstreut, sondern in aussagekräftigen Methoden gekapselt.

Es lässt sich immer viel an der Lesbarkeit einer Methode tun. Am einfachsten ist dies jedoch indem man seinen Entscheidungen auch Namen gibt. Diese am besten aus positiver Sicht betrachten um doppelte Verneinungen zu vermeiden.