Clean Code - Refactoring, Patterns, Testen und Techniken für sauberen Code - Robert C. Martin - E-Book

Clean Code - Refactoring, Patterns, Testen und Techniken für sauberen Code E-Book

Robert C. Martin

4,5
34,99 €

Beschreibung

h2>Kommentare, Formatierung, StrukturierungFehler-Handling und Unit-TestsZahlreiche Fallstudien, Best Practices, Heuristiken und Code Smells Clean Code - Refactoring, Patterns, Testen und Techniken für sauberen CodeAus dem Inhalt:Lernen Sie, guten Code von schlechtem zu unterscheidenSauberen Code schreiben und schlechten Code in guten umwandelnAussagekräftige Namen sowie gute Funktionen, Objekte und Klassen erstellenCode so formatieren, strukturieren und kommentieren, dass er bestmöglich lesbar istEin vollständiges Fehler-Handling implementieren, ohne die Logik des Codes zu verschleiernUnit-Tests schreiben und Ihren Code testgesteuert entwickeln Selbst schlechter Code kann funktionieren. Aber wenn der Code nicht sauber ist, kann er ein Entwicklungsunternehmen in die Knie zwingen. Jedes Jahr gehen unzählige Stunden und beträchtliche Ressourcen verloren, weil Code schlecht geschrieben ist. Aber das muss nicht sein. Mit Clean Code präsentiert Ihnen der bekannte Software-Experte Robert C. Martin ein revolutionäres Paradigma, mit dem er Ihnen aufzeigt, wie Sie guten Code schreiben und schlechten Code überarbeiten. Zusammen mit seinen Kollegen von Object Mentor destilliert er die besten Praktiken der agilen Entwicklung von sauberem Code zu einem einzigartigen Buch. So können Sie sich die Erfahrungswerte der Meister der Software-Entwicklung aneignen, die aus Ihnen einen besseren Programmierer machen werden – anhand konkreter Fallstudien, die im Buch detailliert durchgearbeitet werden. Sie werden in diesem Buch sehr viel Code lesen. Und Sie werden aufgefordert, darüber nachzudenken, was an diesem Code richtig und falsch ist. Noch wichtiger: Sie werden herausgefordert, Ihre professionellen Werte und Ihre Einstellung zu Ihrem Beruf zu überprüfen. Clean Code besteht aus drei Teilen:Der erste Teil beschreibt die Prinzipien, Patterns und Techniken, die zum Schreiben von sauberem Code benötigt werden. Der zweite Teil besteht aus mehreren, zunehmend komplexeren Fallstudien. An jeder Fallstudie wird aufgezeigt, wie Code gesäubert wird – wie eine mit Problemen behaftete Code-Basis in eine solide und effiziente Form umgewandelt wird. Der dritte Teil enthält den Ertrag und den Lohn der praktischen Arbeit: ein umfangreiches Kapitel mit Best Practices, Heuristiken und Code Smells, die bei der Erstellung der Fallstudien zusammengetragen wurden. Das Ergebnis ist eine Wissensbasis, die beschreibt, wie wir denken, wenn wir Code schreiben, lesen und säubern. Dieses Buch ist ein Muss für alle Entwickler, Software-Ingenieure, Projektmanager, Team-Leiter oder Systemanalytiker, die daran interessiert sind, besseren Code zu produzieren. Über den Autor:Robert C. »Uncle Bob« Martin entwickelt seit 1970 professionell Software. Seit 1990 arbeitet er international als Software-Berater. Er ist Gründer und Vorsitzender von Object Mentor, Inc., einem Team erfahrener Berater, die Kunden auf der ganzen Welt bei der Programmierung in und mit C++, Java, C#, Ruby, OO, Design Patterns, UML sowie Agilen Methoden und eXtreme Programming helfen.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB
MOBI

Seitenzahl: 591

Bewertungen
4,5 (46 Bewertungen)
31
8
7
0
0



