Clean Code¶
Robert C. Martin
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
Wenn Sie ein Programm schreiben, ist Ihr erstes Ziel, dass es korrekt läuft. Aber das allein reicht nicht: Code wird nach dem Schreiben viel häufiger gelesen als geschrieben – von Ihnen selbst in drei Monaten, von Kommilitonen, von Kolleginnen und Kollegen, von Prüfenden. Unter Clean Code versteht man Programmcode, der nicht nur funktioniert, sondern auch klar, verständlich und pflegbar ist.
Der Begriff wurde vor allem durch das Buch Clean Code von Robert C. Martin geprägt. Die Prinzipien darin sind heute ein zentraler Bestandteil professioneller Softwareentwicklung.
Warum Clean Code von Anfang an?
Schlechte Gewohnheiten beim Programmieren sind schwer wieder loszuwerden. Wer von Anfang an auf verständlichen Code achtet, spart sich später viel Zeit – beim Debuggen, beim Erweitern und beim Zusammenarbeiten.
Bezeichner¶
Ein Bezeichner ist jeder Name, den Sie selbst vergeben: für Variablen, Methoden, Klassen, Konstanten und Pakete. Gute Bezeichner sind der wichtigste Beitrag zu lesbarem Code.
Allgemeine Regeln¶
- Variablen und Parameter → Substantive, die den Inhalt beschreiben
- Methoden → Verben oder Verb-Substantiv-Kombinationen
- Klassen → Substantive im Singular
- Konstanten →
GROSSBUCHSTABEN_MIT_UNTERSTRICH - Pakete → komplett in Kleinbuchstaben
Länge ist eine Tugend¶
Ein häufiger Anfängerfehler ist, Bezeichner zu kurz zu wählen. Es gibt keinen Grund für Kürze – moderne IDEs ergänzen Namen automatisch. Ein langer, sprechender Name ist fast immer besser als ein kurzer, kryptischer.
Booleans wie Fragen formulieren¶
Booleans drücken einen Wahrheitswert aus. Wenn ihr Name wie eine Ja/Nein-Frage klingt, ist der Code besonders lesbar:
Laufvariablen in Schleifen¶
Die klassischen Bezeichner i, j, k in for-Schleifen sind zwar weit verbreitet, aber oft irreführend. Sprechende Namen machen den Code sofort verständlicher:
Kein Typ im Bezeichner¶
Früher war es üblich, den Typ in den Variablennamen zu kodieren (Ungarische Notation, z.B. strName, iCount). Das ist heute überholt – der Typ ist in Java bereits in der Deklaration sichtbar.
Übung Bezeichner
Welche der folgenden Bezeichner sind gut gewählt, welche nicht? Begründen Sie und benennen Sie die schlechten um:
d, numberOfPassedStudents, temp2, calculateCircleArea, FLAG, x1, isLeapYear, data
Magic Numbers vermeiden¶
Als Magic Numbers bezeichnet man numerische (oder andere) Werte, die direkt im Code stehen, ohne zu erklären, was sie bedeuten. Sie machen Code schwer lesbar und fehleranfällig – wenn sich der Wert ändert, muss man ihn an jeder Stelle suchen und ersetzen.
Konstanten werden in Java mit dem Schlüsselwort final deklariert. In Klassen werden sie oft zusätzlich als static deklariert, damit sie zur Klasse gehören und nicht zu einem bestimmten Objekt.
Gilt auch für Strings
Magic Numbers sind nicht nur Zahlen. Auch hart kodierte Texte, die mehrfach verwendet werden, sollten als Konstanten definiert werden:
Kommentare¶
Es klingt kontraintuitiv, aber: zu viele Kommentare können Code schlechter lesbar machen. Ein Kommentar, der nur wiederholt, was der Code ohnehin sagt, ist Lärm. Schlimmer noch: Kommentare veralten, werden vergessen zu aktualisieren und enthalten dann falsche Informationen.
Kommentare, die man nicht braucht¶
Der "bessere" Code braucht keine einzige Kommentarzeile – die Bezeichner und die ausgelagerte Methode isPassing() machen ihn selbsterklärend.
Wann sind Kommentare sinnvoll?¶
Kommentare sind dann wertvoll, wenn sie das Warum erklären – also den Hintergrund, den man dem Code nicht ansehen kann:
Was immer sinnvoll ist: JavaDoc¶
Für öffentliche Methoden und Klassen sind JavaDoc-Kommentare stets sinnvoll. Sie beschreiben den Zweck, die Parameter und den Rückgabewert – das ist Dokumentation, kein Lärm.
Übung Kommentare
Lesen Sie folgenden Code und entscheiden Sie für jeden Kommentar: Sinnvoll behalten, oder besser entfernen/den Code stattdessen verbessern?
// Student-Klasse
public class Student {
// Name des Studenten
String name;
// Prüft ob bestanden
// Gibt true zurück wenn Note kleiner gleich 4
// gibt false zurück wenn Note größer 4
boolean passed(double grade) {
// Vergleich
if(grade <= 4.0) {
return true; // bestanden
} else {
return false; // nicht bestanden
}
}
}
Methoden¶
Methoden sind das wichtigste Werkzeug für sauberen Code. Die folgenden Prinzipien helfen dabei, Methoden gut zu gestalten.
Eine Methode – eine Aufgabe (SRP)¶
Das Single Responsibility Principle gilt nicht nur für Klassen, sondern besonders deutlich für Methoden: Eine Methode sollte genau eine Sache tun. Wenn Sie eine Methode mit „und" beschreiben müssen, ist sie zu groß.
Drei kleine Methoden sind viel besser als eine große: jede ist einzeln testbar, wiederverwendbar und verständlich.
DRY – Don't Repeat Yourself¶
Don't Repeat Yourself bedeutet: Jede Information (jede Logik) sollte im Code genau einmal vorkommen. Wenn Sie Code kopieren und einfügen, ist das fast immer ein Zeichen, dass Sie eine Methode brauchen.
Warum DRY so wichtig ist
Angenommen, der Mehrwertsteuersatz ändert sich von 19% auf 21%. Im „schlechten" Beispiel müssen Sie die 0.19 an drei Stellen suchen und ändern – und könnten eine vergessen. Im „besseren" Beispiel ändern Sie eine einzige Zeile.
Komplexe Bedingungen auslagern¶
Lange if-Bedingungen mit mehreren logischen Operatoren sind schwer zu lesen. Eine eigene Methode mit einem sprechenden Namen macht den Code sofort klarer:
Parameterzahl begrenzen¶
Je mehr Parameter eine Methode hat, desto schwerer ist sie zu verstehen und aufzurufen. Als Faustregel gilt:
- 0–2 Parameter: gut
- 3 Parameter: akzeptabel, aber hinterfragen
- 4+ Parameter: fast immer ein Zeichen, dass ein Objekt übergeben werden sollte
Formatierung¶
Konsistente Formatierung macht Code schneller lesbar. In einem Team sollte sich jeder an dieselben Regeln halten. Die meisten IDEs (Eclipse, IntelliJ) können Code automatisch formatieren.
Einrückung¶
Verwenden Sie konsistent entweder Leerzeichen oder Tabs – niemals beides gemischt. In Java ist 4 Leerzeichen pro Einrückungsebene der verbreitete Standard.
Klammern¶
In Java ist der K&R-Stil üblich: Die öffnende geschweifte Klammer { steht am Ende der vorherigen Zeile, die schließende } auf einer eigenen Zeile:
Immer geschweifte Klammern bei if¶
Auch wenn eine if-Bedingung nur eine einzige Anweisung hat, sollten Sie immer {}-Blöcke verwenden. Das Weglassen hat schon zu ernsthaften Softwarefehlern geführt:
Der Apple-SSL-Bug
2014 enthielt Apples SSL-Implementierung genau diesen Fehler: Ein versehentlich doppeltes goto fail; ohne Klammern führte dazu, dass Sicherheitszertifikate immer als gültig akzeptiert wurden. Mehr dazu im Selektion-Kapitel.
Leerzeilen und Zeilenlänge¶
- Trennen Sie logische Abschnitte innerhalb einer Methode durch eine Leerzeile.
- Halten Sie Zeilen auf ca. 80–120 Zeichen – längere Zeilen müssen beim Lesen gescrollt werden.
- Halten Sie Methoden kurz: Eine Methode, die auf einen Bildschirm passt (ca. 20–30 Zeilen), ist leichter zu verstehen als eine, die über mehrere Seiten geht.
SOLID Design-Prinzipien¶
Nachdem Robert C. Martin Design-Prinzipien für die Softwareentwicklung zusammengetragen hatte, wurden diese unter dem Akronym SOLID zusammengefasst:
| Buchstabe | Prinzip | Kurzbeschreibung |
|---|---|---|
| S | Single Responsibility Principle | Eine Klasse hat genau einen Grund zur Änderung |
| O | Open/Closed Principle | Offen für Erweiterung, geschlossen für Änderung |
| L | Liskov Substitution Principle | Kindklassen müssen Elternklassen ersetzen können |
| I | Interface Segregation Principle | Keine Abhängigkeit von nicht verwendeten Methoden |
| D | Dependency Inversion Principle | Abhängigkeiten zeigen auf Abstraktionen |
Single Responsibility Principle (SRP)¶
A class should have only one reason to change. – Robert C. Martin
Eine Klasse soll genau eine Verantwortung haben. Wenn mehrere unabhängige Konzepte in einer Klasse vermischt werden, wird sie schwer zu verstehen, zu testen und zu ändern.
Jetzt hat jede Klasse genau eine Aufgabe. Wenn sich das E-Mail-System ändert, muss nur GradeNotifier angepasst werden – Student und StudentExporter bleiben unberührt.
Open/Closed Principle (OCP)¶
Software entities should be open for extension, but closed for modification.
Eine Klasse soll so gestaltet sein, dass man ihr neues Verhalten hinzufügen kann (offen für Erweiterung), ohne bestehenden Code zu ändern (geschlossen für Modifikation). In Java erreicht man das häufig durch Vererbung.
Ein neues Triangle hinzuzufügen erfordert keine Änderung an vorhandenem Code.
Liskov Substitution Principle (LSP)¶
If S is a subtype of T, then objects of type T may be replaced by objects of type S without altering the correctness of the program.
Einfach gesagt: Überall, wo ein Objekt der Elternklasse verwendet wird, muss auch ein Objekt der Kindklasse funktionieren – ohne dass das Programm falsch läuft oder Ausnahmen geworfen werden müssen.
Ein klassisches Gegenbeispiel ist das Rechteck/Quadrat-Problem:
Code, der Rectangle erwartet und setWidth(5); setHeight(3); aufruft, bekommt bei einem Square die Fläche 9 statt 15 – das Verhalten ist überraschend und verletzt LSP. Die Lösung: Square und Rectangle sollten nicht in einer Vererbungsbeziehung stehen, sondern beide von einer gemeinsamen Elternklasse Shape erben.
Interface Segregation Principle (ISP) und Dependency Inversion Principle (DIP)¶
Diese beiden Prinzipien werden relevant, sobald Sie mit Interfaces (Java-Schnittstellen) und komplexeren Abhängigkeiten zwischen Klassen arbeiten. Sie werden diese Konzepte in Programmieren 2 und Software Engineering vertiefen. Kurz zusammengefasst:
- ISP: Eine Klasse sollte nur die Methoden implementieren müssen, die sie auch wirklich nutzt. Statt eines großen „Alles-kann"-Interfaces lieber mehrere kleine, spezifische Interfaces.
- DIP: Klassen sollten von Abstraktionen (Interfaces, abstrakten Klassen) abhängen, nicht von konkreten Implementierungen. Das macht Code flexibler und leichter testbar.
Übungen¶
Übung 1 – Bezeichner verbessern
Benennen Sie alle Bezeichner im folgenden Code so um, dass der Code ohne Kommentare verständlich ist. Entfernen Sie danach alle Kommentare.
Übung 2 – Magic Numbers eliminieren
Welche Magic Numbers finden Sie im folgenden Code? Ersetzen Sie sie durch benannte Konstanten.
Übung 3 – Kommentare aufräumen
Entscheiden Sie für jeden Kommentar im folgenden Code: entfernen, behalten oder den Code so umschreiben, dass der Kommentar überflüssig wird?
Übung 4 – DRY und Methoden
Der folgende Code enthält Wiederholungen. Lagern Sie den gemeinsamen Code in eine oder mehrere Methoden aus.
Übung 5 – Single Responsibility Principle
Die folgende Klasse Library verletzt das Single Responsibility Principle. Sie ist gleichzeitig für Bücherverwaltung, Ausleihe und Berichtserstellung zuständig.
Identifizieren Sie die verschiedenen Verantwortlichkeiten und teilen Sie die Klasse in mindestens drei Klassen auf. Überlegen Sie, welche Methoden und Variablen zu welcher Klasse gehören.
Zusammenfassung
Clean Code ist kein Luxus, sondern professionelles Handwerk. Die wichtigsten Prinzipien auf einen Blick:
- Bezeichner sind lang, sprechend und ohne Abkürzungen
- Magic Numbers werden durch benannte Konstanten ersetzt
- Kommentare erklären das Warum, nicht das Was
- Methoden tun genau eine Sache (SRP) und werden nicht kopiert (DRY)
- Formatierung ist konsistent und macht Struktur sichtbar
- SOLID-Prinzipien führen zu flexiblem, erweiterbarem Design