Guter Code, ist lesbarer Code


Ich programmiere schon länger und habe schon so manche Zeile an Code geschrieben und gelesen. Aber im Laufe seiner Laufbahn als Programmierer wird man immer wieder über ein Problem stolpern, welches einen dazu veranlasst wieder etwas dazu zu lernen, auch wenn es nur etwas Banales ist wie Enumerationen.

Ich hatte folgendes Problem: Es gab eine Variable oder Routine, die nur zwei Zustände annehmen können sollte, die Ausrichtung einer Seitenzahl auf einer Seite, entweder mittig auf der Seite zentriert oder am äusseren Rand der Seite. Man kann hiermit ganzen Zahlen arbeiten: 0 für mittig zentriert und 1 für am äusseren Rand. Das ist ist aber nicht ganz befriedigen, den nach einiger Zeit weiß man nicht mehr, welche Zahl für was steht. Und ein Aussenstehender weiß es schon gar nicht. Diese Lösung wäre so gut wie unlesbar, kaum wartbar und sehr fehleranfällig, denn was passiert, wenn jemand zwei oder drei oder minus vier übergibt? Wir haben also zwei Probleme: 1. Lesbarkeit des Codes und 2. Anfälligkeit für Fehler.

Betrachten wir Punkt eins und nehmen uns mal eine Windows Funktion vor: CreateEvent:

HANDLE WINAPI CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL bManualReset,
  BOOL bInitialState,
  LPCTSTR lpName
);

Problematisch sind hier die zwei Boolean-Parameter. Es wird nicht deutlich, was ein Setzen auf Wahr oder Falsch bewirkt. Wird der erste auf Wahr gesetzt, habe ich dann ein manuelles Zurücksetzen oder nicht? Und was ist der Unterschied zwischen einem wahren und einem falschen Initialisierungstatus? Da hilft es nur in der Hilfe nachzugucken. Eine kleine Hilfe ist schon die Code-Vervollständigung der IDE, aber die hat man auch nicht immer zur Hand (in einem Forum, einer E-Mail, wenn man den Code in einem einfachen Editor betrachtet, als Ausdruck oder mit einem Overheadprojektor). Und oft Mals schreibt man den Code nicht selber, sondern liest ihn nur. Besser wären in diesem Fall Aufzählungstypen mit zum Beispiel den Werten: MANUEL_RESET und AUTO_RESET, dann wäre beim Lesen alles klar. Beim zweiten Boolean-Parameter könnte man sinngemäß verfahren.

Kommen wir zurück zu meinem konkreten Problem. Es hat etwas gedauert, aber ich bin dann doch auf eine gute Lösung gekommen. Ich habe mich nachher etwas geärgert, dass ich so lange dafür gebraucht habe, obwohl ich sie die ganze Zeit vor der Nase hatte: Die Lösung ist eine Aufzählung. Eine Aufzählung wie sie zum Beispiel von der VCL benutzt wird, um einen Absatz in einem TMemo auszurichten: taCenter, taLeftJustify, taRightJustify. Mit der Aufzählung hat man einen eigenen Datentypen mit einem vorgegebenen Bereich und benannten Konstanten, wenn man so will. Eine Lösung in Delphi sähe also so aus:

type
  TPageNumberAlignment = (paCenter, paLeft, paRight);

procedure SetPageNumberAlignment(Alignment: TPageNumberAlignment);
begin
  case Alignment of
    paCenter: ShowMessage('zentriert');
    paLeft: ShowMessage('links');
    paRight: ShowMessage('rechts');
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetPageNumberAlignment(paCenter);
end;

Damit haben wir mit einem Schlag unser beiden Probleme gelöst: Der Code ist lesbar und er ist nicht mehr fehleranfällig, da jetzt nur genau drei Werte eines bestimmten Datentyps übergeben werden können.

Man sieht also dass ein lesbarer Code in den meisten Fällen auch guten Code erzeugt. Deswegen der Grundsatz: "Design for readability". Oder in etwa auf deutsch: "Entwerfen für die Lesbarkeit". Wenn man sich an diesen Grundsatz orientiert beim Programmieren, ergibt sich ein zweiter Grundsatz von alleine: "So wenig Kommentare wie möglich, so viele wie nötig." Man sollte also nur das kommentieren, was nicht aus dem Code ersichtlich ist. Das Inkrementieren einer Variablen zu kommentieren ist überflüssig, wenn man den Code liest, sieht man ja, was passiert. Während hingegen das warum eventuell Sinn ergeben könnte.

Bleibt noch die Frage zu klären, wie man denn lesbaren, guten Code schreibt. Ich denke, das kann man nicht richtig lernen. da hilf wohl wirklich nur Erfahrung, die man sich über Jahre aneignet und das Lesen und Studieren von fremden Code. Obwohl, manchmal muss man gar nicht in die ferne schweifen. Oftmals reicht es schon aus, wenn man sich alten Code von sich selber nach ein, zwei Jahren wieder mal anguckt. Versteht man ihn ohne lange darüber nachzudenken, wie er funktioniert, was er macht und warum man das damals so und nicht anders gelöst hat, war es guter Code. Andernfalls könnte er etwas Überarbeitung gebrauchen. Eventuell hilft ja auch der Ratschlag von Donald Edwin Knuth:

Let us change our traditional attitude to the construction of programs. Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.

Oder um es mit den Worten des Pascal Erfinders, Niklaus Wirth, zu sagen:

Programs should be written and polished until they acquire publication quality.

2010-12-29T23:44:48 +0100, mail+homepage[at]michael-puff.de