Software Enginering

Lesbarkeit von Programmen

Programme werden von Computern ausgeführt, aber von Menschen gelesen. Dem Computer ist es egal, wie der Programmcode formatiert ist, ob eine Funktion xp5q3 oder isEmpty heißt, und ob Kommentare vorhanden sind. Ein Mensch aber, der das Programm vielleicht weiter­entwickeln möchte, ist darauf angewiesen, dass es lesbar ist. Dies betrifft auch den Autor des Programms selbst, der nach einem halben Jahr meist auch nicht mehr weiß, was die Funktion neu_berech1 genau tun sollte.

Die Anforderungen an die Qualität von Software umfassen nicht nur

Zur Struktur gehört die Architektur des Systems, also die zweckmäßige Auf­teilung des Programms in Pakete, Klassen und Funktionen. Zur Struktur im weiteren Sinn gehört aber auch die Über­sicht­lich­keit des Programms, beginnend bei einer sauberen Formatierung über geeignete Benennungen von Klassen, Funktionen und Variablen bis hin zu einer sinnvollen Kommentierung wichtiger Programm­stücke.

Die Kriterien für eine gute Software­struktur sind also

Strukturierung

Ein Programm ist nur dann über­sicht­lich, wenn man es auch tatsächlich übersehen bzw. überblicken kann. Dies ist der Fall, wenn jede Funktion auf eine Bildschirm­seite passt (bei großen Bildschirmen: auf eine halbe Bildschirm­seite).

Wenn Sie merken, dass eine Funktion länger wird, ist es Zeit, sich über eine weiter­gehende Strukturierung der Funktion Gedanken zu machen. Lagern Sie dann zusammen­gehörige Teile der Funktion in jeweils eigene Funktionen aus.

Führen Sie Funktionen nicht nur für den Fall ein, dass ein Programm­stück mehrfach gebraucht wird, sondern auch zum reinen Zweck der Strukturierung des Programms.

public static void main(String[] args)
{
    int port=10500;    // Standardport zur Kommunikation
    Client client=new SimpleClient();

    // Verbindung zum Server aufbauen
    client.connect("localhost", port);

    // Nachrichten des Servers verarbeiten
    while (client.isConnected())
        client.processMessages();
}

Formatierung

Selbst einfachste Programme sind schwer zu verstehen, wenn der Programmcode nicht sauber formatiert ist.

Software-Entwurfs-Umgebungen wie Eclipse ermöglichen eine automatische Formatierung des Programm­codes. Stellen Sie die Formatierung so ein, dass zusammen­gehörige geschweifte Klammern immer übereinander stehen und dass der dazwischen stehende Programmcode deutlich eingerückt ist:

while (i<100)
{
    if (isPrime(i))     
    {
        s=s+i;
        k=k+1;
    }
    i=i+2;
}

 

Häufig anzutreffen ist eine Formatierung in der Weise, dass die öffnende geschweifte Klammer nicht in eine eigene Zeile gesetzt wird:

while (i<100) {
    if (isPrime(i)) {   
        s=s+i;
        k=k+1;
    }
    i=i+2;
}

Hierdurch wird zwar Platz gespart, aber Über­sicht­lich­keit entsteht gerade dadurch, dass großzügig mit Platz umgegangen wird. Daher ist von dieser Art der Formatierung abzuraten.

Benennung und Schreibweise von Klassen, Funktionen, Variablen

Genauso schwierig, aber auch genauso wichtig wie das Programmieren selbst ist es, treffende Benennungen für Klassen, Funktionen und Variablen zu finden.

Investieren Sie hierfür genügend Zeit. Es ist eine Investition, die sich auszahlt: Sie benötigen später dafür umso weniger Zeit, um Ihr eigenes Programm zu verstehen.

Wenn Sie merken, dass Sie eine etwa Funktion oder Variable ungeschickt benannt haben, können Sie durch Refactoring diesen Mangel schnell beheben.

Es ist sinnvoll, Englisch als Sprache für die Benennung von Klassen, Funktionen und Variablen zu verwenden und sich dabei an bestimmte Konventionen der Schreibweise zu halten.

Klassen

Position, Client, BoardIterator

(großer Anfangs­buchstabe, intern ggf. weitere Groß­buchstaben (camel case)).

Funktionen