Inhaltsverzeichnis
Impressum
Vorwort
Einführung
Danksagungen
Kapitel 1: Sauberer Code
1.1 Code, Code und nochmals Code
1.2 Schlechter Code
1.3 Die Lebenszykluskosten eines Chaos
Das große Redesign in den Wolken
Einstellung
Das grundlegende Problem
Sauberen Code schreiben – eine Kunst?
Was ist sauberer Code​?
1.4 Denkschulen​
1.5 Wir sind Autoren
1.6 Die Pfadfinder-Rege​l
1.7 Vorläufer und Prinzipien
1.8 Zusammenfassung
Kapitel 2: Aussagekräftige Namen
2.1 Einführung
2.2 Zweckbeschreibende Namen​ wählen
2.3 Fehlinformationen​ vermeiden
2.4 Unterschiede deutlich​ machen
2.5 Aussprechbare Namen​ verwenden
2.6 Suchbare Namen​ verwenden
2.7 Codierungen​ vermeiden
Ungarische Notation​
Member-Präfixe​
Interfaces​ und Implementierungen​
2.8 ​Mentale Mappings vermeiden
2.9 Klassennamen​​
2.10 Methodennamen​​
2.11 Vermeiden Sie humorige Namen
2.12 Wählen Sie ein Wort pro Konzept
2.13 Keine Wortspiele​
2.14 Namen der Lösungsdomäne​ verwenden
2.15 Namen der Problemdomäne verwenden
2.16 Bedeutungsvollen Kontext​ hinzufügen
2.17 Keinen überflüssigen Kontext​ hinzufügen
2.18 Abschließende Worte
Kapitel 3: Funktionen
3.1 Klein!
Blöcke und Einrückungen
3.2 Eine Aufgabe erfüllen
Abschnitte innerhalb von Funktionen​
3.3 Eine Abstraktionsebene pro Funktion​​
Code Top-down lesen: die Stepdown-Regel
3.4 Switch-Anweisungen​
3.5 Beschreibende Namen​​ verwenden
3.6 ​Funktionsargumente
Gebräuchliche monadische​ Formen
Flag-Argumente
Dyadische Funktionen​
Triaden​
Argument-Objekte
Argument-Listen
Verb​en und Schlüsselwörter​
3.7 Nebeneffekt​e vermeiden
Output-Argumente
3.8 Anweisung und Abfrage trennen
3.9 Ausnahmen sind besser als Fehler-Codes
Try/Catch-Blöcke​ extrahieren
​Fehler-Verarbeitung ist eine Aufgabe
Der Abhängigkeitsmagnet Error.java​​
3.10 Don’t Repeat Yourself
3.11 Strukturierte Programmierung​​
3.12 Wie schreibt man solche Funktionen?
3.13 Zusammenfassung
3.14 SetupTeardownIncluder
Kapitel 4: Kommentare
4.1 Kommentare sind kein Ersatz für schlechten Code
4.2 Erklären Sie im und durch den Code
4.3 Gute Kommentare​
Juristische Kommentare​
Informierende Kommentare​
Erklärung der Absicht
Klarstellungen
Warnungen vor Konsequenzen
TODO-Kommentare​
Verstärkung
​Javadocs in öffentlichen APIs
4.4 Schlechte Kommentare​
Geraune
Redundante Kommentare​
Irreführende Kommentare
Vorgeschriebene Kommentare​
Tagebuch-Kommentare​
Geschwätz​
Beängstigendes Geschwätz
Verwenden Sie keinen Kommentar, wenn Sie eine Funktion oder eine Variable verwenden können
Positionsbezeichner​
Kommentare hinter schließenden Klammern​
Zuschreibungen und Nebenbemerkungen
Auskommentierter Code​​
HTML-Kommentare​​
Nicht-lokale Informationen​
Zu viele Informationen
Unklarer Zusammenhang
Funktions-Header​​
Javadocs in nicht-öffentlichem Code
Beispiel
Kapitel 5: Formatierung
5.1 Der Zweck der Formatierung​
5.2 Vertikale Formatierung​
Die Zeitungs-Metapher​​
Vertikale Offenheit​​ zwischen Konzepten
Vertikale Dichte​​
Vertikaler Abstand​​
Vertikale Anordnung​​
5.3 Horizontale Formatierung​
Horizontale Offenheit und Dichte
Horizontale Ausrichtung​​
Einrückung​​
Dummy-Bereiche​
5.4 Team-Regeln​​
5.5 Uncle Bobs Formatierungsregeln​
Kapitel 6: Objekte und Datenstrukturen
6.1 Datenabstraktion​
6.2 Daten/Objekt-Anti-Symmetrie​​​
6.3 Das Law of Demeter
Zugkatastrophe
Hybride​
Struktur verbergen
6.4 Datentransfer-Objekte
Active Record
6.5 Zusammenfassung
Kapitel 7: Fehler-Handling
7.1 Ausnahme​n statt Rückgabe-Codes​
7.2 Try-Catch-Finally-Anweisungen zuerst schreiben
7.3 Unchecked Exception​​​s
7.4 Ausnahmen mit Kontext auslösen​
7.5 Definieren Sie Exception-Klassen mit Blick auf die Anforderungen des Aufrufers
7.6 Den normalen Ablauf definieren
7.7 Keine ​Null zurückgeben
7.8 Keine Null übergeben
7.9 Zusammenfassung
Kapitel 8: Grenzen
8.1 Mit Drittanbieter-Code​​ arbeiten
8.2 Grenzen erforschen und kennen lernen
8.3 ​log4j kennen lernen
8.4 Lern-Tests sind besser als kostenlos
8.5 Code verwenden, der noch nicht existiert
8.6 Saubere Grenzen
Kapitel 9: Unit-Tests
9.1 Die drei Gesetze​ der TDD
9.2 Tests sauber halten​
Tests ermöglichen die -heiten und -keiten
9.3 Saubere Tests​
Domänenspezifische Testsprache​
Ein Doppelstandard​
9.4 Ein assert pro Test​
Ein Konzept pro Test​
9.5 ​F.I.R.S.T. ​
9.6 Zusammenfassung
Kapitel 10: Klassen
10.1 Klassenaufbau
Einkapselung
10.2 Klassen sollten klein sein!
Fünf Methoden sind nicht zu viel, oder?
Das Single-Responsibility-Prinzip​
Kohäsion​
Kohäsion zu erhalten, führt zu vielen kleinen Klassen
10.3 Änderungen einplanen
Änderungen isolieren
Kapitel 11: Systeme
11.1 Wie baut man eine Stadt?
11.2 Konstruktion und Anwendung eines Systems trennen
Trennung in main
Factories
Dependency Injection
11.3 Aufwärtsskalierung​
Cross-Cutting Concerns
11.4 ​Java-Proxies
11.5 Reine Java-AOP-Frameworks
11.6 ​AspectJ-Aspekte
11.7 Die Systemarchitektur testen
11.8 Die Entscheidungsfindung optimieren
11.9 ​Standards weise anwenden, wenn sie nachweisbar einen Mehrwert bieten
11.10 Systeme brauchen domänenspezifische Sprachen
11.11 Zusammenfassung
Kapitel 12: Emergenz
12.1 Saubere Software durch emergentes Design
12.2 Einfache Design-Regel 1: Alle Tests bestehen
12.3 Einfache Design-Regeln 2–4: Refactoring​
12.4 Keine Duplizierung
12.5 Ausdrucksstärke
12.6 Minimale Klassen und Methoden
12.7 Zusammenfassung
Kapitel 13: Nebenläufigkeit
13.1 Warum Nebenläufigkeit?
Mythen und falsche Vorstellungen
13.2 Herausforderungen
13.3 Prinzipien einer defensiven Nebenläufigkeitsprogrammierung
Single-Responsibility-Prinzip​
Korollar: Beschränken Sie den Gültigkeitsbereich von Daten
Korollar: Arbeiten Sie mit Kopien der Daten
Korollar: Threads sollten voneinander so unabhängig wie möglich sein
13.4 Lernen Sie Ihre Library kennen
Thread-sichere Collections
13.5 Lernen Sie Ihre Ausführungsmodelle kennen
Erzeuger-Verbraucher
Leser-Schreiber
Philosophenproblem
13.6 Achten Sie auf Abhängigkeiten zwischen synchronisierten Methoden
13.7 Halten Sie synchronisierte Abschnitte klein
13.8 Korrekten Shutdown-Code zu schreiben, ist schwer
13.9 Threaded-Code testen
Behandeln Sie gelegentlich auftretende Fehler als potenzielle Threading-Probleme
Bringen Sie erst den Nonthreaded-Code zum Laufen
Machen Sie Ihren Threaded-Code pluggable
Schreiben Sie anpassbaren Threaded-Code
Den Code mit mehr Threads als Prozessoren ausführen
Den Code auf verschiedenen Plattformen ausführen
Code-Scheitern durch Instrumentierung provozieren
Manuelle Codierung
Automatisiert
13.10 Zusammenfassung
Kapitel 14: Schrittweise Verfeinerung
14.1 Args-Implementierung
Wie habe ich dies gemacht?
14.2 Args: der Rohentwurf
Deshalb hörte ich auf
Über inkrementelle Entwicklung​​
14.3 String-Argumente
14.4 Zusammenfassung
Kapitel 15: JUnit im Detail
15.1 Das JUnit-Framework
15.2 Zusammenfassung
Kapitel 16: Refactoring von SerialDate
16.1 Zunächst bring es zum Laufen!
16.2 Dann mach es richtig!
16.3 Zusammenfassung
Kapitel 17: Smells und Heuristiken
17.1 Kommentar​e
​C1: Ungeeignete​ Informationen
​C2: Überholte Kommenta​re
​C3: Redundante Kommentare
​C4: Schlecht geschriebene Kommentare​
​C5: Auskommentierter Code​
17.2 Umgebung
​E1: Ein Build​ erfordert mehr als einen Schritt
​E2: Tests erfordern mehr als einen Schritt
17.3 Funktion​en
​F1: Zu viele Argumente​​
​F2: Output-Argumente​​
​F3: Flag-Argument​​e
​F4: Tote Funktione​n
17.4 Allgemein
​G1: Mehrere Sprache​n in einer Quelldatei​
​G2: Offensichtliches Verhalten​ ist nicht implementiert
​G3: Falsches Verhalten an den Grenzen
​G4: Übergangene Sicherungen​
​G5: Duplizierung​
​G6: Auf der falschen Abstraktionsebene​ codieren
​G7: Basisklasse​​ hängt von abgeleiteten Klassen​​ ab
​G8: Zu viele Informationen
​G9: Toter Code
​G10: Vertikale Trennung​
​G11: Inkonsistenz​
​G12: Müll​​
​G13: Künstliche Kopplung​
​G14: Funktionsneid​
​G15: Selektor-Argumente​​
​G16: Verdeckte Absicht
​G17: Falsche Zuständigkeit​
​G18: Fälschlich als statisch deklarierte Methode​n
​G19: Aussagekräftige Variable​n verwenden
​G20: Funktionsname​​ sollte die Aktion ausdrücken
​G21: Den Algorithmus​ verstehen
​G22: Logische Abhängigkeiten in physische umwandeln
​G23: Polymorphismus​ statt If/Else oder Switch/Case verwenden
​G24: Konvention​​en beachten
​G25: Magische Zahlen​ durch benannte Konstanten ersetzen
​G26: Präzise sein
​G27: Struktur ist wichtiger als Konvention
​G28: Bedingungen​​ einkapseln
​G29: Negative Bedingungen​ vermeiden
​G30: Eine Aufgabe pro Funktion​!
​G31: Verborgene zeitliche Kopplungen​
​G32: Keine Willkür
​G33: Grenzbedingungen einkapseln
​G34: In Funktionen nur eine Abstraktionsebene​​ tiefer gehen
​G35: Konfigurierbare Daten hoch ansiedeln
​G36: Transitive Navigation​ vermeiden
17.5 Java
​J1: Lange Importlisten​ durch Platzhalter​ vermeiden
​J2: Keine Konstanten vererben​
​J3: Konstanten im Gegensatz zu Enums​
17.6 Namen​
​N1: Deskriptive Namen​ wählen
​N2: Namen sollten der Abstraktionsebene​ entsprechen
​N3: Möglichst die Standardnomenklatur​ verwenden
​N4: Eindeutige Namen​
​N5: Lange Namen​ für große Geltungsbereiche
​N6: Codierungen vermeiden
​N7: Namen sollten Nebeneffekte​ beschreiben
17.7 Test​s
​T1: Unzureichende Tests​
​T2: Ein Coverage-Tool​ verwenden
​T3: Triviale Tests​ nicht überspringen
​T4: Ein ignorierter Test zeigt eine Mehrdeutigkeit​ auf
​T5: Grenzbedingung​​en testen
​T6: Bei Bugs die Nachbarschaft gründlich testen
​T7: Das Muster des Scheiterns zur Diagnose nutzen
​T8: Hinweise durch Coverage-Patterns
​T9: Tests sollten schnell sein
17.8 Zusammenfassung
Anhang A: Nebenläufigkeit II
A.1 Client/Server-Beispiel
Der Server
Threading hinzufügen
Server-Beobachtungen
Zusammenfassung
A.2 Mögliche Ausführungspfade
Anzahl der Pfade
Tiefer graben
Zusammenfassung
A.3 Lernen Sie Ihre Library kennen
Executor Framework
Nicht blockierende Lösungen
Nicht thread-sichere Klassen​
A.4 Abhängigkeiten zwischen Methoden können nebenläufigen Code beschädigen
Das Scheitern tolerieren
Clientbasiertes Locking
Serverbasiertes Locking
A.5 Den Durchsatz verbessern
Single-Thread-Berechnung des Durchsatzes
Multithread-Berechnung des Durchsatzes
A.6 Deadlock​
Gegenseitiger Ausschluss​
Sperren & warten
Keine präemptive Aktion
Zirkuläres Warten
Den gegenseitigen Ausschluss aufheben
Das Sperren & Warten aufheben
Die Präemption umgehen
Das zirkuläre Warten umgehen
A.7 Multithreaded-Code testen
A.8 Threadbasierten Code mit Tools testen
A.9 Zusammenfassung
A.10 Tutorial: kompletter Beispielcode
Client/Server ohne Threads
Client/Server mit Threads
Anhang B: org.jfree.date.SerialDate
Anhang C: Literaturverweise
Epilog

Clean Code

Refactoring, Patterns, Testen und Techniken für sauberen Code

Robert C. Martin

Unter Mitarbeit von: Michael C. Feathers, Timothy R. Ottinger, Jeffrey J. Langr, Brett L. Schuchert, James W. Grenning, Kevin Dean Wampler Object Mentor, Inc.

Impressum

Bibliografische Information der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über <http://dnb.d-nb.de> abrufbar.

ISBN 978-3-8266-9639-8

1. Auflage 2009

www.mitp.de

E-Mail: [email protected]

Telefon: +49 6221 / 489 -555

Telefax: +49 6221 / 489 -410

© 2009 mitp, eine Marke der Verlagsgruppe Hüthig Jehle Rehm GmbH Heidelberg, München, Landsberg, Frechen, Hamburg

Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und die Einspeicherung und Verarbeitung in elektronischen Systemen.

Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften.

Authorized translation from the English language edition, entitled CLEAN CODE: A HANDBOOK OF AGILE SOFTWARE CRAFTSMANSHIP, 1 st Edition, 0132350882 by MARTIN, ROBERT C., published by Pearson Education, Inc, publishing as Prentice Hall, Copyright © 2009 Pearson Education, Inc.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc. GERMAN language edition published by mitp-Verlag, VERLAGSGRUPPE HÜTHIG JEHLE REHM GMBH, Copyright © 2009.

Lektorat: Sabine Schulz

Korrektorat: Petra Heubach-Erdmann

electronic publication: III-satz, Husby, www.drei-satz.de

Dieses Ebook verwendet das ePub-Format und ist optimiert für die Nutzung mit dem iBooks-reader auf dem iPad von Apple. Bei der Verwendung anderer Reader kann es zu Darstellungsproblemen kommen.

Der Verlag räumt Ihnen mit dem Kauf des ebooks das Recht ein, die Inhalte im Rahmen des geltenden Urheberrechts zu nutzen. Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheherrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und Einspeicherung und Verarbeitung in elektronischen Systemen.

Der Verlag schützt seine ebooks vor Missbrauch des Urheberrechts durch ein digitales Rechtemanagement. Bei Kauf im Webshop des Verlages werden die ebooks mit einem nicht sichtbaren digitalen Wasserzeichen individuell pro Nutzer signiert.

Bei Kauf in anderen ebook-Webshops erfolgt die Signatur durch die Shopbetreiber. Angaben zu diesem DRM finden Sie auf den Seiten der jeweiligen Anbieter.

Vorwort

Bei uns in Dänemark zählt Ga-Jol zu den beliebtesten Süßigkeiten. Sein starker Lakritzduft ist ein perfektes Mittel gegen unser feuchtes und oft kühles Wetter. Der Charme, den Ga-Jol für uns Dänen entfaltet, liegt auch an den weisen oder geistreichen Sprüchen, die auf dem Deckel jeder Packung abgedruckt sind. Ich habe mir heute Morgen eine Doppelpackung dieser Köstlichkeit gekauft und fand darauf das folgende alte dänische Sprichwort:

Ærlighed i små ting er ikke nogen lille ting.

Ehrlichkeit in kleinen Dingen ist kein kleines Ding. Dies war ein gutes Omen. Es passte zu dem, was ich hier sagen wollte. Kleine Dinge spielen eine Rolle. In diesem Buch geht es um bescheidene Belange, deren Wert dennoch beträchtlich ist.

Gott steckt in den Details, sagte der Architekt ​Ludwig Mies van der Rohe. Dieses Zitat erinnert an zeitgenössische Auseinandersetzungen über die Rolle der Architektur bei der Software-Entwicklung und insbesondere in der Agilen Welt. Bob und ich führen gelegentlich heiße Diskussionen über dieses Thema. Und ja, Mies van der Rohe war sehr an der Nützlichkeit und der Zeitlosigkeit der Formen des Bauens interessiert, auf denen großartige Architektur basiert. Andererseits wählte er auch persönlich jeden Türknopf für jedes Haus aus, das er entworfen hatte. Warum? Weil kleine Aufgaben eine Rolle spielen.

Bei unserer laufenden »Debatte« über TDD haben Bob und ich festgestellt, dass wir beide der Auffassung sind, dass die Software-​Architektur eine wichtige Rolle bei der Entwicklung spielt, obwohl wir wahrscheinlich verschiedene Vorstellungen davon haben, was genau das bedeutet. Doch solche Differenzen sind relativ unwichtig, weil wir davon ausgehen können, dass verantwortungsbewusste Profis am Anfang eines Projekts eine gewisse Zeit über seinen Ablauf und seine Planung nachdenken. Die Vorstellungen der späten 1990er-Jahre, dass Design nur durch Tests und den Code vorangetrieben werden könnte, sind längst passé. Doch die Aufmerksamkeit im Detail ist ein noch wesentlicherer Aspekt der Professionalität als Visionen im Großen. Erstens: Es ist die Übung im Kleinen, mit der Profis ihr Können und ihr Selbstvertrauen entwickeln, sich an Größeres heranzuwagen. Zweitens: Die kleinste Nachlässigkeit bei der Konstruktion, die Tür, die nicht richtig schließt, die missratene Kachel auf dem Fußboden oder sogar ein unordentlicher Schreibtisch können den Charme des größeren Ganzen mit einem Schlag ruinieren. Darum geht es bei sauberem Code.

Dennoch bleibt die Architektur nur eine Metapher für die ​​Software-Entwicklung und insbesondere die Phase der Software, in der das anfängliche Produkt etwa in derselben Weise entsteht, wie ein Architekt ein neues Gebäude hervorbringt. In der heutigen Zeit von Scrum und Agile geht es hauptsächlich darum, ein Produkt schnell auf den Markt zu bringen. Die Fabrik soll mit höchster Kapazität Software produzieren. Nur: Hier geht es um menschliche Fabriken, denkende und führende Programmierer, die eine Aufgabenliste abarbeiten oder sich bemühen, anhand von Benutzer-Stories ein brauchbares Produkt zu erstellen. Ein solches Denken wird von der Metapher der Fabrik dominiert. Die Produktionsaspekte der Herstellung von Autos in Japan, also einer von Fließbändern dominierten Welt, haben viele Ideen von Scrum inspiriert.

Doch selbst in der Automobilindustrie wird der Hauptteil der Arbeit nicht bei der Produktion, sondern bei der Wartung geleistet – oder bei dem Bemühen, sie zu vermeiden. Bei der Software werden die 80 oder mehr Prozent unserer Tätigkeit anheimelnd als »Wartung« bezeichnet, ein beschönigendes Wort für »Reparatur«. Statt uns also auf typische westliche Weise auf die Produktion guter Software zu konzentrieren, sollten wir anfangen, eher wie ein Hausmeister bei der Gebäudeinstandhaltung oder wie ein Kfz-Mechaniker bei der Reparatur von Autos zu denken. Was haben japanische Managementweisheiten dazu zu sagen?

Etwa 1951 erschien ein Qualitätsansatz namens ​Total Productive Maintenance (​TPM; »Umfassendes Management des Produktionsprozesses«, der Ausdruck wird nicht ins Deutsche übersetzt) in der japanischen Szene. Er konzentrierte sich weniger auf die Produktion, sondern mehr auf die Wartung. Eine der fünf Säulen des TPM ist der Satz der so genannten 5S-Prinzipien. 5S bezieht sich auf einen Satz von Disziplinen oder Tätigkeitsbereichen. Tatsächlich verkörpern diese 5S-Prinzipien die Bedeutung von ​Lean – einem anderen Modewort in westlichen Produktionskreisen, das zunehmend auch in der Software-Entwicklung verwendet wird. Diese Prinzipien sind nicht optional. Wie Uncle Bob auf der Titelseite sagt, erfordert die Software-Praxis eine gewisse Disziplin: Fokus, Aufmerksamkeit und Denken. Es geht nicht immer nur darum, aktiv zu sein und die Fabrikausrüstung mit der optimalen Geschwindigkeit zu betreiben. Die ​5S-Philosophie umfasst die folgenden Konzepte:

​Seiri oder Organisation (Eselsbrücke: »sortieren«). Zu wissen, wo sich Dinge befinden, ist erfolgsentscheidend. Dazu zählen zum Beispiel Ansätze wie das Vergeben geeigneter Namen. Wenn Sie meinen, die Benennung Ihrer Bezeichner sei nicht wichtig, sollten Sie auf jeden Fall die folgenden Kapitel lesen.

​Seiton oder Ordentlichkeit (Eselsbrücke: »aufräumen«). Ein altes Sprichwort sagt: Ein Platz für alles, und alles an seinem Platz. Ein Code-Abschnitt sollte da stehen, wo Sie ihn zu finden erwarten; und falls er nicht da steht, sollten Sie ein Refactoring von Ihrem Code vornehmen, so dass er danach an der erwarteten Stelle steht.

​Seiso oder Sauberkeit (Eselsbrücke: »wienern«). Sorgen Sie dafür, dass der Arbeitsplatz frei von herumhängenden Drähten, Müllspuren, Einzelteilen und Abfall ist. Was sagen die Autoren hier über die Vermüllung Ihres Codes mit Kommentaren und auskommentierten Codezeilen, die den Verlauf der Entwicklung oder Wünsche für die Zukunft wiedergeben? Weg damit.

​Seiketsu oder Standardisierung. Die kommt zu einem Konsens darüber, wie der Arbeitsplatz sauber gehalten werden soll. Hat dieses Buch etwas über einen konsistenten Codierstil und gemeinsam in der Gruppe befolgte Praktiken zu sagen? Wo kommen diese Standards her? Lesen Sie weiter.

​Shutsuke oder Disziplin (Selbst-disziplin). Dies bedeutet, die Disziplin aufzubringen, den Praktiken zu folgen, seine Arbeit regelmäßig zu überdenken und bereit zu sein, sich zu ändern.

Wenn Sie die Herausforderung – jawohl, die Herausforderung – annehmen, dieses Buch zu lesen und anzuwenden, werden Sie den letzten Punkt verstehen und schätzen lernen. Hier kommen wir schließlich zu den Wurzeln einer verantwortlichen professionellen Einstellung in einem Beruf, der sich um den Lebenszyklus eines Produktes kümmern sollte. So wie Automobile und andere Maschinen unter TPM vorbeugend gewartet werden, sollte eine Wartung im Falle eines Zusammenbruchs – also darauf zu warten, dass die Bugs sich zeigen – die Ausnahme sein. Stattdessen sollten Sie eine Ebene höher ansetzen: Inspizieren Sie die Maschinen jeden Tag und tauschen Sie Verschleißteile aus, bevor sie kaputtgehen, oder lassen Sie den sprichwörtlichen Ölwechsel vornehmen, um die Abnutzung des Motors möglichst zu verringern. Für Ihren Code bedeutet das: Nehmen Sie ein gnadenloses Refactoring vor. Sie können mit der Verbesserung noch eine Ebene höher ansetzen, wie es die TPM-Bewegung innovativ vor über 50 Jahren vorgemacht hat: Bauen Sie Maschinen, die von vornherein wartungsfreundlicher sind. Code lesbar zu machen, ist genauso wichtig, wie ihn ausführbar zu machen. Die ultimative Praxis, die in TPM-Kreisen etwa 1960 eingeführt wurde, besteht darin, die alten Maschinen vorbeugend durch vollkommen neue zu ersetzen. Wie Fred ​Brooks anmahnt, sollten wir wahrscheinlich Hauptteile unserer Software etwa alle sieben Jahre von Grund auf erneuern, um die schleichende Ansammlung von ​Cruft (Jargon: Müll, Staub, Unrat) zu beseitigen. Vielleicht sollten wir die von Brooks genannte Zeitspanne drastisch reduzieren und nicht von Jahren, sondern von Wochen, Tagen oder gar Stunden sprechen. Denn dort finden sich die Details.

​​Details haben eine mächtige Wirkungskraft. Dennoch hat dieser Ansatz etwas Bescheidenes und Grundsätzliches, so wie wir es vielleicht stereotyp von einem Ansatz erwarten, der japanische Wurzeln für sich in Anspruch nimmt. Aber dies ist nicht nur eine köstliche Art, das Leben zu sehen. Auch die westliche Volksweisheit enthält zahlreiche ähnliche Sprichwörter. Das Seiton-Zitat von oben floss auch aus der Feder eines Priesters in Ohio, der Ordentlichkeit buchstäblich »als Gegenmittel für jede Art von Bösem« sah. Was ist mit Seiso? Sauberkeit kommt gleich nach Göttlichkeit. So schön ein Haus auch sein mag, ein unordentlicher Tisch raubt ihm seinen ganzen Glanz. Was bedeutet Shutsuke in diesen kleinen Dingen? Wer an wenig glaubt, glaubt an viel. Wie wär’s damit, das Refactoring des Codes rechtzeitig durchzuführen, um seine Position für folgende »große« Entscheidungen zu stärken, als die Aufgabe aufzuschieben? Ein Stich zur rechten Zeit erspart dir neun weitere. Wer früh kommt, mahlt zuerst. Was du heute kannst besorgen, das verschiebe nicht auf morgen. (Dies war die ursprüngliche Bedeutung des Ausdrucks »der letzte tragbare Moment« bei Lean, bevor er in die Hände von Software-Beratern fiel.) Was ist mit der Ordnung eines Arbeitsplatzes im Kleinen im Vergleich zum großen Ganzen? Auch die größte Eiche wächst aus einer kleinen Eichel. Oder wie ist es damit, einfache vorbeugende Arbeiten in den Alltag einzubauen? Vorsicht ist besser als Nachsicht. Ein Apfel am Tag hält den Doktor fern. Sauberer Code anerkennt die verwurzelte Weisheit unserer Kultur im Allgemeinen, oder wie sie einmal war, oder wie sie sein sollte, oder wie sie sein könnte, indem er den Details die schuldige Aufmerksamkeit schenkt.