Je nach Rückgabetyp:

(kleiner Anfangs­buchstabe, intern ggf. Groß­buchstaben (camel case))

Variablen

i, p, pos, lastmove, startfields (nur Klein­buchstaben)

Für lokale Variablen und Parameter genügen kurze Namen wie a, i, und n. Denn diese Variablen haben ja nur einen kurzen Gültigkeits­bereich, und dort können wir uns den Verwendungs­zweck etwa eines Arrays merken, auch wenn es einfach a heißt.

Also nicht so:

if (array_to_be_sorted[currentIndex1-1]>array_to_be_sorted[currentIndex1])
{
    temporaryValue=array_to_be_sorted[currentIndex1-1];
    array_to_be_sorted[currentIndex1-1]=array_to_be_sorted[currentIndex1];
    array_to_be_sorted[currentIndex1]=temporaryValue;
}

sondern so:

if (a[i-1]>a[i])
{
    t=a[i-1];
    a[i-1]=a[i];
    a[i]=t;
}

Globale Variablen und Objekt­attribute sollten dagegen längere Namen haben, da sie einen größeren Gültigkeits­bereich haben, also z.B. lastmove, startfields usw. Wenn wir ein Objekt­attribut statt lastmove einfach m nennen, besteht zudem die Gefahr von Verwechslungen mit lokalen Variablen namens m.

"Ungarische Notation" – don't use it

Abzuraten ist davon, den Typ einer Variablen in ihrem Namen mitzucodieren, also die Benennung iCnt für eine Variable vom Typ int oder strZeile für eine Variable vom Typ String oder objDatei für eine Variable vom Typ Object.

for (iCnt=0; iCnt<iAnz; iCnt++)
{
    strZeile=objDatei.readLine();
    . . .
}

Die Lesbarkeit leidet erheblich, und der Typ der Variablen lässt sich leicht anhand ihrer Deklaration feststellen. Moderne Entwicklungs­umgebungen zeigen im Übrigen auch den Typ einer Variablen an, wenn man mit dem Mauszeiger darüberfährt (Bild 1).

for (i=0; i<ni++)
{
    line=file.readLine();
    . . .
}

 

Bild 1: Anzeige des Typs einer Variablen mit dem Mauszeiger

 

Kommentare

Sinnvolle Kommentare an den ent­scheidenden Stellen des Programms ermöglichen ein leichtes Verständnis. Kommentierung hat aber auch Rück­wirkungen auf das Programmieren selbst: Wir merken, dass wir eine Funktion wohl schlecht implementiert haben, wenn wir nur einen sehr umständ­lichen Kommentar über ihre Arbeitsweise zustande bringen.

Kommentare sind auch in deutscher Sprache zulässig, jedenfalls solange Sie nicht in einem inter­nationalen Entwickler­team arbeiten.

Beschreiben Sie über jeder Funktion den Zweck der Funktion; nennen Sie dabei die Argumente und den Rückgabewert:

// Gibt true zurück, wenn Position p frei ist
public boolean isFree(Position p)
{
    ...
}

Bei längeren Funktionen erläutern Sie kurz die Arbeitsweise der Funktion:

// Wartet auf eine Nachricht vom Server. Eine eintreffende
// Nachricht wird dekodiert und je nach Inhalt weiterverarbeitet. 
public void processMessage()
{
    ...
}

Mit Zeilen­kommentaren können Sie den Zweck bestimmter Anweisungen erläutern, wenn diese nicht selbst­erklärend sind:

w=2*v+1;     // w ist erster Nachfolger von v

Vermeiden Sie jedoch überflüssige Kommentare:

i=i+1;       // i um 1 erhöhen

Schreiben Sie insgesamt nicht so viel Kommentar, dass der Programmcode darin untergeht. Das Programm sollte immer noch als zusammen­hängendes Ganzes erkennbar bleiben.

Literatur

[Mar 09]   R.C. Martin: Clean Code. Prentice Hall (2009)

[Fow 99]   M. Fowler: Refactoring. Addison-Wesley (1999)

 

 

 

[up]

 


H.W. Lang   mail@hwlang.de   Impressum   Datenschutz
Created: 24.01.2008   Updated: 18.02.2023
Diese Webseiten sind während meiner Lehrtätigkeit an der Hochschule Flensburg entstanden