Selbst in der Literatur über große Architektur greifen Autoren auf Sprichwörter über die Bedeutung von Details zurück. Denken Sie an die Türgriffe von Mies van der Rohe. Das ist Seiri. Das bedeutet, sich um jeden Variablennamen zu kümmern. Sie sollten Variablennamen mit derselben Sorgfalt auswählen wie den Namen eines erstgeborenen Kindes.

Jeder Hausbesitzer weiß, dass eine solche Pflege und fortwährende Verbesserung niemals zu Ende ist. Der Architekt Christopher Alexander – Vater der Patterns und Pattern-Sprachen – betrachtet jeden Design-Akt selbst als einen kleinen, lokalen Akt der Reparatur. Und er betrachtet die Anwendung des Könnens auf feine Strukturen als den einzigen legitimen Arbeitsbereich des Architekten; die größeren Formen können den Patterns und deren Anwendung durch die Bewohner überlassen werden. Design geht immer weiter. Es betrifft nicht nur den Anbau neuer Räumlichkeiten, sondern auch profanere Aufgaben wie ein neuer Anstrich, das Ersetzen eines abgelaufenen Teppichs oder die Modernisierung der Spüle in der Küche. In den meisten Künsten werden ähnliche Überzeugungen vertreten. Bei unserer Suche nach anderen, die das Haus Gottes in den Details sehen, stießen wir beispielsweise auf den französischen Autor Gustav Flaubert aus dem 19. Jahrhundert. Der französische Dichter Paul Valery sagt uns, ein Gedicht wäre niemals fertig und müsse laufend überarbeitet werden; mit dieser Arbeit aufzuhören wäre vergleichbar damit, dieses Gedicht zu verwerfen. Eine solche Besessenheit von Details ist allen Bemühungen gemeinsam, die auf Exzellenz, also auf herausragende Leistungen gerichtet sind. Also: Vielleicht gibt es hier wenig Neues, aber wenn Sie dieses Buch lesen, werden Sie herausgefordert, die guten Disziplinen wieder aufzunehmen, die Sie vor langer Zeit aus Apathie, dem Wunsch nach Spontanität oder einfach deswegen aufgegeben haben, weil Sie »etwas anderes« machen wollten.

Leider betrachten wir solche Überlegungen normalerweise nicht als Grundbausteine der Kunst der Programmierung. Wir entlassen unseren Code früh aus unserer Obhut, nicht, weil er fertig ist, sondern weil unser Wertesystem mehr auf die äußere Erscheinung als auf die Substanz des gelieferten Produkts gerichtet ist. Diese fehlende Aufmerksamkeit kommt uns letztendlich teuer zu stehen: Irgendwann machen sich die Defekte immer bemerkbar. Weder in akademischen Kreisen noch in der Industrie begibt sich die Forschung in die niedrigen Ebenen hinunter, Code sauber zu halten. Früher, als ich noch bei der Bell Labs Software Production Research Organization (also wirklich Produktion!) beschäftigt war, machten wir die beiläufige Entdeckung, dass ein konsistenter Stil beim Einrücken von Klammern der statistisch signifikanteste Indikator für eine geringe Fehlerhäufigkeit war. Wir wollen, dass die Architektur, die Programmiersprache oder irgendein anderes hoch angesiedeltes Konzept die Ursache für Qualität sein soll. Als Entwickler, deren vorgebliche Professionalität auf der Meisterung von Werkzeugen und abgehobenen Design-Methoden basiert, fühlen wir uns von dem Mehrwert beleidigt, den diese Maschinen aus der Fabrikhalle, pardon!, Codierer, erzielen, indem sie einfach einen bestimmten Stil der Einrückung von Klammern konsistent anwenden. Um mein eigenes Buch zu zitieren, das ich vor 17 Jahren geschrieben habe: Ein solcher Stil unterscheidet Exzellenz von bloßer Kompetenz. Die japanische Weltsicht versteht den entscheidenden Beitrag jedes gewöhnlichen Arbeiters und mehr noch, wie Entwicklungssysteme von den einfachen gewöhnlichen Aktionen dieser Arbeiter abhängen. Qualität ist das Ergebnis eine Million selbstloser Akte der Sorgfalt – nicht nur das einer großartigen Methode, die vom Himmel gefallen ist. Dass diese Akte einfach sind, bedeutet nicht, dass sie simplizistisch (einfältig) sind. Es bedeutet auch nicht, dass sie leicht sind. Dennoch sind sie der Stoff, aus dem die Größe und mehr noch die Schönheit menschlicher Anstrengungen gemacht ist. Wer diese Akte ignoriert, hat noch nicht sein volles menschliches Potenzial realisiert.

Natürlich befürworte ich immer noch, auch den größeren Rahmen zu betrachten und besonders den Wert von architektonischen Ansätzen zu berücksichtigen, die in einem tiefen Wissen sowohl des Problembereiches als auch der Software-Usability verwurzelt sind. Doch darum geht es in diesem Buch nicht – zumindest nicht vordergründig. Dieses Buch will eine subtilere Botschaft verbreiten, deren Gewichtigkeit nicht unterschätzt werden sollte. Sie passt zu dem gegenwärtigen Credo wirklich codebasierter Entwickler wie Peter Sommerlad, Kevlin Henney und Giovanni Asproni. Ihre Mantras lauten: »Der ​Code ist das ​Design« und »Einfacher Code«. Während wir darauf achten müssen, dass die Schnittstelle das Programm ist und dass ihre Struktur viel über die Struktur unseres Programmes aussagt, ist es von erfolgsentscheidender Bedeutung, dass wir uns laufend mit der bescheidenen Einstellung identifizieren, dass das Design tatsächlich nur im Code existiert. Und während eine Überarbeitung in der Metapher der fabrikmäßigen Produktion zu höheren Kosten führt, führt sie beim Design zu einem Mehrwert. Wir sollten unseren Code als den wunderschönen Ausdruck edler Design-Anstrengungen betrachten – Design als Prozess, nicht als statischer Endpunkt. Nur im Code lassen sich letztlich die architektonischen Metriken der Kopplung und Kohäsion nachweisen. Wenn Larry ​Constantine Kopplung und Kohäsion beschreibt, spricht er von Code – nicht von abgehobenen abstrakten Konzepten, die man vielleicht in UML findet. Richard ​Gabriel rät uns in seinem Essay Abstraction Descant, Abstraktion sei böse. Code ist anti-böse, und sauberer Code ist vielleicht göttlich.

Zurück zu meiner kleinen Packung Ga-Jol: Ich glaube, dass es wichtig ist, anzumerken, dass uns die dänische Weisheit nicht nur rät, unsere Aufmerksamkeit auf die kleinen Aufgaben zu lenken, sondern auch, bei kleinen Aufgaben ehrlich zu sein. Dies bedeutet, wir müssen dem Code gegenüber ehrlich sein, wir müssen unseren Kollegen gegenüber über den Zustand unseres Codes ehrlich sein und vor allem, wir müssen uns selbst gegenüber über den Zustand unseres Codes ehrlich sein. Haben wir unser Bestes gegeben, um den »Campingplatz sauberer zu hinterlassen, als wir ihn gefunden haben«? Haben wir das Refactoring des Codes erledigt, bevor wir ihn eingecheckt haben? Dies sind keine nebensächlichen Belange, sondern Belange, die zum Kern agiler Werte gehören. Zum Beispiel empfiehlt ​Scrum, das Refactoring zu einem Bestandteil des Konzepts »Done« (»Fertig«) zu machen. Weder Architektur noch sauberer Code verlangt nach Perfektion, sondern nur nach Ehrlichkeit und dem Bemühen, unser Bestes zu geben. Irren ist menschlich, vergeben göttlich. Bei Scrum machen wir alles sichtbar. Wir zeigen unsere schmutzige Wäsche. Wir sind ehrlich über den Zustand unseres Codes, weil Code niemals perfekt ist. Wir werden menschlicher, werden würdiger, das Göttliche zu empfangen, und nähern uns der Größe in den Details.

In unserem Beruf brauchen wir verzweifelt alle Hilfe, die wir bekommen können. Wenn ein sauberer Fabrikboden die Anzahl der Unfälle reduziert und wohlgeordnete Werkzeugkästen die Produktivität verbessern, dann kann man dies nur befürworten. Was dieses Buch angeht: Es ist die beste pragmatische Anwendung von Lean-Prinzipien auf Software, die ich je in Druckform gesehen habe. Aber weniger hatte ich von dieser praktischen kleinen Gruppe denkender Individuen auch nicht erwartet, die sich nicht nur seit Jahren darum bemühen, immer besser zu werden, sondern auch ihr Wissen an die Branche weiterzugeben. Dieses Buch ist ein Ausdruck dieses Bemühens. Es hinterlässt die Welt ein wenig besser, als ich sie vorfand, bevor Uncle Bob mir das Manuskript schickte.

Doch genug von meinen abgehobenen Einsichten. Ich muss meinen Schreibtisch aufräumen.

James O. Coplien

Mørdrup, Dänemark

Einführung

Abb. 1: Abdruck mit freundlicher Genehmigung von Thom Holwerda (http://www.osnews.com/story/19266/WTFs_m)

Welche Tür repräsentiert Ihren Code? Welche Tür repräsentiert Ihr Team oder Ihr Unternehmen? Warum sind wir in diesem Raum? Geht es nur um einen normalen Code-Review oder haben wir eine Reihe schrecklicher Probleme gefunden, die kaum geringer als das Leben sind? Debuggen wir in Panik; brüten wir über Code, der unserer Meinung nach funktionieren sollte? Laufen uns die Kunden in Scharen davon und hängen uns die Manager im Nacken? Wie können wir dafür sorgen, dass wir hinter der richtigen Tür landen, wenn es heiß hergeht? Die Antwort ist: ​Könnerschaft.

​Können zu erwerben, hat zwei Aspekte: Wissen und Arbeit. Sie müssen sich Prinzipien, Patterns, Techniken und Heuristiken aneignen, die jeder Fachmann kennt, und Sie müssen dieses Wissen in Ihre Finger, Ihre Augen und Ihren Bauch einprägen, indem Sie hart arbeiten und üben.

Ich kann Ihnen die physikalischen Gesetzmäßigkeiten des Fahrradfahrens vermitteln. Tatsächlich ist die entsprechende klassische Mathematik relativ einfach. Schwerkraft, Reibung, Drehmoment, Massenschwerpunkt usw. können auf weniger als einer Seite mit Gleichungen demonstriert werden. Mit diesen Formeln könnte ich Ihnen beweisen, dass Fahrradfahren praktisch ist, und Ihnen das gesamte Wissen vermitteln, das Sie brauchen, um es auszuüben. Doch was passiert beim ersten Mal, wenn Sie ein Fahrrad besteigen? Sie fallen runter.

Beim ​Codieren ist es genauso. Wir könnten alle »So-geht’s«-Prinzipien von sauberem Code niederschreiben und dann darauf vertrauen, dass Sie die Arbeit erledigen. (Anders ausgedrückt: Wir könnten Sie einfach auf die Nase fallen lassen, wenn Sie das Fahrrad besteigen.) Doch was für eine Art von Lehrer wären wir dann, und welche Art von Schüler würde dann aus Ihnen werden?

So also nicht. So soll dieses Buch nicht funktionieren.

​Sauberen ​Code schreiben zu lernen, ist harte Arbeit. Es erfordert mehr, als nur die Prinzipien und Patterns zu kennen. Sie müssen sich an dem Code abarbeiten. Sie müssen es selbst üben und aus Ihren Fehlern lernen. Sie müssen andere dabei beobachten, wie sie es ausprobieren, welche Fehler sie machen. Sie müssen erkennen, wo sie stolpern, und ihre Schritte nachvollziehen. Sie müssen sehen, welche Entscheidungen ihnen besonders schwerfallen und welchen Preis sie bezahlen müssen, wenn sie die falschen Entscheidungen treffen.

Sie sollten sich auf harte Arbeit einstellen, wenn Sie dieses Buch lesen. Dies ist kein Buch, das Ihnen »angenehme« Unterhaltung bietet und das Sie im Flugzeug lesen und vor der Landung beenden können. Dieses Buch fordert Sie auf, hart zu arbeiten. Um welche Art von Arbeit geht es dabei? Sie werden Code lesen – sehr viel Code. Und Sie werden aufgefordert, darüber nachzudenken, wo dieser Code richtig und wo er falsch ist. Sie werden aufgefordert, uns dabei zu folgen, wie wir Module zerpflücken und wieder zusammensetzen. Dies braucht Zeit und Mühe; aber wir sind der Ansicht, dass es sich für Sie lohnt.

Wir haben dieses Buch in drei Teile aufgeteilt. Die ersten Kapitel beschreiben die Prinzipien, Patterns und Techniken für das Schreiben von sauberem Code. Diese Kapitel enthalten eine ganze Menge Code, und es wird nicht einfach sein, ihn zu lesen. Sie bereiten Sie auf den zweiten Teil vor. Wenn Sie das Buch nach dem Lesen des ersten Abschnitts aus der Hand legen, alles Gute für Sie!

Der zweite Teil des Buches enthält die schwerere Arbeit. Er besteht aus mehreren Fallstudien, die zunehmend komplexer werden. Jede Fallstudie ist ein Beispiel für die Bereinigung von Code – also von der Umwandlung von Code, der gewisse Probleme enthält, in Code, der weniger Probleme enthält. In diesen Teil geht es sehr ins Detail. Sie müssen ständig zwischen dem beschreibenden Text und den Code-Listings hin- und herblättern. Sie müssen den Code, mit dem wir arbeiten, analysieren und verstehen und unsere Überlegungen für die durchgeführten Änderungen nachvollziehen. Sie müssen dafür schon einige Zeit reservieren, denn Sie werden dafür einige Tage benötigen.

Im dritten Teil des Buches erhalten Sie Ihren Lohn. Er besteht aus einem einzigen Kapitel mit einer Liste von Heuristiken und Smells, die während der Erstellung der Fallstudien zusammengetragen wurden. Während wir den Code in den Fallstudien analysierten und bereinigten, haben wir alle Gründe für unsere Aktionen als Heuristik oder Smell dokumentiert. Wir versuchten, unsere eigenen Reaktionen auf den Code zu verstehen, den wir gelesen und geändert hatten, und mühten uns wirklich ab, herauszufinden und festzuhalten, warum wir fühlten, was für fühlten, und warum wir taten, was wir taten. Das Ergebnis ist eine Wissensbasis, die unsere Art zu denken beschreibt, wenn wir sauberen Code schreiben und lesen.

Diese Wissensbasis hat für Sie nur einen beschränkten Wert, wenn Sie die Fallstudien im zweiten Teil dieses Buches nicht sorgfältig lesen und nachvollziehen. In diesen Fallstudien haben wir sorgfältig alle durchgeführten Änderungen mit Referenzen auf die Wissensbasis versehen. Diese Referenzen werden wie folgt in eckigen Klammern angegeben: [H22]. Dies ermöglicht es Ihnen, den Kontext zu sehen, in dem diese Heuristiken angewendet und geschrieben wurden! Es sind nicht die Heuristiken selbst, die so wertvoll sind, sondern die Beziehungen zwischen diesen Heuristiken und den einzelnen Entscheidungen, die wir beim Bereinigen des Codes in den Fallstudien getroffen haben.

Um Ihnen mit diesen Beziehungen noch weiterzuhelfen, haben wir am Anfang des Indexes Querverweise auf die Seitenzahlen eingefügt, unter denen Sie die jeweilige Referenz finden können. So können Sie leicht alle Stellen lokalisieren, an denen eine bestimmte Heuristik angewendet wurde.

Wenn Sie nur den ersten und dritten Teil lesen und die Fallstudien überspringen, dann haben Sie nur ein weiteres unterhaltsames Buch über das Schreiben von Software gelesen. Doch wenn Sie sich die Zeit nehmen, die Fallstudien durchzuarbeiten und jedem winzigen Schritt und jeder kleinen Entscheidung zu folgen – wenn Sie sich also an unsere Stelle versetzt und sich gezwungen haben, in denselben Bahnen zu denken wie wir, dann werden Sie ein viel tieferes Verständnis dieser Prinzipien, Patterns, Techniken und Heuristiken gewonnen haben. Diese werden dann nicht mehr nur gewisse »ganz nützliche« Techniken unter anderen sein, sondern werden Ihnen in Fleisch und Blut übergegangen sein. Sie werden ein Teil von Ihnen geworden sein, ähnlich wie ein Fahrrad eine Erweiterung Ihres Willens wird, wenn Sie das Fahren erlernt haben.

Danksagungen

Grafiken

Danke an meine beiden Künstlerinnen Jenniffer Kohnke und Angela Brooks. Jennifer ist für die beeindruckenden und kreativen Bilder am Anfang jedes Kapitels und die Porträts von Kent Beck, Ward Cunningham, Bjarne Stroustrup, Ron Jeffries, Grady Booch, Dave Thomas, Michael Feathers und mir verantwortlich.

Für Ann Marie: die Liebe meines Lebens.

Kapitel 1: Sauberer Code

Sie lesen das Buch aus zwei Gründen. Erstens: Sie sind Programmierer. Zweitens: Sie wollen ein besserer Programmierer werden. Gut. Wir brauchen bessere Programmierer.

Dieses Buch handelt von guter Programmierung. Es ist voller Code. Wir werden uns Code aus allen möglichen Richtungen anschauen. Wir werden ihn von oben und unten und von außen und innen betrachten. Wenn wir fertig sind, werden Sie sehr viel über Code wissen. Darüber hinaus werden Sie guten Code von schlechtem Code unterscheiden können. Sie werden wissen, wie Sie guten Code schreiben können. Und Sie werden wissen, wie Sie schlechten Code in guten Code transformieren können.

1.1  Code, Code und nochmals Code

Vielleicht könnte man einwenden, ein Buch über ​Code wäre doch etwas altmodisch – Code wäre doch längst kein Thema mehr; stattdessen sollte man sich mit Modellen und Anforderungen befassen. Tatsächlich vertreten einige Leute die Auffassung, die Ära des Codes ginge zu Ende. Bald werde aller Code nicht mehr geschrieben, sondern generiert werden. Programmierer würden einfach überflüssig werden, weil Geschäftsentwickler Programme einfach aus Spezifikationen generieren würden.

Unsinn! Wir werden niemals ohne Code arbeiten können, weil der Code die Details der Anforderungen repräsentiert. Auf einer gewissen Ebene können diese Details nicht ignoriert oder abstrahiert werden; sie müssen spezifiziert werden. Und die Spezifikation von Anforderungen in einer Detailgenauigkeit, dass sie von einer Maschine ausgeführt werden können, ist ​Programmierung. Und eine solche Spezifikation ist ​Code.

Ich rechne damit, dass die ​Abstraktionsebene unserer Sprachen noch höher gehen wird. Ich erwarte auch, dass die Anzahl der domänenspezifischen Sprachen weiterhin wachsen wird. Diese Entwicklung bringt Vorteile mit sich, aber sie wird den Code nicht eliminieren. Tatsächlich werden alle Spezifikationen, die auf diesen höheren Ebenen und in den domänenspezifischen Sprachen geschrieben werden, Code sein! Sie müssen immer noch stringent, genau und so formal und detailliert sein, dass sie von einer Maschine verstanden und ausgeführt werden können.

Leute, die denken, Code werde eines Tages verschwinden, ähneln Mathematikern, die hoffen, eines Tages eine Mathematik zu entdecken, die nicht formal sein muss. Sie hoffen, dass wir eines Tages eine Methode entdecken werden, Maschinen zu erschaffen, die tun, was wir wollen, und nicht, was wir sagen. Diese Maschinen müssen in der Lage sein, uns so gut zu verstehen, dass sie unsere unscharf formulierten Bedürfnisse in perfekt ausgeführte Programme übersetzen können, die genau diese Bedürfnisse erfüllen.

Dies wird nie passieren. Nicht einmal Menschen mit all ihrer Intuition und Kreativität sind bis jetzt in der Lage gewesen, aus den unscharfen Gefühlen ihrer Kunden erfolgreiche Systeme abzuleiten. Wenn wir überhaupt etwas aus der Disziplin der Anforderungsspezifikation gelernt haben, ist es Folgendes: Wohlspezifizierte Anforderungen sind genauso formal wie Code und können als ausführbare Tests dieses Codes verwendet werden!

Vergessen Sie nicht, dass ​Code letztlich die Sprache ist, in der wir die Anforderungen ausdrücken. Wir können Sprachen konstruieren, die näher bei den Anforderungen angesiedelt sind. Wir können Werkzeuge schaffen, die uns helfen, diese Anforderungen zu parsen und zu formalen Strukturen zusammenzusetzen. Aber wir werden niemals die erforderliche Präzision eliminieren können – und deshalb wird es immer Code geben.

1.2  Schlechter Code

Abb. 1.1: Kent Beck

​​Neulich las ich das Vorwort zu dem Buch ​​Implementation Patterns von Kent Beck [Beck07]. Darin schreibt er: »... dieses Buch basiert auf einer recht fragilen Prämisse: dass guter Code eine Rolle spiele ...«. Eine fragile Prämisse? Dem kann ich nicht zustimmen! Ich glaube, dass diese Prämisse zu den robustesten, am besten unterstützten und meistdiskutierten Prämissen unserer Zunft gehört (und ich glaube, das weiß Kent Beck auch). Wir wissen, dass guter Code eine Rolle spielt, weil wir uns so lange mit seiner mangelnden Qualität auseinandersetzen mussten.

Ich kenne ein Unternehmen, das in den späten 80er-Jahren eine Killer-Applikation herausbrachte. Sie war sehr beliebt, und zahlreiche professionelle Anwender kauften und nutzten sie. Aber dann wurden die Release-Zyklen immer länger. Bugs wurden von einem Release zum nächsten nicht mehr repariert. Die Startzeiten wurden länger und die Abstürze häufiger. Ich erinnere mich an den Tag, an dem ich das Produkt frustriert abschaltete und niemals wieder benutzte. Kurz danach verschwand das Unternehmen vom Markt.

Zwei Jahrzehnte später traf ich einen früheren Mitarbeiter dieses Unternehmens und fragte ihn, was damals passiert wäre. Die Antwort bestätigte meine Befürchtungen. Das Unternehmen hatte das Produkt zu schnell auf den Markt gebracht und im Code ein riesiges Chaos angerichtet. Je mehr Funktionen zu dem Code hinzugefügt wurden, desto schlechter wurde er, bis das Unternehmen ihn einfach nicht mehr verwalten konnte. Es war der schlechte Code, der das Unternehmen in den Abgrund trieb.

Sind Sie jemals erheblich von schlechtem Code beeinträchtigt worden? Wenn Sie als Programmierer auch nur ein bisschen Erfahrung haben, dann haben Sie eine solche Behinderung viele Male erlebt. Tatsächlich haben wir eine spezielle Bezeichnung dafür: ​Wading (Waten). Wir waten durch schlechten Code. Wir kämpfen uns durch einen Morast verschlungener Schlingpflanzen und verborgener Fallgruben. Wir mühen uns ab, den richtigen Weg zu finden, und hoffen auf irgendwelche Hinweise, die uns zeigen, was passiert; aber alles, was wir sehen, ist ein schier endloses Meer von sinnlosem Code.

Natürlich sind Sie von schlechtem Code behindert worden. Also – warum haben Sie ihn geschrieben?

Haben Sie zu schnell gearbeitet? Waren Sie unter Druck? Wahrscheinlich. Vielleicht hatten Sie das Gefühl, keine Zeit für gute Arbeit zu haben, meinten, Ihr Chef würde ärgerlich werden, wenn Sie sich die Zeit nehmen würden, Ihren Code aufzuräumen. Vielleicht waren Sie es einfach leid, an diesem Programm zu arbeiten, und wollten endlich damit fertig werden. Oder vielleicht haben Sie Ihren Stapel unerledigter Arbeit angeschaut, die Sie längst hätten erledigen müssen, und sind zu dem Schluss gekommen, Sie müssen dieses Modul zusammenschustern, um mit dem nächsten weitermachen zu können. Wir alle kennen diese Erfahrung.

Wir alle haben uns das Chaos angeschaut, das wir gerade angerichtet hatten, und dann beschlossen, es an einem anderen Tag zu beseitigen. Wir alle haben die Erleichterung gefühlt, zu sehen, dass unser chaotisches Programm lief, und beschlossen, dass ein laufendes Chaos besser wäre als nichts. Wir alle haben uns vorgenommen, später zurückzukommen und das Chaos zu beseitigen. Natürlich kannten wir damals das Gesetz von L​eBlanc nicht: Später gleich niemals.

1.3  Die Lebenszykluskosten eines Chaos

​Wenn Sie schon länger als zwei bis drei Jahre programmieren, haben Sie wahrscheinlich die Erfahrung gemacht, dass Ihre Arbeit von dem chaotischen Code eines anderen Entwicklers erheblich verlangsamt worden ist. Die Verlangsamung kann beträchtlich sein. Im Laufe von einem oder zwei Jahren kann es passieren, dass Teams, die am Anfang eines Projekts sehr schnell vorangekommen waren, sich plötzlich nur noch im Schneckentempo vorwärtsbewegen. Jede Änderung des Codes führt zur Defekten an zwei oder drei anderen Stellen des Codes. Keine Änderung ist trivial. Für jede zusätzliche Funktion oder Modifikation des Systems müssen alle Verzweigungen, Varianten und Knoten »verstanden« werden, damit weitere Verzweigungen, Varianten und Knoten hinzugefügt werden können. Im Laufe der Zeit wird das Chaos so groß und so verfilzt, dass Sie es nicht mehr bereinigen können. Sie sind am Ende Ihres Weges angelangt.

Während das Chaos immer größer wird, nimmt die ​​Produktivität des Teams laufend ab und geht asymptotisch gegen null. Während die Produktivität sinkt, tut das Management das Einzige, was es kann: Es weist dem Projekt mehr Personal zu in der Hoffnung, die Produktivität zu steigern. Aber das neue Personal versteht das Design des Systems nicht. Es kennt nicht den Unterschied zwischen einer Änderung, die zum Zweck des Designs passt, und einer Änderung, die dem zuwiderläuft. Darüber hinaus stehen Sie und die anderen Teammitglieder unter schrecklichem Druck, die Produktivität zu verbessern. Deshalb produzieren alle immer mehr Chaos und senken damit die Produktivität immer weiter gegen null (siehe Abbildung 1.2).

Abb. 1.2: Produktivität und Zeit

Das große Redesign in den Wolken

​​Schließlich rebelliert das Team. Das Management wird darüber informiert, dass man mit dieser zweifelhaften Code-Basis nicht weiterarbeiten könne. Es wird ein Redesign gefordert. Das Management will aber nicht die Ressourcen für ein komplett neues Redesign des Projekts aufwenden, kann sich aber auch nicht der Erkenntnis verschließen, dass die Produktivität nicht akzeptabel ist. Schließlich beugt es sich den Forderungen der Entwickler und autorisiert das große Redesign in den Wolken.

Es wird ein neues ​Tiger-Team zusammengestellt. Jeder möchte zu diesem Team gehören, weil es ein frisches neues Projekt ist. Man darf neu anfangen und etwas wirklich Schönes erstellen. Aber nur die Besten und Hellsten werden für das Tiger-Team ausgewählt. Alle anderen müssen sich um die Wartung des gegenwärtigen Systems kümmern.

Jetzt gibt es ein Wettrennen zwischen den beiden Teams. Das Tiger-Team muss ein neues System erstellen, das alle Funktionen des alten erfüllt. Und nicht nur das: Es muss auch mit den Änderungen Schritt halten, die laufend an dem alten System vorgenommen werden. Das Management wird das alte System nicht ersetzen, bevor nicht das neue alle Funktionen des alten erfüllt.

Dieser Wettlauf kann sich sehr lange hinziehen. Ich habe Zeitspannen von bis zu zehn Jahren erlebt. Und wenn er beendet wird, sind die ursprünglichen Mitglieder des Tiger-Teams längst nicht mehr da, und die gegenwärtigen Mitglieder verlangen nach einem Redesign des neuen Systems, weil es ein solches Chaos sei.

Wenn nur ein kleiner Teil dieser Geschichte Ihrer Erfahrung entspricht, dann wissen Sie bereits, dass die Zeit, die Sie für das Sauberhalten Ihres Codes verwenden, nicht nur kosteneffizient, sondern eine Frage des beruflichen Überlebens ist.

Einstellung

Sind Sie jemals durch einen Morast gewatet, der so dicht war, dass es Wochen dauerte, um zu tun, was nur einige Stunden hätte dauern sollen? Haben Sie erlebt, dass eine Änderung, die nur eine Zeile hätte erfordern sollen, in Hunderten verschiedener Module durchgeführt werden musste? Diese Symptome kommen leider allzu oft vor.

Warum passiert das mit ​Code? Warum verrottet guter Code so schnell zu schlechtem Code? Dafür haben wir viele Erklärungen. Wir beklagen uns, dass die Anforderungen in einer Weise geändert wurden, die dem ursprünglichen Design zuwiderläuft. Sie jammern, dass der Zeitplan zu eng bemessen war, um die Aufgaben richtig zu erledigen. Geben dummen Managern und den toleranten Kunden und nutzlosen Marketing-Typen und einem unzureichenden Telefon-Support die Schuld. Aber der Fehler, lieber Dilbert, liegt nicht in unseren Sternen, sondern in uns selbst. Wir sind unprofessionell.

Diese Pille zu schlucken, mag etwas bitter sein. Wie könnte dieses Chaos unsere Schuld sein? Was ist mit den Anforderungen? Was ist mit dem Zeitplan? Gibt es etwa keine dummen Manager und nutzlose Marketing-Typen? Tragen sie nicht einen Teil der Schuld?

Nein. Die Manager und Marketing-Leute fragen uns nach den Informationen, die sie benötigen, um Versprechungen und Zusagen zu machen; und selbst wenn sie uns nicht fragen, sollten wir keine Hemmungen haben, ihnen zu sagen, was wir denken. Die Benutzer wenden sich an uns, damit wir ihnen zeigen, wie das System ihre Anforderungen erfüllt. Die Projektmanager benutzen unsere Informationen, um ihre Zeitpläne aufzustellen. Wir sind eng in die Planung des Projekts eingebunden und tragen einen großen Teil der Verantwortung für auftretende Fehler, insbesondere wenn diese Fehler mit schlechtem Code zu tun haben!

»Doch halt!«, sagen Sie. »Wenn ich nicht tue, was mein Manager sagt, werde ich gefeuert.« Wahrscheinlich nicht. Die meisten Manager wollen die Wahrheit wissen, selbst wenn sie sich nicht immer entsprechend verhalten. Die meisten Manager wollen guten Code haben, selbst wenn sie von ihrem Zeitplan besessen sind. Vielleicht verteidigen sie leidenschaftlich den Zeitplan und die Anforderungen; aber das ist ihr Job. Dagegen ist es Ihr Job, den Code mit gleicher Leidenschaft zu verteidigen.

Betrachten wir eine Analogie: Was würden Sie als Arzt machen, wenn ein Patient Sie auffordern würde, dieses blödsinnige Händewaschen bei der Vorbereitung auf einen chirurgischen Eingriff zu lassen, weil es zu viel Zeit kostet? (Als das Händewaschen 1847 den Ärzten erstmals von Ignaz Semmelweis empfohlen wurde, wurde es mit der Begründung zurückgewiesen, die Ärzte wären zu beschäftigt und hätten keine Zeit, sich die Hände zwischen ihren Patientenbesuchen zu waschen.) Natürlich hat der Patient Vorrang. Dennoch sollte der Arzt in diesem Fall die Forderung kompromisslos zurückweisen. Warum? Weil der Arzt mehr über die Risiken einer Erkrankung und Infektion weiß als der Patient. Es wäre unprofessionell (und in diesem Fall sogar kriminell), wenn der Arzt der Forderung des Patienten nachgeben würde.

Deshalb ist es auch unprofessional, dass sich Programmierer dem Willen von Managern beugen, die die Risiken nicht verstehen, die mit dem Erzeugen von Chaos im Code verbunden sind.

Das grundlegende Problem

Programmierer werden mit einem grundlegenden Wertekonflikt konfrontiert. Erfahrene Entwickler wissen, dass ihre Arbeit durch alten chaotischen Code erheblich behindert wird. Dennoch fühlen alle Entwickler den Druck, chaotischen Code zu schreiben, um Termine einzuhalten. Kurz gesagt: Sie nehmen sich nicht die Zeit, es richtig zu machen!

Echte Profis wissen, dass der zweite Teil dieses Konflikts falsch ist. Man erfüllt einen Termin eben nicht, indem man chaotischen Code produziert. Tatsächlich verlangsamt chaotischer Code Ihre Arbeit sofort und führt dazu, dass Sie Ihren Termin nicht einhalten können. Die einzige Methode, den Termin einzuhalten, besteht darin, den Code jederzeit so sauber wie möglich zu halten.

Sauberen Code schreiben – eine Kunst?

Angenommen, Sie glaubten, chaotischer Code wäre eine beträchtliche Behinderung Ihrer Arbeit. Wenn Sie jetzt akzeptieren, dass die einzige Möglichkeit, schneller zu arbeiten, darin besteht, den eigenen Code sauber zu halten, müssen Sie sich zwangsläufig fragen: »Wie schreibe ich sauberen Code?« Es hat keinen Sinn, zu versuchen, sauberen Code zu schreiben, wenn Sie nicht wissen, wie sauberer Code aussieht!

Leider haben wir hier eine schlechte Nachricht: ​Sauberen Code zu schreiben, hat sehr viel mit dem Malen eines Bildes zu tun. Die meisten können erkennen, wann ein Bild gut oder schlecht gemalt ist. Aber dies erkennen zu können, bedeutet nicht, dass wir auch malen können. Wenn Sie also in der Lage sind, sauberen von schlechtem Code zu unterscheiden, bedeutet dies nicht automatisch, dass Sie sauberen Code schreiben können!

Sauberen Code zu schreiben, erfordert den disziplinierten Einsatz zahlreicher kleiner Techniken, die mit einem sorgfältig erworbenen Gefühl für »Sauberkeit« angewendet werden. Dieses »​Gefühl für den Code​« ist der Schlüssel. Einige sind damit geboren. Einige müssen es sich mehr oder weniger mühsam erarbeiten. Dieses Gefühl für den Code hilft uns nicht nur, guten von schlechtem Code zu unterscheiden; sondern zeigt uns die Strategie, wie wir unser Arsenal von erworbenen Techniken anwenden müssen, um schlechten Code in guten zu transformieren.

Ein Programmierer ohne dieses »Gefühl für den Code« kann sich ein chaotisches Modul anschauen und das Chaos erkennen, hat aber absolut keine Vorstellung davon, was er dagegen tun könnte. Ein Programmierer mit »Gefühl für den Code« schaut sich das chaotische Modul an und erkennt seine Optionen und Änderungsmöglichkeiten. Sein »Gefühl für den Code« hilft ihm dabei, die beste Option auszuwählen und eine Reihe von Änderungsschritten festzulegen, die ihn zum Ziel bringen und zugleich nach jedem Teilschritt die volle Funktionsfähigkeit des Codes erhalten.

Kurz gesagt: Ein Programmierer, der sauberen Code schreibt, ist ein Künstler, der einen leeren Bildschirm mit einer Reihe von Transformationen in ein elegant codiertes System umwandelt.

Was ist sauberer Code​?

Es gibt wahrscheinlich so viele Definitionen wie Programmierer. Deshalb fragte ich einige sehr bekannte und sehr erfahrene Programmierer nach ihrer Meinung.

Bjarne Stroustrup

Abb. 1.3: Bjarne ​Stroustrup

Bjarne ​Stroustrup, Erfinder von C++ und Autor von The C++ Programming Language

Mein Code sollte möglichst elegant und effizient sein. Die Logik sollte gradlinig sein, damit sich Bugs nur schwer verstecken können, die Abhängigkeiten sollten minimal sein, um die Wartung zu vereinfachen, das Fehler-Handling​ sollte vollständig gemäß einer vordefinierten Strategie erfolgen, und das Leistungsverhalten sollte dem Optimum so nah wie möglich kommen, damit der Entwickler nicht versucht ist, den Code durch Ad-hoc-Optimierungen zu verunstalten. Sauberer Code erledigt eine Aufgabe gut.

Bjarne verwendet das Wort »elegant«. Was für ein Wort! Im Wörterbuch findet man auch folgende Synonyme: ansprechende Anmut und Kunstfertigkeit in Aussehen oder Verhalten; ansprechende Sinnlichkeit und Einfachheit. Wichtig ist dabei die Betonung von »ansprechend«. Offensichtlich glaubt Bjarne, dass sauberer Code angenehm zu lesen sein soll. Solchen Code zu lesen, sollte einen Ausdruck des Wohlgefallens auf Ihr Gesicht zaubern, den Sie auch vom Anschauen eines rassigen Automobils kennen.

Bjarne erwähnt auch die Effizienz des Codes. Vielleicht sollte uns dies bei dem Erfinder von C++ weniger überraschen; aber ich glaube, dass er damit mehr als seinen Wunsch nach einer Geschwindigkeit meint. Verschwendete Zyklen sind unelegant, sie vermitteln kein angenehmes Gefühl. Und jetzt beachten Sie, wie Bjarne die Folgen dieser Uneleganz beschreibt. Er verwendet den Ausdruck »versucht sein«. Darin ist eine tiefe Weisheit verborgen. Schlechter Code verleitet dazu, das Chaos zu vergrößern! Wenn andere schlechten Code ändern, neigen sie dazu, ihn noch schlechter zu machen.

Die ​Pragmatischen Programmierer Dave Thomas und Andy ​Hunt drückten dasselbe auf andere Weise aus. Sie verwendeten die Metapher der zerbrochenen Fenster (http://www.artima.com/intv/fixit.html). Ein Gebäude mit zerbrochenen Fenstern sieht so aus, als würde sich niemand darum kümmern. Deshalb kümmern sich auch andere Entwickler nicht um den Code. Sie lassen es gewissermaßen zu, dass weitere Fenster zerbrochen werden. Schließlich helfen sie aktiv dabei. Sie verschmieren die Vorderfront mit Graffiti und lassen zu, dass sich Müll ansammelt. Der Prozess des Zerfalls beginnt mit einem zerbrochenen Fenster.

Bjarne erwähnt auch, dass das Fehler-Handling vollständig sein sollte. Dies gehört zur Disziplin, aufmerksam in den Details zu sein. Ein verkürztes Fehler-Handling ist nur eine Methode, wie Programmierer Details vernachlässigen. Speicherlecks und Race-Bedingungen sind weitere Beispiele dafür. Eine inkonsistente Namensgebung zählt ebenfalls zu. Das Fazit ist: Sauberer Code bedeutet auch große Sorgfalt im Detail.

Bjarne schließt mit der Zusicherung, dass sauberer Code eine Aufgabe gut erledigt. Es ist kein Zufall, dass so viele Prinzipien des Software-Designs auf diese einfache Mahnung zurückgeführt werden können. Autor für Autor hat versucht, diesen einen Gedanken zu kommunizieren. Schlechter Code tut zu viel; seine Absicht ist nicht klar zu erkennen und er versucht, mehrere Zwecke auf einmal zu erfüllen. Sauberer Code ist fokussiert. Jede Funktion, jede Klasse, jedes Modul ist eindeutig auf einen einzigen Zweck ausgerichtet und lässt sich von den umgebenden Details weder ablenken noch verunreinigen.

Grady Booch

Abb. 1.4: Grady Booch

Grady ​Booch, Autor von Object-Oriented Analysis and Design with Applications

Sauberer Code ist einfach und direkt. Sauberer Code liest sich wie wohlgeschriebene Prosa. Sauberer Code verdunkelt niemals die Absicht des Designers, sondern ist voller griffiger (engl. crisp) Abstraktionen und geradliniger Kontrollstrukturen.

Einige Punkte von Grady decken sich mit denen von Bjarne, aber er betrachtet das Ganze aus der Perspektive der ​​Lesbarkeit. Mir gefällt besonders seine Auffassung, dass sich sauberer Code wie wohlgeschriebene Prosa lesen lassen soll. Denken Sie zurück an ein wirklich gutes Buch, das Sie gelesen haben. Erinnern Sie sich, wie die Wörter verschwanden und durch Bilder ersetzt wurden? Es war, als würden Sie einen Film sehen, nicht wahr? Besser! Sie sahen die Zeichen, Sie hörten die Geräusche, Sie erlebten die Leidenschaften und den Humor.

Sauberen Code zu lesen, wird natürlich niemals dasselbe sein, wie Der Herr der Ringe zu lesen. Dennoch ist die literarische Metapher brauchbar. Wie ein guter Roman sollte sauberer Code die Spannung in den zu lösenden Problemen sauber herausarbeiten. Diese Spannung sollte einem Höhepunkt zutreiben und dann dem Leser dieses »Aha! Ja natürlich!« vermitteln, wenn die Probleme und Spannungen bei der Enthüllung einer offensichtlichen Lösung aufgelöst werden.

Für mich ist der Ausdruck »griffige Abstraktion​« (im Original: »crisp abstraction«, wörtl. »knackige oder frische Abstraktion«, unübersetzbar) ein faszinierendes Oxymoron (ein Widerspruch in sich)! Schließlich bedeutet das Wort »griffig« eher etwas Handgreifliches, Konkretes, praktisch Nutzbares. Trotz dieses scheinbaren Widerspruchs der Wörter vermitteln sie eine klare Botschaft. Unser Code sollte nicht spekulativ, sondern nüchtern und sachbezogen sein. Es sollte nur das Erforderliche enthalten. Unsere Leser sollten unsere Bestimmtheit erkennen können.

Dave Thomas

Abb. 1.5: Dave Thomas

»Big« Dave ​Thomas, Gründer der ​OTI, der Pate (Godfather) der​ Eclipse-Strategie

Sauberer Code kann von anderen Entwicklern gelesen und verbessert werden. Er verfügt über Unit- und Acceptance-Tests. Er enthält bedeutungsvolle Namen. Er stellt zur Lösung einer Aufgabe nicht mehrere, sondern eine Lösung zur Verfügung. Er enthält minimale Abhängigkeiten, die ausdrücklich definiert sind, und stellte ein klares und minimales API zur Verfügung. Code sollte »literate« sein, da je nach Sprache nicht alle erforderlichen Informationen allein im Code klar ausgedrückt werden können. (A.d.Ü.: »Literate Programming« ist eine Unterströmung, bei der die Einheit von Kommentaren und Code betont und gefördert wird.)

Auch Big Dave strebt wie Grady Lesbarkeit an, fordert aber eine wichtige Ergänzung. Für Dave ist es wichtig, dass sauberer Code es anderen Entwicklern erleichtert, ihn zu verbessern. Dies mag offensichtlich scheinen, aber es kann nicht genug betont werden. Schließlich gibt es einen Unterschied zwischen Code, der einfach zu lesen ist, und Code, der einfach zu ändern ist.

Dave macht Sauberkeit von Tests abhängig! Vor zehn Jahren hätten viele bei dieser Forderung die Stirn gerunzelt. Aber die Disziplin der ​Test Driven Development (TDD​) hat einen wesentlichen Einfluss auf die Software-Branche gehabt und hat sich zu einer der grundlegenden Disziplinen entwickelt. Dave hat recht. Code ohne Tests ist nicht sauber. Egal wie elegant er ist, egal wie lesbar und änderungsfreundlich er ist, ohne Tests ist er unsauber.

Dave verwendet das Wort ​​minimal zweimal. Offensichtlich schätzt er Code, der einen geringen Umfang hat. Tatsächlich hat sich im Laufe der letzten Jahre ein Konsens in der Software-Literatur gebildet: Kleiner ist besser.

Dave sagt auch, Code solle ​literate sein. Dies ist ein sanfter Hinweis auf das ​Literate Programming von Donald Knuth [Knuth92]. Die Quintessenz lautet: Code sollte so aufbereitet werden, dass er von Menschen gelesen werden kann.

Michael Feathers

Abb. 1.6: Michael Feathers

Michael ​Feathers, Autor von Working Effectively with Legacy Code

Ich könnte alle Eigenschaften auflisten, die mir bei sauberem Code auffallen; aber es gibt eine übergreifende Qualität, die alle anderen überragt: Sauberer Code sieht immer so aus, als wäre er von jemandem geschrieben worden, dem dies wirklich wichtig war. Es fällt nichts ins Auge, wie man den Code verbessern könnte. Alle diese Dinge hat der Autor des Codes bereits selbst durchdacht; und wenn Sie versuchen, sich Verbesserungen vorzustellen, landen Sie wieder an der Stelle, an der Sie gerade sind: Sie sitzen einfach da und bewundern den Code, den Ihnen jemand hinterlassen hat – jemand, der sein ganzes Können in sorgfältige Arbeit gesteckt hat.

Ein Wort: Sorgfalt. Das ist das eigentliche Thema dieses Buches. Vielleicht hätte ein passender Untertitel gelautet: Wie man seinem Code Sorgfalt angedeihen lässt.

Michael trifft den Nagel auf den Kopf. Sauberer Code ist Code, der sorgfältig erstellt worden ist. Jemand hat sich die Zeit genommen, den Code sauber zu strukturieren und zu schreiben. Jemand hat den Details die erforderliche Sorgfalt angedeihen lassen. Jemand war es nicht egal, wie sein Arbeitsergebnis aussah.

Ron Jeffries

Abb. 1.7: Ron Jeffries

Ron ​Jeffries, Autor von ​Extreme Programming Installed und Extreme Programming Adventures in C#

Ron begann seine Karriere als Programmierer in Fortran bei dem Strategic Air Command und hat Code in fast jeder Sprache und auf fast jeder Maschine geschrieben. Es zahlt sich aus, seine Worte sorgfältig zu überdenken.

In den letzten Jahren beginne ich (und ende ich fast immer) mit ​den Regeln von Beck für einfachen Code. In der Reihenfolge der Priorität erfüllt einfacher Code die folgenden Bedingungen:

Er besteht alle Tests.

Er enthält keine Duplizierung.

Er drückt alle Design-Ideen aus, die in dem System enthalten sind.

Er minimiert die Anzahl der Entities, also der Klassen, Methoden, Funktionen usw.

Unter diesen Bedingungen konzentriere ich mich hauptsächlich auf die Duplizierung. Wenn dieselbe Sache immer wieder gemacht wird, ist dies ein Zeichen dafür, dass wir einen bestimmten Gedanken in unserem Code nicht gut genug repräsentiert haben. Dann versuche ich herauszufinden, diesen Gedanken zu fassen und klarer auszudrücken.

Ausdruckskraft umfasst für mich bedeutungsvolle Namen. Häufig ändere ich die Namen der Dinge mehrfach, bis ich die endgültige Version gefunden habe. Mit modernen Entwicklungswerkzeugen wie etwa ​Eclipse ist die Umbenennung recht einfach, weshalb ich mir darüber keine Gedanken mache. Doch die Ausdruckskraft geht über Namen hinaus. Ich schaue mir auch an, ob ein Objekt oder eine Methode mehr als eine Aufgabe erfüllt. Ist dies der Fall, zerlege ich ein Objekt in zwei oder mehr kleinere Objekte oder führe ein Refactoring einer Methode mit der Extract-Methode so durch, dass die neue Methode klarer zum Ausdruck bringt, was sie tut, und einige Untermethoden sagen, wie dies getan wird.

​​Duplizierungen zu eliminieren und die Ausdruckskraft zu steigern, bringen mich meinem Ideal von sauberem Code schon sehr viel näher. Chaotischen Code allein unter zwei dieser Gesichtspunkte zuvor zu verbessern, kann bereits zu einem erheblich besseren Ergebnis führen. Es gibt jedoch noch einen anderen Aspekt meiner Bemühungen, der etwas schwerer zu erklären ist.

Aufgrund meiner langen Erfahrung beim Programmieren scheint es mir, dass alle Programme aus sehr ähnlichen Elementen aufgebaut sind. Ein Beispiel: »Suche Dinge in einer Collection.« Egal was wir durchsuchen wollen, eine Datenbank mit Mitarbeiter-Datensätzen, eine Hash-Map mit Schlüsseln und Werten oder ein Array mit Elementen bestimmter Art, immer wollen wir ein spezielles Element aus dieser Collection abrufen. Wenn ich eine solche Aufgabe identifiziere, verpacke ich oft ihre spezielle Implementierung in eine abstraktere Methode oder Klasse. Dadurch erziele ich eine Reihe interessanter Vorteile.

Ich kann die Funktionalität jetzt mit etwas Einfachem, etwa einer Hash-Map, implementieren. Doch da jetzt alle Referenzen auf diese Suche in meiner kleinen Abstraktion eingekapselt sind, kann ich die Implementierung jederzeit ändern. Ich komme schneller voran und bewahre mir trotzdem meine Fähigkeit, den Code später zu ändern.

Außerdem lenkt die Collection-Abstraktion oft meine Aufmerksamkeit auf das, was »wirklich« passiert, und hält mich davon ab, Implementierungspfade zu verfolgen, auf denen ich alle möglichen Collection-Verhaltensweisen realisiere, auch wenn ich wirklich nur eine ziemlich einfache Methode brauche, um etwas Gesuchtes zu finden.

Reduzierung der Duplizierung, Steigerung der Ausdruckskraft und frühe Formulierung einfacher Abstraktionen machen für mich sauberen Code aus.

Hier hat Ron in einigen kurzen Absätzen den Inhalt dieses Buches zusammengefasst: keine Duplizierung, eine Aufgabe, Ausdruckskraft, kleine Abstraktionen. Es ist alles da.

Ward Cunningham

Ward Cunningham​, Erfinder des Wiki​, Erfinder von F​it, Miterfinder des e​Xtreme Programming. Treibende Kraft hinter den D​esign Patterns. Smalltalk​- und O​O-Vordenker. Der Pate aller Leute, denen ihr Code nicht egal ist.

Abb. 1.8: Ward Cunningham

Sie wissen, dass Sie an sauberem Code arbeiten, wenn jede Routine, die Sie lesen, ziemlich genau so funktioniert, wie Sie es erwartet haben. Sie können den Code auch »schön« nennen, wenn er die Sprache so aussehen lässt, als wäre sie für das Problem geschaffen worden.

Solche Aussagen sind für Ward charakteristisch. Sie lesen sie, nicken mit dem Kopf und wenden sich dann dem nächsten Thema zu. Die Aussage hört sich so vernünftig, so offensichtlich an, dass sie kaum als etwas Grundlegendes wahrgenommen wird. Sie glauben, sie drücke recht genau das aus, was Sie erwartet haben. Doch schauen wir etwas genauer hin.

»... ziemlich genau so, wie Sie es erwartet haben.« Wann haben Sie zum letzten Mal ein Modul gesehen, das ziemlich genau dem entsprach, was Sie erwartet haben? Ist es nicht wahrscheinlicher, dass die Module, die Sie sich anschauen, rätselhaft, kompliziert und verworren aussehen? Ist es nicht die Regel, dass Sie in die falsche Richtung gelockt werden? Sind Sie es nicht gewohnt, verzweifelt und frustriert die Denkfäden aufzuspüren und durch das ganze System zu verfolgen, aus denen letztlich das Modul gewebt ist? Wann haben Sie zum letzten Mal Code gelesen und dabei mit dem Kopf genickt, wie Sie eben die Aussage von Ward aufgenommen haben?

Ward erwartet, dass Sie beim Lesen von sauberem Code überhaupt keine Überraschungen erleben. Tatsächlich sollte das Ganze fast mühelos sein. Sie lesen den Code, und er entspricht ziemlich genau dem, was Sie erwartet haben. Er ist offensichtlich, einfach und überzeugend. Jedes Modul ist eine Stufe für das nächste. Jedes gibt vor, wie das nächste geschrieben sein wird. Programme, die so sauber sind, sind so außerordentlich gut geschrieben, dass Sie es gar nicht mal bemerken. Der Designer lässt das Problem lächerlich einfach aussehen – ein herausragendes Merkmal aller außerordentlichen Designs.

Und was ist mit Wards Vorstellung von Schönheit? Wir haben alle schon darüber geschimpft, dass unsere Sprachen nicht für unsere Probleme konzipiert worden wären. Aber Wards Aussage gibt uns den Schwarzen Peter zurück. Er sagt, schöner Code lasse die Sprache aussehen, als wäre sie für das Problem gemacht worden! Es liegt also in unserer Verantwortung, die Sprache einfach aussehen zu lassen! Dies sollte Spracheiferern jeder Couleur zu denken geben! Es ist nicht die Sprache, die ein Programm einfach aussehen lässt. Es ist der Programmierer, der die Sprache einfach aussehen lässt!

1.4  Denkschulen​

Abb. 1.9: Uncle Bob (Robert C. Martin)

Was ist mit mir (​