Sie sind auf Seite 1von 480

mitp Deutsche Ausgabe

Robert c. Martin
Robert C. Martin

Clean Code

Refactori n g, Patterns, Testen u nd Tech n i ke n


für sau bere n Cod e

Unter Mitarbeit von:

Michael C. Feathers, Timothy R. Ottinger,


Jefftey J. Langr, Brett L. Schuchert ,
James W. Grenning, Kevin Dean Warnpier
Object Mentor, Inc.

Übersetzt aus dem Amerikanischen


von Reinhard Engel

mitp
Bibliografische Information der Deutschen Nationalbibliothek
Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der
Deutschen Nationalbibliografie. Detaillierte bibliografische Daten sind
im Internet über http:/ jdnb.d-nb.de abrufbar.

ISBN 978-3-8 266-5548-7


I. Auflage 2009

Alle Rechte, auch die der Übersetzung, vorbehalten. Kein Teil des Werkes darf in irgendei­
ner Form (Druck, Fotokopie, Mikrofilm oder einem anderen Verfahren) ohne schriftliche
Genehmigung des Verlages reproduziert oder unter Verwendung elektronischer Systeme
verarbeitet, vervielfältigt oder verbreitet werden. Der Verlag übernimmt keine Gewähr für
die Funktion einzelner Programme oder von Teilen derselben. Insbesondere übernimmt er
keinerlei Haftung für eventuelle aus dem Gebrauch resultierende Folgeschäden.

Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in die­


sem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass sol­
che 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 HAND­
BOOK OF AGILE SOFTWARE CRAFT SMANSHIP, rst Edition, or3235o882 by MARTIN,
ROBERT C., published by Pearson Education, Inc, publishing as Prentice Hall, Copyright ©
2009 Pearson Education, Inc.

All rights reserved. No part ofithis 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, Copy­
right © 2009.

Printed in Austria
© Copyright 2009 by mitp-Verlag
Verlagsgruppe Hüthig Jehle Rehm GmbH
Heidelberg, München, Landsberg, Frechen, Harnburg
www.it-fachportal.de

Lektorat: Sabine Schulz


Korrektorat Petra Heubach-Erdmann
Satz: III-satz, Husby, www.drei-satz.de
Inhaltsverzeichnis

Vorwort................................................... 15

Einführung................................................ 21

1 Sauberer Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.1 Code, Code und nochmals Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.2 Schlechter Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.3 Die Lebenszykluskosten eines Chaos . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Das große Redesign in den Wolken . . . . . ....................... 29
Einstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Das grundlegende Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
S auberen Code schreiben- eine Kunst? . . . . . . . . . . . . . . . . . . . . . . . . 31
Was ist sauberer Code? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1 .4 Denkschulen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
I.5 Wir sind Autoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.6 Die Pfadf inder-Regel . . . . . . . . . . . . . . . . . ....................... 43
1 .7 Vorläufer und Prinzipien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1 .8 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

2 Aussagekräftige Namen ........... . . . . . . . . . . . . . . . . . . . . . . . . . . 45


2.1 Einführung. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.2 Zweckbeschreibende Namen wählen . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3 Fehlinformationen vermeiden . . . . . . .......................... 47
2 -4 Unterschiede deutlich machen. . . . . . .......................... 49
2 .5 Aussprechbare Namen verwenden . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.6 Suchbare Namen verwenden . . . . . . . .......................... 51
2 .7 Codierungen vermeiden . . . . . . . . . . . .......................... 52
Ungarische Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Member-Präfi xe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Interfaces und Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.8 M entale M appings vermeiden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2 .9 Klassennamen . . . . . . . . . . . . . . . . . . . .......................... 55
2.10 Methodennamen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

5
I n h a ltsverzeich n i s

2 .II Vermeiden Sie humorige Namen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55


2.12 Wählen Sie ein Wort pro Konzept . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.13 Keine Wortspiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2 .J4 Namen der Lösungsdomäne verwenden . . . . . . . . . . . . . . . . . . . . . . . 57
2 . 15 Namen der Problemdomäne verwenden . . . . . . . . . . . . . . . . . . . . . . . 57
2.16 Bedeutungsvollen Kontext hinzufügen . . . . . . . . . . . . . . . . . . . . . . . . 57
2 . 17 Keinen überflüssigen Kontext hinzufügen . . . . . . . . . . . . . . . . . . . . . 60
2.18 Abschließende Worte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

3 Funktionen .............................................. . 61
3-1 Klein! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Blöcke und Einrückungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Eine Aufgabe erfüllen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Abschnitte innerhalb von Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . 66
3 ·3 Eine Abstraktionsebene pro Funktion . . . . . . . . . . . . . . . . . . . . . . . . . 67
Code Top-down lesen: die Stepdown-Regel . . . . . . . . . . . . . . . . . . . . . 67
3 -4 Switch-Anweisungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
3 ·5 Beschreibende Namen verwenden . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3·6 Funktionsargumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Gebräuchliche monadische Formen . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Flag-Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Dyadische Funktionen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Triaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .................... 73
Argument-Objekte . . . . . . . . . . . . . . . . . . . . . .................... 74
Argument-Listen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Verben und Schlüsselwörter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3 ·7 Nebeneffekte vermeiden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Output-Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3·8 Anweisung und Abfrage trennen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3 ·9 Ausnahmen sind besser als Fehler-Codes . . . . . . . . . . . . . . . . . . . . . . 77
TryJ Catch-Blöck e extrahieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Fehler-Verarbeitung ist eine Aufgabe . . . . . . . . . . . . . . . . . . . . . . . . . 79
Der Abhängigkeitsmagnet Error.java . . . . . . . . . . . . . . . . . . . . . . . . . 79
3 · 10 Don't Repeat Yourself . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3 · II Strukturierte Programmierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.12 Wie schreibt man solche Funktionen? . . . . . . . . . . . . . . . . . . . . . . . . . 81
3-13 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3 - 14 SetupTeardownl ncluder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

6
I n h a ltsverzeich n i s

4 Kommentare ................................. . . . . . . . . . . . . . 8S
4-1 Kommentare sind kein Ersatz für schlechten Code . . . . . . . . . . . . . . . 86
4-2 Erklären Sie im und durch den Code . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4-3 Gute Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ............. 87
Juristische Kommentare . . . . . . . . . . . . . . . . . . . . . . . . ............. 87
Informierende Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Erklärung der Absicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Klarstellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Warnungen vor Konsequenzen . . . . . . . . . . . . . . . . . . ............. 90
TODO-Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . ............. 91
Verstärkung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
J avadocs in öffentlichen APi s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4-4 Schlechte Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
C eraune . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ............. 92
Redundante Kommentare . . . . . . . . . . . . . . . . . . . . . . . ............. 93
Irreführende Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9S
Vorgeschriebene Kommentare . . . . . . . . . . . . . . . . . . . ............. 96
Tagebuch-Kommentare. . . . . . . . . . . . . . . . . . . . . . . . . ............. 96
Geschwätz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Beängstigendes Geschwätz . . . . . . . . . . . . . . . . . . . . . . ............. 99
Verwenden Sie keinen Kommentar, wenn Sie
eine Funktion oder eine Variable verwenden können . . . . . . . . . . . . . 1 00
Positions bezeichner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 00
Kommentare hinter schließenden Klammern . . . . . . . . . . . . . . . . . . . 1 01
Zuschreibungen und Nebenbemerkungen . . . . . . . . . . . . . . . . . . . . . . 1 01
Auskommentierter Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 02
HTM L-Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 02
Nicht-lokale Informationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 03
Zu viele Informationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 04
Unklarer Zusammenhang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 04
Funktions-Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 04
J avadocs in nicht -öffentlichem Code . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 OS
Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 OS

5 Formatierung. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 09
5.1 Der Zweck der Formatierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 09
5.2 Vertikale Formatierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Die Zeitungs-Metapher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Vertikale Offenheit zwischen Konzepten . . . . . . . . . . . . . . . . . . . . . . . 112

7
I n h a ltsverzeich n i s

Vertik ale Dich te . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113


Vertik aler Abstand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Vertik ale Anordnung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
5·3 Horizontale Formatierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Horizontale Offenh eit und Dich te . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Horizontale Ausrich tung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Einrück ung . . . . . . . . . . . . . . . . . . . ............................ 123
Dummy-Bereich e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
5 ·4 Team-Regeln . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
5 ·5 Uncle Bobs Formatierungsregeln . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

6 Objekte und Datenstrukturen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129


6.r Datenabstrak tion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
6.2 DatenjObj ekt-Anti-Symmetrie ............................... 131
6.3 Das Law of Demeter . . . . . . . . ............................... 133
Z ugk atastroph e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Hybride . . . . . . . . . . . . . . . . . . . ............................... 135
Struk tur verbergen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
6 -4 Datentransfer-Obj ek te . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Active Record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
6 .5 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

7 Fehler-Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
7. 1 Ausnah men statt Rück gabe-Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
7.2 Try-Catch - Finally-Anweisungen zuerst sch reiben . . . . . . . . . . . . . . . 141
7·3 Unch eck ed Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
7·4 Ausnah men mit Kontext auslösen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
7·5 Defi nieren Sie Exception-Klassen mit Blick auf die
Anforderungen des Aufrufers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
7. 6 Den normalen Ablauf defi nieren . . . . . . . . . . . . . . . .............. 146
7·7 Keine Null zurück geben . . . . . . . . . . . . . . . . . . . . . . .............. 147
7.8 Keine Null übergeben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
7· 9 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

8 Grenzen .......................... . . . . . . . . . . . . . . . . . . . . . . . 151


8.1 Mit Drittanbieter-Code arbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
8.2 Grenzen erforsch en und k ennen lernen . . . . . . . . . . . . . . . . . . . . . . . 154
8.3 log4j k ennen lernen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
8 .4 Lern-Tests sind besser als kostenlos . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

8
I n h a ltsverzeich n i s

8.5 Code verwenden, der noch nicht existiert . . . . . . . . . . . . . . . . . . . . . . . 1 57


8.6 S aubere Grenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 58

9 Unit-Tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 59
9.1 Die drei Gesetze der TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 60
9 .2 Tests sauber h alten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 61
Tests ermöglich en die -h eiten und -k eiten . . . . . . . . . . . . . . . . . . . . . . 1 62
9 ·3 S aubere Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 63
Domänenspezifi sch e Testsprach e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 66
Ein Doppelstandard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 66
9 ·4 Ein assert pro Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 68
Ein Konzept pro Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 70
9 ·5 F .I . R. S .T. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 71
9. 6 Z usammenfassung......................................... 1 72

10 Klassen ....................................... . . . . . . . . . . . . 1 73
10.1 Klassenaufb au . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 73
Eink apselung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 74
10.2 Klassen sollten klein sein! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 74
Fünf Meth oden sind nich t zu viel, oder? . . . . . . . . . . . . . . . . . . . . . . . . 1 76
Das Single-Responsibility-P rinzip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 76
Koh äsion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 78
Koh äsion zu erh alten, füh rt zu vielen kleinen Klassen . . . . . . . . . . . . 1 79
10.3 Änderungen einplanen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 85
Änderungen isolieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 88

11 Systeme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 91
11.1 Wie baut man eine Stadt? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 91
11.2 Konstruktion und Anwendung eines Systems trennen . . . . . . . . . . . . 1 92
Trennung in main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 93
Facta ries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 94
Dependency I nj ection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 95
11.3 Aufwärtssk alierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 96
Cross-Cutting Concerns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 99
11.4 Java-P roxies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
11.5 Reine Java-AOP -Framework s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
11.6 AspectJ -Aspekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
11.7 Die Systemarch itek tur testen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
11.8 Die Entsch eidungst indung optimieren . . . . . . . . . . . . . . . . . . . . . . . . . 207

9
I n h a ltsverzeich n i s

rr. 9 Standards weise anwenden, wenn sie nachweisbar


einen Meh rwert bieten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
rr.ro Systeme brauch en domänenspezifi sch e Sprach en . . . . . . . . . . . . . . . 208
II.II Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208

rz Emergenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
rz. r Saubere Software durch emergentes Design . . .................. 209
r2.2 Einfach e Design-Regel r : Alle Tests besteh en . . . . . . . . . . . . . . . . . . . 210
r2.3 Einfach e Design-Regeln 2-4: Refactoring . . . . .................. 211
r2.4 Keine Duplizierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
r2.5 Ausdruck sstärke. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
rz. 6 Minimale Klassen und Meth oden . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
r2.7 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

I3 Nebenläufigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
rp Warum Nebenläufi gk eit? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
Myth en und falsch e Vorstellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
r3.2 Herausforderungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
r3.3 P rinzipien einer defensiven Nebenläufi gk eitsprogrammierung . ... 221
Single-Responsibility-P rinzip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Korollar: Besch ränk en Sie den Gültigk eitsbereich
von Daten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Korollar: Arbeiten Sie mit Kopien der Daten. . . . . . . . . . . . . . . . . . . . 222
Korollar: Th reads sollten voneinander so unabh ängig
wie möglich sein . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
r3.4 Lernen Sie Ih re Library k ennen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Th read-sich ere Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
r3.5 Lernen Sie Ih re Ausfüh rungsmodelle k ennen . . . . . . . . . . . . . . . . . . 224
Erzeuger-Verbrauch er . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Leser- Sch reiber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Ph ilosoph enproblem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
r3.6 Ach ten Sie auf Abh ängigk eiten zwisch en
synch ronisierten Meth oden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
r3.7 Halten Sie synch ronisierte Absch nitte klein . . . . . . . . . . . . . . . . . . . . 226
r3.8 Korrekten Shutdown-Code zu sch reiben, ist schwer . . . . . . . . . . . . . 227
r3.9 Th readed-Code testen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Beh andeln Sie gelegentlich auftretende Feh ler als
potenzielle Th reading-P robleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Bringen Sie erst den Nonth readed-Code zum Laufen . . . . . . . . . . . . 228

10
I n h a ltsverzeich n i s

Mach en Sie Ih ren Th readed-Code pluggable . . . . . . . . . . . . . . . . . . . . 229


Sch reiben Sie anpassbaren Th readed-Code . . . . . . . . . . . . . . . . . . . . . 229
Den Code mit meh r Th reads als P rozessoren ausfüh ren . . . . . . . . . . 229
Den Code auf versch iedenen P lattformen ausfüh ren . . . . . . . . . . . . . 229
Code- Sch eitern durch I nstrumentierung provozieren . . . . . . . . . . . . . 230
Manuelle Codierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Automatisiert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
I3 . IO Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

I4 Schrittweise Verfeinerung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235


I4-I Args-I mplementierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Wie h abe ich dies gemacht? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
I4-2 Args: der Roh entwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Desh alb h örte ich auf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Über ink rementeH e Entwick lung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
I4-3 String-Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
I4-4 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300

15 JUnit im Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301


15 . 1 D a s J Unit-Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
I5.2 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 6

16 Refactoring von SerialDate .... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 7


16.1 Z unäch st bring es zum Laufen! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 8
I6 .2 Dann mach es rich tig! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
1 6 .3 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336

17 Smells und Heuristiken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337


I7. I Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
CI: Ungeeignete I nformationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
C2: Überh olte Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
C} Redundante Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
C+ Sch lech t gesch riebene Kommentare . . . . . . . . . . . . . . . . . . . . . . . . 338
Cs : Ausk ommentierter Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
I7.2 Umgebung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
E I: Ein Build erfordert meh r als einen Sch ritt . . . . . . . . . . . . . . . . . . . 339
E2: Tests erfordern meh r als einen Sch ritt . . . . . . . . . . . . . . . . . . . . . . 339
I7 ·3 Funktionen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
F I: Z u viele Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
F2: Output-Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340

11
I n h a ltsverzeich n i s

F3: Plag-Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340


F4: Tote Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
17.4 Allgemein . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
Gr: Meh rere Sprach en in einer Q uelldatei . . . . . . . . . . . . . . . . . . . . . 340
G2: Offensich tlich es Verh alten ist nich t implementiert. . . . . . . . . . . 341
G3: Falsch es Verh alten an den Grenzen . . . . . . . . . . . . . . . . . . ..... 341
G4 : übergangene Sich erungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
Gs : Duplizierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
G 6 : Auf der falsch en Abstraktionsebene codieren . . . . . . . . . . . . . . . 342
GT Basisld asse h ängt von abgeleiteten Klassen ab . . . . . . . . . . . . . . . 344
G8: Z u viele I nformationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
G 9 : Toter Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 345
Gro: Vertik ale Trennung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 345
Gn : I nk onsistenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 345
Gr2: Müll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
G13: Künstlich e Kopplung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 346
GI+ Funktionsneid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
C rs : Selektor-Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Gr6: Verdeckte Absich t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 348
GrT Falsch e Z uständigk eit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 349
Gr8: Fälsch lich als statisch deklarierte Meth oden . . . . . . . . . . . . . . . 350
G1 9 : Aussagek räft ige Variablen verwenden . . . . . . . . . . . . . . . . . . . . 350
G2o: Funktionsname sollte die Aktion ausdrück en . . . . . . . . . . . . . . 351
G21: Den Algorith mus versteh en . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
G22: Logisch e Abh ängigk eiten in physisch e umwandeln . . . . . . . . . 352
G23: P olymorph ismus statt I f/Else oder Switchj Case
verwenden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
G24: Konventionen beach ten . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 354
G25 : Magisch e Z ah len durch benannte Konstanten ersetzen . ..... 354
G26: P räzise sein . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... 355
G2T Struk tur ist wich tiger als Konvention . . . . . . . . . . . . . . . . . . . . . 356
G28: Bedingungen eink apseln . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
G2 9 : N egative Bedingungen vermeiden . . . . . . . . . . . . . . . . . . . . . . . 356
G3o: Eine Aufgabe pro Funk tion! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
G31: Verborgene zeitlich e Kopplungen . . . . . . . . . . . . . . . . . . . ..... 357
G32: Keine Willkür . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
G33: Grenzbedingungen eink apseln . . . . . . . . . . . . . . . . . . . . . . . . . . 359
G34: I n Funktionen nur eine Abstrak tionsebene tiefer geh en . . . . . 359

12
I n h a ltsverzeich n i s

G35 : Konfi gurierbare Daten h och ansiedeln . . . . . . . . . . . . . . . . . . . . . 361


G3 6 : Transitive Navigation vermeiden . . . . . . . . . . . . . . . . . . . . . . . . . 362
17.5 Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Jl : Lange I mportlisten durch Platzh alter vermeiden . . . . . . . . . . . . . . 362
J2: Keine Konstanten vererben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
J3: Konstanten im Gegensatz zu Enums . . . . . . . . . . . . . . . . . . . . . . . . 364
17.6 Namen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
Nr: Deskriptive Namen wählen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
N2: Namen sollten der Abstraktionsebene entsprech en . . . . . . . . . . . 367
N3: Möglich st die Standardnomenklatur verwenden . . . . . . . . . . . . . . 368
N+ Eindeutige Namen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Ns : Lange Namen fü r große Geltungsbereich e . . . . . . . . . . . . . . . . . . 369
N 6 : Codierungen vermeiden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
NT Namen sollten Nebeneff ekte besch reiben . . . . . . . . . . . . . . . . . . . 370
17.7 Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
TI: Unzureich ende Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
T2 : Ein Coverage-Tool verwenden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
T3 : Triviale Tests nich t überspringen . . . . . . . . . . . . . . . . . . . . . . . . . . 370
T4 : Ein ignorierter Test zeigt eine Meh rdeutigk eit auf . . . . . . . . . . . . 371
Ts : Grenzbedingungen testen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
T6: Bei Bugs die Nach barsch aft gründlich testen . . . . . . . . . . . . . . . . . 371
TT Das Muster des Sch eiterns zur Diagnose nutzen . . . . . . . . . . . . . . 371
T8 : Hinweise durch Coverage-P atterns . . . . . . . . . . . . . . . . . . . . . . . . . 371
T 9 : Tests sollten sch nell sein . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
17.8 Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372

A Nebenläufigkeit II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
A.r ClientJ Server- Beispiel . . . . . . . . . .............................. 373
Der Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
Threading h inzufü gen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
Server- Beobach tungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
A.2 Möglich e Ausfüh rungspfade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Anzah l der P fade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Tiefer graben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
Z usammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
A.3 Lernen Sie Ih re Library k ennen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
Executor Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
I n h a ltsverzeich n i s

Nich t block ierende Lösungen . . . . . . . . . . . . . . .................. 384


Nich t th read-sich ere Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
A.4 Abh ängigk eiten zwisch en Meth oden k önnen
nebenläufi gen Code besch ädigen . . . . . . . . . . . .................. 387
Das Sch eitern tolerieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
Clientbasiertes Lock ing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
S erverbasiertes Lock ing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
A.s Den Durch satz verbessern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
Single-Th read-Berech nung des Durch satzes . . .................. 392
Multith read-Berech nung des Durch satzes . . . . . . . . . . . . . . . . . . . . . 393
A.6 Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Gegenseitiger Aussch luss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Sperren & warten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 5
Keine präemptive Aktion. . . . . . . . . . . . . . . . . . .................. 395
Zirk uläres Warten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Den gegenseitigen Ausschluss aufh eben . . . . . . . . . . . . . . . . . . . . . . 396
Das Sperren & Warten aufh eben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
Die P räemption umgeh en . . . . . . . . . . . . . . . . . .................. 397
Das zirk uläre Warten umgeh en . . . . . . . . . . . . .................. 397
A.7 Multith readed-Code testen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
A.8 Th readbasierten Code mit Tools testen . . . . . . . . . . . . . . . . . . . . . . . 401
A. 9 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . .................. 402
A.Io Tutorial: k ompletter Beispielcode . . . . . . . . . . . .................. 402
Clientj Server oh ne Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
Clientj Server mit Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406

B org.jfree.date.SerialDate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407

C Literaturverweise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463

Epilog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465

Stichwortverzeichnis. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467

14
Vorwort

Bei uns in Dänemark zäh lt Ga- J ol zu den beliebtesten Süßigk eiten. Sein stark er Lak­
ritzduft ist ein perfek tes Mittel gegen unser feuch tes und oft k üh les Wetter. Der
Ch arme, den Ga-Jol für uns Dänen entfaltet, liegt auch an den weisen oder geist­
reich en Sprüch en, die auf dem Deck el j eder P ackung abgedruckt sind. I ch h abe mir
h eute Morgen eine Doppelpack ung dieser Köstlichk eit gek auft und fand darauf das
folgende alte dänisch e Sprich wort:
JErlighed i sma ting er ikke nagen lille ting.
Ehrlichkeit in kleinen Dingen ist kein kleines Ding. Dies war ein gutes Omen. Es passte
zu dem, was ich h ier sagen wollte. Kleine Dinge spielen eine Rolle. I n diesem Buch
geh t es um besch eidene Belange, deren Wert dennoch beträch tlich ist.
Gott steckt in den Details, sagte der Arch itekt Ludwig Mies van der Roh e. Dieses Zitat
erinnert an zeitgenössisch e Auseinandersetzungen über die Rolle der Arch itek tur
bei der Software-Entwicklung und insbesondere in der Agilen Welt. Bob und ich
füh ren gelegentlich h eiße Disk ussionen über dieses Th ema. Und ja, Mies van der
Roh e war seh r an der Nützlichk eit und der Z eitlosigk eit der Formen des Bauens
interessiert, auf denen großartige Arch itek tur basiert. Andererseits wäh lte er auch
persönlich j eden Türk nopffür j edes Haus aus, das er entworfen h atte. Wa rum? Weil
k leine Aufg aben eine Rolle spielen.
Bei unserer laufenden » Debatte« über T D D h aben Bob und ich festgestellt, dass wir
beide der Auffassung sind, dass die Software-Arch itektur eine wich tige Rolle bei der
Entwicklung spielt, obwoh l wir wah rsch einlich versch iedene Vorstellungen davon
h aben, was gerr au das bedeutet. Doch solch e Diff erenzen sind relativ unwich tig,
weil wir davon ausgeh en k önnen, dass verantwortungsbewusste P rofis am Anfang
eines P roj ekts eine gewisse Z eit über seinen Ablauf und seine Planung nach denk en.
Die Vorstellungen der späten 1 9 9 oer-Jah re, dass Design nur durch Tests und den
Code vorangetrieben werden k önnte, sind längst passe . Doch die Aufmerk samk eit
im Detail ist ein noch wesentlich erer Aspekt der P rofessionalität als Visionen im
Großen. Erstens: Es ist die Übung im Kleinen, mit der P rofis ih r Können und ih r
Selbstvertrauen entwick eln, sich an Größeres h eranzuwagen. Zweitens: Die
k leinste Nach lässigk eit bei der Konstruktion, die Tür, die nich t rich tig sch ließt, die
missratene Kach el auf dem Fußboden oder sogar ein unordentlich er Sch reibtisch
k önnen den Ch arme des größeren Ganzen mit einem Sch lag ruinieren. Darum
geh t es bei sauberem Code.
Vorwo rt

Dennoch bleibt die Arch itek tur nur eine Metaph er für die Software-Entwicklung
und insbesondere die Ph ase der Software, in der das anfänglich e P rodukt etwa in
derselben Weise entsteh t, wie ein Arch itek t ein neues Gebäude h ervorbringt. I n der
h eutigen Z eit von Serum und Agile geh t es h auptsächlich darum, ein P roduk t
sch nell auf den Markt z u bringen. Die Fabrik soll mit h öch ster Kapazität Software
produzieren. Nur: Hier geh t es um menschlich e Fabrik en, denk ende und füh rende
P rogrammierer, die eine Aufg abenliste abarbeiten oder sich bemüh en, anh and von
Benutzer- Stories ein brauchbares P roduk t zu erstellen. Ein solch es Denk en wird
von der Metaph er der Fabrik dominiert. Die P roduk tionsaspekte der Herstellung
von Autos in Japan, also einer von Fließbändern dominierten Welt, h aben viele
I deen von Serum inspiriert.
Doch selbst in der Automobilindustrie wird der Hauptteil der Arbeit nich t bei der
P roduktion, sondern bei der Wartung geleistet- oder bei dem Bemüh en, sie zu ver­
meiden. Bei der Software werden die 8o oder meh r P rozent unserer Tätigk eit anh ei­
melnd als »Wartung« bezeich net, ein besch önigendes Wort f ür »Reparatur«. Statt
uns also auf typisch e westlich e Weise auf die Produktion guter Software zu k onzen­
trieren, sollten wir anfangen, eh er wie ein Hausmeister bei der Gebäudeinstand­
h altung oder wie ein Kfz -Mech anik er bei der Reparatur von Autos zu denk en. Was
h aben j apanisch e Managementweish eiten dazu zu sagen?
Etwa 1 95 1 ersch ien ein Q ualitätsansatz namens Total P roductive Maintenance
(TP M ; »Umfassendes Management des P roduktionsprozesses«, der Ausdruck wird
nicht ins Deutsch e übersetzt) in der j apanisch en Szene. Er k onzentrierte sich weni­
ger auf die P roduktion, sondern meh r auf die Wartung. Eine der fünf Säulen des
TP M ist der Satz der so genannten 5 S -P rinzipien. 5 S bezieh t sich auf einen Satz von
Disziplinen oder Tätigk eitsbereich en. Tatsächlich verk örpern diese 5 S -P rinzipien
die Bedeutung von Lean - einem anderen Modewort in westlich en P roduk tions­
k reisen, das zuneh mend auch in der Software-Entwicklung verwendet wird. Diese
P rinzipien sind nich t optional. Wie Uncle Bob auf der Titelseite sagt, erfordert die
Software-P raxis eine gewisse Disziplin: Fokus, Aufmerk samk eit und Denk en. Es
geh t nich t immer nur darum, ak tiv zu sein und die Fabrik ausrüstung mit der opti­
malen Geschwindigk eit ZU betreiben. Die s S -Ph ilosoph ie umfasst die folgenden
Konzepte:
• Seiri oder Organisation (Eselsbrück e: »sortieren«) . Zu wissen, wo sich Dinge
befinden, ist erfolgsentsch eidend. Dazu zählen zum B eispiel Ansätze wie das
Vergeben geeigneter Namen. Wenn Sie meinen, die B enennung Ih rer B ezeich ­
ner sei nich t wich tig, sollten Sie aufj eden Fall die folgenden Kapitel lesen.
• Seiton oder Ordentlichk eit (Eselsbrück e : »aufräumen«) . Ein altes Sprichwort
sagt: Ein Platz für alles, und alles an seinem Platz. Ein Code-Ab sch nitt sollte da
steh en, wo Sie ih n zu finden erwarten; und falls er nich t da steh t, sollten Sie ein
Refactoring von Ih rem Code vorneh men, so dass er danach an der erwarteten
Stelle steh t.
• Seiso oder Sauberk eit (Eselsbrücke: »wienern«) . Sorgen Sie dafür, dass der Ar­
beitsplatz frei von h erumh ängenden Dräh ten, Müllspuren, Einzelteilen und
Abfall ist. Was sagen die Autoren h ier über die Vermüllung Ih res Codes mit
Kommentaren und ausk ommentierten Codezeilen, die den Verlaufi der Ent­
wicklung oder Wünsch e für die Zukunft wiedergeben? Weg damit.
• Seiketsu oder Standardisierung. Die k ommt zu einem Konsens darüber, wie der
Arbeitsplatz sauber geh alten werden soll. Hat dieses Buch etwas über einen
k onsistenten Codierstil und gemeinsam in der Gruppe befolgte P raktik en zu
sagen? Wo k ommen diese Standards h er? Lesen Sie weiter.
• Shutsuke oder Disziplin ( Selbst disziplin) . Dies bedeutet, die Disziplin aufz u­
-

bringen, den P raktik en zu folgen, seine Arbeit regelmäßig zu überdenk en und


bereit zu sein, sich zu ändern.
Wenn Sie die Herausforderung- j awohl, die Herausforderung- anneh men, dieses
Buch zu lesen und anzuwenden, werden Sie den letzten Punkt versteh en und sch ät­
zen lernen. Hier k ommen wir sch ließlich zu den Wurzeln einer verantwortlich en
professionellen Einstellung in einem Beruf, der sich um den Lebenszyklus eines
P roduktes kümmern sollte. So wie Automobile und andere Masch inen unter TP M
vorbeugend gewartet werden, sollte eine Wartung im Falle eines Zusammenbruch s
- also darauf zu warten, dass die Bugs sich zeigen- die Ausnah me sein. Stattdessen
sollten Sie eine Ebene h öh er ansetzen: I nspizieren Sie die Masch inen j eden Tag und
tausch en Sie Versch leißteile aus, bevor sie k aputtgeh en, oder lassen Sie den sprich­
wörtlich en Ölwech sel vorneh men, um die Abnutzung des Motors möglich st zu ver­
ringern. Für Ih ren Code bedeutet das : Neh men Sie ein gnadenloses Refa ctoring vor.
Sie k önnen mit der Verbesserung noch eine Ebene h öh er ansetzen, wie es die TP M ­
Bewegung innovativ vor über 50 Jah ren vorgemach t h at: Bauen Sie Masch inen, die
von vornh erein wartungsfreundlich er sind. Code lesbar zu mach en, ist genauso
wich tig, wie ih n ausfüh rbar zu mach en. Die ultimative P raxis, die in TP M-Kreisen
etwa 1 9 6 0 eingefüh rt wurde, besteht darin, die alten Masch inen vorbeugend durch
vollk ommen neue zu ersetzen. Wie Fred Brook s anmah nt, sollten wir wah rsch ein­
lich Hauptteile unserer Software etwa alle sieben Jah re von Grund auf erneuern, um
die schleich ende Ansammlung von Cruft (Jargon: Müll, Staub, Unrat) zu beseitigen.
V:ielleich t sollten wir die von Brook s genannte Z eitspanne drastisch reduzieren und
nich t von Jah ren, sondern von Woch en, Tagen oder gar Stunden sprech en. Denn
dort fi nden sich die Details.
Details h aben eine mäch tige Wirkungsk raft. Dennoch h at dieser Ansatz etwas
Besch eidenes und Grundsätzlich es, so wie wir es vielleich t stereotyp von einem
Ansatz erwarten, der j apanisch e Wurzeln für sich in Anspruch nimmt. Aber dies ist
nich t nur eine k östlich e Art, das Leben zu seh en. Auch die westlich e Volk sweish eit
enth ält zah lreich e äh nlich e Sprichwörter. Das Seiton-Z itat von oben floss auch aus
der Feder eines P riesters in Ohio, der Ordentlichk eit buch stäblich »als Gegenmittel
für j ede Art von Bösem« sah . Was ist mit Seiso? Sauberkeit kommt gleich nach Gött-

17
Vorwo rt

lichkeit. So sch ön ein Haus auch sein mag, ein unordentlich er Tisch raubt ih m sei­
nen ganzen Glanz. Was bedeutet Sh utsuk e in diesen kleinen Dingen? Wer an wenig
glaubt, glaubt an viel. Wie wär's damit, das Refactoring des Codes rech tzeitig durch ­
zufüh ren, um seine Position fü r folgende »große« Entsch eidungen zu stärk en, als
die Aufg abe aufzusch ieben? Ein Stich zur rechten Zeit ersP.art dir neun weitere. Wer
früh kommt, mahlt zuerst. Was du heute kannst besorgen, das verschiebe nicht auf mor­
gen. (Dies war die ursprünglich e Bedeutung des Ausdruck s »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, einfach e
vorbeugende Arbeiten in den Alltag einzubauen? Vorsicht ist besser als Nachsicht. Ein
Apfel am Tag hält den Doktorfern. Sauberer Code anerk ennt die verwurzelte Weish eit
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 sch uldige Aufmerk samk eit
sch enkt.
Selbst in der Literatur über große Arch itektur greifen Autoren auf Sprichwörter
über die Bedeutung von Details zurück . Denk en Sie an die Türgriffe von Mies van
der Roh e. Das ist Seiri. Das bedeutet, sich um j eden Variablennamen zu k ümmern.
Sie sollten Variablennamen mit derselben Sorgfalt auswäh len wie den Namen eines
erstgeborenen Kindes.
Jeder Hausbesitzer weiß, dass eine solch e P flege und fortwäh rende Verbesserung
niemals zu Ende ist. Der Arch itekt Ch ristoph er Alexander- Vater der Patterns und
P attern- Sprach en - betrach tetj eden Design -Ak t selbst als einen kleinen, lok alen Ak t
der Reparatur. Und er betrach tet die Anwendung des Könnens auffeine Strukturen
als den einzigen legitimen Arbeitsbereich des Arch itekten; die größeren Formen
k önnen den Patterns und deren Anwendung durch die Bewoh ner überlassen wer­
den. Design geh t immer weiter. Es betrifft nich t nur den Anbau neuer Räumlich ­
k eiten, sondern auch profanere Aufg aben wie ein neuer Anstrich , das Ersetzen
eines abgelaufenen Teppich s oder die Modernisierung der Spüle in der Küch e . I n
den meisten Künsten werden äh nlich e Überzeugungen vertreten. Bei unserer
Such e nach anderen, die das Haus Gottes in den Details seh en, stießen wir bei­
spielsweise aufden französisch en Autor Gustav Flaubert aus dem 1 9 . Jah rh undert.
Der französisch e Dich ter Paul Valery sagt uns, ein Gedich t wäre niemals fertig und
müsse laufend überarbeitet werden; mit dieser Arbeit aufz uh ören wäre vergleich ­
bar damit, dieses Gedich t zu verwerfen. Eine solch e Besessenh eit von Details ist
allen Bemüh ungen gemeinsam, die auf Exzellenz, also aufh erausragende Leistun­
gen gerich tet sind. Also: Vielleich t gibt es h ier wenig Neues, aber wenn Sie dieses
Buch lesen, werden Sie h erausgefordert, die guten Disziplinen wieder aufzuneh ­
men, die Sie vor langer Z eit aus Apath ie, dem Wunsch nach Spontanität oder ein­
fach deswegen aufg egeben h aben, weil Sie »etwas anderes« mach en wollten.
Leider betrach ten wir solch e Überlegungen normalerweise nich t als Grundbau­
steine der Kunst der P rogrammierung. Wir entlassen unseren Code früh aus unse-
rer Obh ut, nicht, weil er fertig ist, sondern weil unser Wertesystem meh r auf die
äußere Ersch einung als auf die Substanz des gelieferten P roduk ts gerich tet ist.
Diese fehlende Aufmerk samk eit k ommt uns letztendlich teuer zu steh en: I rgend­
wann mach en sich die Defek te immer bemerkbar. Weder in ak ademisch en Kreisen
noch in der I ndustrie begibt sich die Forsch ung in die niedrigen Ebenen h inunter,
Code sauber zu h alten. Früh er, als ich noch bei der Bell Labs Software P roduction
Research Organization (also wirklich P roduktion!) besch äftigt war, mach ten wir die
beiläufige Entdeck ung, dass ein k onsistenter Stil beim Einrück en von Klammern
der statistisch signifik anteste I ndik ator für eine geringe Feh lerh äufigk eit war. Wir
wollen, dass die Arch itektur, die P rogrammiersprach e oder irgendein anderes h och
angesiedeltes Konzept die Ursach e für Q ualität sein soll. Als Entwiclder, deren vor­
geblich e P rofessionalität auf der Meisterung von Werk zeugen und abgeh obenen
Design-Meth oden basiert, fühlen wir uns von dem Meh rwert beleidigt, den diese
Masch inen aus der Fabrikh alle, pardon! , Codierer, erzielen, indem sie einfach einen
bestimmten Stil der Einrück ung von Klammern k onsistent anwenden. Um mein
eigenes Buch zu zitieren, das ich vor r7 Jah ren gesch rieben h abe: Ein solch er Stil
untersch eidet Exzellenz von bloßer Kompetenz. Die j apanisch e Weltsich t versteh t
den entsch eidenden Beitrag j edes gewöh nlich en Arbeiters und meh r noch , wie Ent­
wicklungssysteme von den einfach en gewöh nlich en Ak tionen dieser Arbeiter
abh ängen. Q ualität ist das Ergebnis eine Million selbstloser Akte der Sorgfalt- nich t
nur das einer großartigen Meth ode, die vom Himmel gefallen ist. Dass diese Ak te
einfach sind, bedeutet nicht, dass sie simplizistisch (einfältig) sind. Es bedeutet
auch nich t, dass sie leich t sind. Dennoch sind sie der Stoff, aus dem die Größe und
meh r noch die Sch önh eit menschlich er Anstrengungen gemach t ist. Wer diese
Ak te ignoriert, h at noch nich t sein volles menschlich es P otenzial realisiert.
Natürlich befü rworte ich immer noch , auch den größeren Rah men zu betrach ten
und besonders den Wert von arch itektonisch en Ansätzen zu berück sich tigen, die in
einem tiefen Wissen sowoh l des P roblembereich es als auch der Software-Usability
verwurzelt sind. Doch darum geh t es in diesem Buch nich t - zumindest nich t vor­
dergründig. Dieses Buch will eine subtilere Botsch aft verbreiten, deren Gewich tig­
k eit nich t untersch ätzt werden sollte. Sie passt zu dem gegenwärtigen Credo
wirklich codebasierter Entwickler wie Peter Sommerlad, Kevlin Henney und Gio­
vanni Asproni. Ih re Mantras lauten: »Der Code ist das Design« und »Einfach er
Code«. Wäh rend wir darauf ach ten müssen, dass die Sch nittstelle das P rogramm ist
und dass ih re Struk tur viel über die Struk tur unseres P rogrammes aussagt, ist es
von erfolgsentsch eidender Bedeutung, dass wir uns laufend mit der besch eidenen
Einstellung identifizieren, dass das Design tatsächlich nur im Code existiert. Und
wäh rend eine Überarbeitung in der Metaph er der fabrik mäßigen P roduk tion zu
h öh eren Kosten füh rt, füh rt sie beim Design zu einem Mehrwert. Wir sollten unse­
ren Code als den wundersch önen Ausdruck edler Design-Anstrengungen betrach ­
ten- Design als P rozess, nich t als statisch er Endpunkt. Nur i m Code lassen sich
letztlich die arch itektonisch en Metrik en der Kopplung und Koh äsion nachweisen.
Wenn Larry Constantine Kopplung und Koh äsion besch reibt, sprich t er von Code
Vorwo rt

- nich t von abgeh obenen abstrakten Konzepten, die man vielleich t in UML findet.
Rich ard Gabriel rät uns in seinem E ssay Abstraction Descant, Abstraktion sei böse.
Code ist anti-böse, und sauberer Code ist vielleich t göttlich .
Zurück zu meiner kleinen Packung Ga- Jol: I ch glaube, dass es wich tig ist, anzumer­
k en, dass uns die dänisch e Weish eit nich t nur rät, unsere Aufmerk samk eit auf die
kleinen Aufgaben zu lenk en, sondern auch , bei kleinen Aufgaben eh rlich zu sein.
Dies bedeutet, wir müssen dem Code gegenüber eh rlich sein, wir müssen unseren
Kollegen gegenüber über den Zustand unseres Codes eh rlich sein und vor allem,
wir müssen uns selbst gegenüber über den Zustand unseres Codes eh rlich sein.
Haben wir unser Bestes gegeben, um den »Campingplatz sauberer zu h interlassen,
als wir ih n gefunden h aben«? Haben wir das Refactoring des Codes erledigt, bevor
wir ih n eingech eckt h aben? Dies sind k eine nebensäch lich en Belange, sondern
Belange, die zum Kern agiler Werte geh ören. Zum Beispiel empfieh lt Serum, das
Refactoring zu einem Bestandteil des Konzepts »Done« (»Fertig«) zu mach en.
Weder Arch itektur noch sauberer Code verlangt nach Perfektion, sondern nur nach
Ehrlichk eit und dem Bemüh en, unser Bestes zu geben. I rren ist mensch lich , ver­
geben göttlich . Bei Serum mach en wir alles sichtbar. Wir zeigen unsere sch mutzige
Wäsch e. Wir sind eh rlich über den Zustand unseres Codes, weil Code niemals per­
fekt ist. Wir werden mensch lich er, werden würdiger, das Göttlich e zu empfangen,
und näh ern uns der Größe in den Details.
In unserem Beruf brauch en wir verzweifelt alle Hilfe, die wir bek ommen k önnen.
Wenn ein sauberer Fabrikboden die Anzahl der Unfälle reduziert und woh lgeord­
nete Werk zeugkästen die P roduktivität verbessern, dann k ann man dies nur befür­
worten. Was dieses Buch angeht: Es ist die beste pragmatisch e Anwendung von
Lean-P rinzipien auf Software, die ich j e in Druck form geseh en h abe. Aber weniger
h atte ich von dieser praktisch en kleinen Gruppe denk ender I ndividuen auch nich t
erwartet, die sich nich t nur seit Jah ren darum bemüh en, immer besser z u werden,
sondern auch ih r Wissen an die Branch e weiterzugeben. Dieses Buch ist ein Aus­
druck dieses Bemüh ens. Es h interlässt die Welt ein wenig besser, als ich sie vorfand,
bevor Uncle Bob mir das Manusk ript sch ickte.
Doch genug von meinen abgeh obenen Einsich ten. I ch mus s meinen Sch reibtisch
aufräumen.
James 0 . Coplien

M0rdrup, Dänemark

20
Einführun g

Th e o rvLy VA c id M e ASY �t.e ne rvr­


oF ccde.. O G\ A l.- 'r r '{ : WTT s I1"1 i "' t.n-e.

,I
-

ßAo\ c o ol. e.. .


Good c ock_ .
Abb. 1 : Abdruck m it fre u n d l icher G e n eh m i g u n g von Thom H olwerd a
( h t t p : // www . o s n ews . com / s t o r y / 192 66 / WTFs_m)

Welche Tür repräsentiert I hren Code? Welche Tür repräsentiert I hr Team oder I hr
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 unse­
rer 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 Prin­
zipien, Patterns, Techniken und Heuristiken aneignen, die jeder Fachmann kennt,
und Sie müssen dieses Wissen in I hre Finger, I hre Augen und I hren Bauch einprä­
gen, indem Sie hart arbeiten und üben.
I ch kann I hnen die physikalischen Gesetzmäßigkeiten des Fahrradfahrens vermit­
teln. Tatsächlich ist die entsprechende klassische Mathematik relativ einfach.
Schwerkraft, Reibung, Drehmoment, Massenschwerpunkt usw. können auf weni­
ger als einer Seite mit Gleichungen demonstriert werden. Mit diesen Formel::
E i n fü h ru n g

könnte ich I hnen beweisen, dass Fahrradfahren praktisch ist, und I hnen 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 saube­
rem Code niederschreiben und dann daraufvertrauen, dass Sie die Arbeit erledigen.
(Anders ausgedrückt Wir könnten Sie einfach aufi die Nase fallen lassen: wenn Sie
das Fahrrad besteigen.) Doch was für eine Art von Lehrer wären wir dann, und wel­
che Art von Schüler \\·ürde dann aus I hnen 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 I hren Fehlern lernen. Sie müssen andere dabei beo­
bachten, wie sie es ausprobieren, welche Fehler sie machen. Sie müssen erkennen,
wo sie stolpern. und ihre Schritte nachvollziehen. Sie müssen sehen, welche Ent­
scheidungen ihnen besonders schwerfallen und welchen Preis sie bezahlen müs­
sen, wenn sie die falschen Entscheidungen treffen.
Sie sollten sich aufhane Arbeit einstellen, wenn Sie dieses Buch lesen. Dies ist kein
Buch, das I hnen »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 \·on _-\rbeit 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. S1e werden aufgefordert, uns dabei zu folgen, wie wir Module zer­
pflücken und v.ieder zusammensetzen. Dies braucht Z eit 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 S:e aufden 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 Pro­
bleme 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, analy­
sieren und verstehen und unsere Überlegungen für die durchgeführten Änderun­
gen nachvollziehen. Sie müssen dafür schon einige Z eit resen·ieren, denn Sie
werden dafür einige Tage benötigen.
I m dritten Teil des Buches erhalten Sie I hren Lohn. Er besteht aus einem einzigen
Kapitel mit einer Liste von Heuristiken und Smells, die während der Erstellung der

22
Vorwort

Fallstudien zusammengetragen wurden. Wäh rend wir den Code in den Fallstudien
analysierten und bereinigten, h aben wir alle Gründe für unsere Aktionen als Heu­
ristik oder Smell dokumentiert. Wir versuch ten, unsere eigenen Reaktionen auf den
Code zu versteh en, den wir gelesen und geändert h atten, und mühten uns wirklich
ab, h erauszufinden und festzuh alten, 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 besch reibt, wenn wir sauberen Code schreiben und lesen.
Diese Wissensbasis h at für Sie nur einen besch ränkten Wert, wenn Sie die Fallstu­
dien im zweiten Teil dieses Buch es nicht sorgfältig lesen und nachvollzieh en. I n die­
sen Fallstudien h aben wir sorgfältig alle durch geführten Änderungen mit
Referenzen aufi die Wissensbasis verseh en. Diese Referenzen werden wie folgt in
eckigen Klammern angegeben: [H22]. Dies ermöglicht es Ih nen, den Kontext zu
seh en, in dem diese Heuristiken angewendet und geschrieben wurden! Es sind
nicht die Heuristiken selbst, die so wertvoll sind, sondern die Bezieh ungen zwi­
sch en diesen Heuristiken und den einzelnen Entsch eidungen, die wir beim Berei­
nigen des Codes in den Fallstudien getroffen h aben.
Um Ih nen mit diesen Bezieh ungen noch weiterzuh elfen, h aben wir am Anfang des
I ndexes Querverweise aufidie Seitenzah len 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 h aben Sie nur ein weiteres unterh altsames Buch über das Schreiben von Soft­
ware gelesen. Doch wenn Sie sich die Zeit neh men, die Fallstudien durch zuarbeiten
und jedem winzigen Sch ritt und jeder kleinen Entsch eidung zu folgen- wenn Sie
sich also an unsere Stelle versetzt und sich gezwungen h aben, in denselben Bah nen
zu denken wie wir, dann werden Sie ein viel tieferes Verständnis dieser Prinzipien,
Patterns, Tech niken und Heuristiken gewonnen h aben. Diese werden dann nich t
mehr nur gewisse »ganz nützlich e« Techniken unter anderen sein, sondern werden
Ih nen in Fleisch und Blut übergegangen sein. Sie werden ein Teil von Ih nen gewor­
den sein, äh nlich wie ein Fahrrad eine Erweiterung Ih res Willens wird, wenn Sie das
Fah ren erlernt h aben.

D a n ksagu n ge n

G rafiken

Danke an meine beiden Künstlerinnen Jenniffer Koh nke und Angela Brooks. Jen­
nifer ist für die beeindruckenden und kreativen Bilder am Anfang i edes Kapitels
und die P orträts von Kent Beck, Ward Cunningh am. Bjarne Stroustrup, Ron Jeffries,
Grady Booch , Dave Th omas, Mich ael Feath ers und mir ...-erantwortlich .

23
Für Ann Marie: die Liebe meines Lebens.
Kapitel 1

Sau berer Code

Sie lesen das Buch aus zwei Gründen. Erstens: Sie sind P rogrammierer. Zweitens:
Sie wollen ein besserer P rogrammierer werden. Gut. Wir brauch en bessere P ro­
grammierer.
Dieses Buch h andelt von guter P rogrammierung. Es ist voller Code. Wir werden uns
Code aus allen möglich en Rich tungen ansch auen. Wir werden ih n von oben und
unten und von außen und innen betrach ten. Wenn wir fertig sind, werden Sie seh r
viel über Code wissen. Darüber h inaus werden Sie guten Code von sch lech tem Code
untersch eiden k önnen. Sie werden wissen, wie Sie guten Code sch reiben k önnen.
Und Sie werden wissen, wie Sie sch lech ten Code in guten Code transformieren k ön­
nen.
Kapitel l
S a u b e re r Code

1 .1 Cod e, Cod e u n d n oc h m a l s Cod e

Vielleich t k önnte man einwenden, ein Buch über Code wäre doch etwas altmodisch
- Code wäre doch längst k ein T;h ema meh r; stattdessen sollte man sich mit Model­
len und Anforderungen befassen. Tatsächlich vertreten einige Leute die Auffas­
sung, die Ära des Codes ginge zu Ende. B ald werde aller Code nich t meh r
gesch rieben, sondern generiert werden. P rogrammierer würden einfach überflüs­
sig werden, weil Gesch äftsentwickler P rogramme einfach aus Spezifik ationen
generieren würden.
Unsinn! Wir werden niemals oh ne Code arbeiten k önnen, weil der Code die Details
der Anforderungen repräsentiert. Auu einer gewissen Ebene k önnen diese Details
nich t ignoriert oder abstrah iert werden; sie müssen spezifi ziert werden. Und die
Spezifik ation von Anforderungen in einer Detailgenauigk eit, dass sie von einer
Masch ine ausgefüh rt werden k önnen, ist Programmierung. Und eine solch e Spezi­
fik ation ist Code.
I ch rech ne damit, dass die Abstrak tionsebene unserer Sprach en noch h öh er geh en
wird. I ch erwarte auch , dass die Anzahl der domänenspezifi sch en Sprach en wei­
terh in wach sen wird. Diese Entwicklung bringt Vorteile mit sich , aber sie wird den
Code nich t eliminieren. Tatsächlich werden alle Spezifik ationen, die auf diesen
h öh eren Ebenen und in den domänenspezifi sch en Sprach en gesch rieben werden,
Code sein! Sie müssen immer noch stringent, genau und so formal und detailliert
sein, dass sie von einer Masch ine verstanden und ausgefüh rt werden k önnen.
Leute, die denk en, Code werde eines Tages verschwinden, äh neln Math ematik ern,
die h offen, eines Tages eine Math ematik zu entdeck en, die nich t formal sein muss.
Sie h offen, dass wir eines Tages eine Meth ode entdeck en werden, Masch inen zu
ersch affen, die tun, was wir wollen, und nich t, was wir sagen. Diese Masch inen
müssen in der Lage sein, uns so gut zu versteh en, dass sie unsere unsch arf formu­
lierten Bedürfnisse in perfekt ausgefüh rte P rogramme übersetzen k önnen, die
genau diese Bedürfnisse erfü llen.
Dies wird nie passieren. Nich t einmal Mensch en mit all ih rer I ntuition und Krea­
tivität sind bis j etzt in der Lage gewesen, aus den unsch arfen Gefüh len ih rer Kunden
erfolgreich e Systeme abzuleiten. Wenn wir überh aupt etwas aus der Disziplin der
Anforderungsspezifik ation gelernt h aben, ist es Folgendes: Woh lspezifi zierte
Anforderungen sind genauso formal wie Code und k önnen als ausfüh rbare Tests
dieses Codes verwendet werden!
Vergessen Sie nich t, dass Code letztlich die Sprach e ist, in der wir die Anforderun­
gen ausdrück en. Wir k önnen Sprach en k onstruieren, die näh er bei den Anforde­
rungen angesiedelt sind. Wir k önnen Werk zeuge sch affen, die uns h elfen, diese
Anforderungen zu parsen und zu formalen Struk turen zusammenzusetzen. Aber
wir werden niemals die erforderlich e P räzision eliminieren k önnen- und desh alb
wird es immer Code geben.

26
1 .2
Sch I echter Code

1 .2 Sch I echter Cod e

Abb. 1.1: Ke nt Beck

Neulich las ich das Vorwort zu dem Buch Implementation Patterns von Kent Beck
[Beck o7] . Darin sch reibt er: » . . . dieses Buch basiert auf einer rech t fragilen P rä­
misse: dass guter Code eine Rolle spiele . . . « . Eine fragile P rämisse? Dem k ann ich
nich t zustimmen! I ch glaube, dass diese P rämisse zu den robustesten, am besten
unterstützten und meistdiskutierten P rä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.
I ch k enne ein Unterneh men, das in den späten 8oer-Jah ren eine Killer-Applik ation
h erausbrachte. Sie war seh r beliebt, und zah lreich e professionelle Anwender k auf­
ten und nutzten sie. Aber dann wurden die Release-Zyk len immer länger. Bugs wur­
den von einem Release zum näch sten nich t meh r repariert. Die Startzeiten wurden
länger und die Abstürze h äufiger. I ch erinnere mich an den Tag, an dem ich das P ro­
dukt frustriert absch altete und niemals wieder benutzte. Kurz danach verschwand
das Unterneh men vom Mark t.
Zwei Jah rzeh nte später traf ich einen früh eren Mitarbeiter dieses Unterneh mens
und fragte ih n, was damals passiert wäre. Die Antwort bestätigte meine Befürch ­
tungen. Das Unterneh men h atte das P roduk t zu sch nell aufiden Mark t gebrach t und
im Code ein riesiges Ch aos angerich tet. Je meh r Funk tionen zu dem Code h inzu­
gefügt wurden, desto sch lech ter wurde er, bis das Unterneh men ih n einfach nich t
meh r verwalten k onnte. Es war der schlechte Code, der das Unternehmen i n den
Abgrund trieb.
Sind Sie j emals erh eblich von sch lech tem Code beeinträch tigt worden? Wenn Sie als
P rogrammierer auch nur ein bissch en Erfah rung h aben, dann h aben Sie eine sol­
ch e Beh inderung viele Male erlebt. Tatsäch lich h aben wir eine spezielle Bezeich -

27
Kapitel l
S a u b e re r Code

nung dafür: Wading (Waten) . Wir waten durch sch lech ten Code. Wir k ämpfen uns
durch einen Morast verschlungener Sch lingpflanzen und verborgener Fallgruben.
Wir müh en uns ab, den rich tigen Weg zu finden, und h offen aufirgendwelch e Hin­
weise, die uns zeigen, was passiert; aber alles, was wir seh en, ist ein sch ier endloses
Meer von sinnlosem Code.
Natürlich sind Sie von sch lech tem Code beh indert worden. Also- warum h aben Sie
ih n gesch rieben?
Haben Sie zu sch nell gearbeitet? Waren Sie unter Druck ? Wah rsch einlich . Vielleich t
h atten Sie das Gefüh l, k eine Z eit für gute Arbeit z u h aben, meinten, Ih r Ch efiwürde
ärgerlich werden, wenn Sie sich die Z eit neh men würden, Ih ren Code aufzuräu­
men. Vielleich t waren Sie es einfa ch leid, an diesem P rogramm zu arbeiten, und
wollten endlich damit fertig werden. Oder vielleich t h aben Sie Ih ren Stapel unerle­
digter Arbeit angesch aut, die Sie längst h ätten erledigen müssen, und sind zu dem
Sch luss gek ommen, Sie müssen dieses Modul zusammensch ustern, um mit dem
näch sten weitermach en zu k önnen. Wir alle k ennen diese Erfah rung.
Wir alle h aben uns das Ch aos angesch aut, das wir gerade angerich tet h atten, und
dann besch lossen, es an einem anderen Tag zu beseitigen. Wir alle h aben die
Erleich terung gefühlt, zu seh en, dass unser ch aotisch es P rogramm lief) und
besch lossen, dass ein laufendes Ch aos besser wäre als nichts. Wir alle h aben uns
vorgenommen, später zurück zuk ommen und das Ch aos zu beseitigen. Natürlich
k annten wir damals das Gesetz von LeBlanc nicht: Später gleich niemals.

1 .3 Die Lebe n s zyk l u s koste n ei n es C h aos

Wenn Sie sch on länger als zwei bis drei Jah re programmieren, h aben Sie wah r­
sch einlich die Erfah rung gemach t, dass Ih re Arbeit von dem ch aotisch en Code eines
anderen Entwicklers erh eblich verlangsamt worden ist. Die Verlangsamung k ann
beträch tlich sein. I m Laufe von einem oder zwei Jah ren k ann es passieren, dass
Teams, die am Anfang eines P roj ekts seh r sch nell vorangek ommen waren, sich
plötzlich nur noch im Sch neck entempo vorwärtsbewegen. Jede Änderung des
Codes füh rt zur Defekten an zwei oder drei anderen Stellen des Codes. Keine Ände­
rung ist trivial. Für j ede zusätzlich e Funktion oder Modifik ation des Systems müs­
sen alle Verzweigungen, Varianten und Knoten »verstanden« werden, damit weitere
Verzweigungen, Varianten und Knoten h inzugefügt werden k önnen. I m Laufe der
Z eit wird das Ch aos so groß und so verfilzt, dass Sie es nich t meh r bereinigen k ön­
nen. Sie sind am Ende Ihres Weges angelangt.
Wäh rend das Ch aos immer größer wird, nimmt die P roduktivität des Teams laufend
ab und geh t asymptotisch gegen null. Wäh rend die P roduktivität sinkt, tut das
Management das Einzige, was es k ann: Es weist dem P roj ekt meh r Personal zu in
der Hoffnung, die P roduktivität zu steigern. Aber das neue Personal versteh t das
Design des Systems nich t. Es k ennt nich t den Untersch ied zwisch en einer Ände-
1 .3
D i e Le ben szyk l u s kosten e i nes Chaos

rung, die zum Zweck des Designs passt, und einer Änderung, die dem zuwiderläuft.
Darüber h inaus steh en Sie und die anderen Teammitglieder unter sch recklich em
Druck , die P roduktivität zu verbessern. Desh alb produzieren alle immer meh r
Ch aos und senk en damit die P roduktivität immer weiter gegen null (sieh e Abbil­
dung r.2) .

1 00 -------
� 80 '
.� 60 \

::::s 40 '
"' ......
eD. 20 --
0

Zeit
Abb. 1 .2: P rod u ktivität u n d Zeit

Das große Redesign i n d e n Wol ke n

Sch ließlich rebelliert das Team. Das Management wird darüber informiert, das s
man mit dieser zweifelh aften Code-Basis nich t weiterarbeiten k önne. E s wird ein
Redesign gefordert. Das Management will aber nich t die Ressourcen für ein k om­
plett neues Redesign des P roj ekts aufwenden, k ann sich aber auch nicht der
Erk enntnis versch ließen, dass die P roduk tivität nich t ak zeptabel ist. Sch ließlich
beugt es sich den Forderungen der Entwickler und autorisiert das große Redesign
in den Wolk en.
Es wird ein neues Tliger-Team zusammengestellt. Jeder möchte zu diesem Team
geh ören, weil es ein frisch es neues P roj ekt ist. Man darfi neu anfa ngen und etwas
wirklich Sch önes erstellen. Aber nur die Besten und Hellsten werden für das Tliger­
Team ausgewäh lt. Alle anderen müssen sich um die Wa rtung des gegenwärtigen
Systems kümmern.
Jetzt gibt es ein Wettrennen zwisch en den beiden Teams. Das Tci.ger-Team muss ein
neues System erstellen, das alle Funktionen des alten erfüllt. Und nicht nur das : Es
muss auch mit den Änderungen Sch ritt h alten, die laufend an dem alten System
vorgenommen werden. Das Management wird das alte System nich t ersetzen, bevor
nich t das neue alle Funktionen des alten erfüllt.
Dieser Wettlaufk ann sich seh r lange h inzieh en. I ch h abe Z eitspannen von bis zu
zeh n Jah ren erlebt. Und wenn er beendet wird, sind die ursprünglich en Mitglieder
des Tliger-Teams längst nicht meh r da, und die gegenwärtigen Mitglieder verlangen
nach einem Redesign des neuen Systems , weil es ein solch es Ch aos sei.

29
Kapitel l
S a u b e re r Code

Wenn nur ein kleiner Teil dieser Gesch ich te Ih rer Erfah rung entsprich t, dann wis­
sen Sie bereits, dass die Z eit, die Sie für das Sauberh alten Ih res Codes verwenden,
nicht nur k osteneffizient, sondern eine Frage des beruflich en Überlebens ist.

E i nste l l u ng

Sind Sie j emals durch einen Morast gewatet, der so dich t war, dass es Woch en dau­
erte, um zu tun, was nur einige Stunden h ätte dauern sollen? Haben Sie erlebt, dass
eine Änderung, die nur eine Z eile h ätte erfordern sollen, in Hunderten versch iede­
ner Module durch gefüh rt werden musste? Diese Symptome k ommen leider allzu
oft vor.
Warum passiert das mit Code? Warum verrottet guter Code so sch nell zu schlech ­
tem Code? Dafür h aben wir viele Erklärungen. Wir beklagen uns , dass die Anfor­
derungen in einer Weise geändert wurden, die dem ursprünglich en Design
zuwiderläuft. Sie j ammern, dass der Z eitplan zu eng bemessen war, um die Aufga­
ben richtig zu erledigen. Geben dummen Managern und den toleranten Kunden
und nutzlosen Mark eting- Typen und einem unzureich enden Telefon- Support die
Sch uld. Aber der Fehler, lieber Dilbert, liegt nich t in unseren Sternen, sondern in
uns selbst. Wir sind unprofessionell.
Diese Pille zu sch luck en, mag etwas bitter sein. Wie k önnte dieses Ch aos unsere
Sch uld sein? Was ist mit den Anforderungen? Was ist mit dem Z eitplan? Gibt es
etwa k eine dummen Manager und nutzlose Mark eting-Typen? Tragen sie nich t
einen Teil der Sch uld?
N ein. Die Manager und Mark eting- Leute fragen uns nach den I nformationen, die
sie benötigen, um Versprech ungen und Zusagen zu mach en; und selbst wenn sie
uns nich t fragen, sollten wir k eine Hemmungen h aben, ih nen zu sagen, was wir
denk en. Die Benutzer wenden sich an uns , damit wir ih nen zeigen, wie das System
ih re Anforderungen erfüllt. Die P roj ektmanager benutzen unsere I nformationen,
um ih re Z eitpläne aufzustellen. Wir sind eng in die Planung des P roj ekts einge­
bunden und tragen einen großen Teil der Verantwortung für auftretende Fehler, ins­
besondere wenn diese Fehler mit schlechtem Code zu tun h aben!
»Doch h alt!«, sagen Sie. »Wenn ich nich t tue, was mein Manager sagt, werde ich
gefeuert.« Wahrsch einlich nicht. Die meisten Manager wollen die Wahrh eit wissen,
selbst wenn sie sich nich t immer entsprech end verh alten. Die meisten Manager
wollen guten Code h aben, selbst wenn sie von ih rem Z eitplan besessen sind. V:iel­
leich t verteidigen sie leidensch aftlich den Z eitplan und die Anforderungen; aber das
ist ih r Job. Dagegen ist es Ihr Job, den Code mit gleich er Leidensch aft zu verteidigen.
Betrachten wir eine Analogie: Was würden Sie als Arzt mach en, wenn ein Patient
Sie auffordern würde, dieses blödsinnige Händewasch en bei der Vorbereitung aufi
einen ch irurgisch en Eingriffi zu lassen, weil es zu viel Z eit kostet? (Als das Hände­
wasch en r847 den Ärzten erstmals von I gnaz Semmelweis empfohlen wurde,
wurde es mit der Begründung zurück gewiesen, die Ärzte wären zu besch äftigt und
1 .3
D i e Le ben szy k l u s kosten e i nes C hao s

h ätten k eine Z eit, sich die Hände zwisch en ih ren Patientenbesuch en zu wasch en.)
Natürlich h at der Patient Vorrang. Dennoch sollte der Arzt in diesem Fall die For­
derung k ompromisslos zurückweisen. Warum? Weil der Arzt meh r über die Risi­
k en einer Erk rankung und I nfektion weiß als der Patient. Es wäre unprofessionell
(und in diesem Fall sogar k riminell) , wenn der Arzt der Forderung des P atienten
nach geben würde.
Desh alb ist es auch unprofessional, dass sich P rogrammierer dem Willen von
Managern beugen, die die Risik en nich t versteh en, die mit dem Erzeugen von
Ch aos im Code verbunden sind.

Das gru n d legende Problem

P rogrammierer werden mit einem grundlegenden Wertek onflikt k onfrontiert.


Erfah rene Entwickler wissen, dass ih re Arbeit durch alten ch aotisch en Code erh eb­
lich beh indert wird. Dennoch fühlen alle Entwickler den Druck , ch aotisch en Code
zu sch reiben, um Termine einzuh alten. Kurz gesagt: Sie neh men sich nich t die Z eit,
es rich tig zu mach en!
Ech te P rofi s wissen, dass der zweite Teil dieses Konflikts falsch ist. Man erfüllt einen
Termin eben nicht, indem man ch aotisch en Code produziert. Tatsäch lich verlang­
samt ch aotisch er Code Ih re Arbeit sofort und füh rt dazu, dass Sie Ih ren Termin
nich t einh alten k önnen. Die einzige Meth ode, den Termin einzuh alten, besteht
darin, den Code jederzeit so sauber wie möglich zu h alten.

Sa u beren Code sch re i be n - e i n e K u n st?

Angenommen, Sie glaubten, ch aotisch er Code wäre eine beträch tlich e Beh inde­
rung Ih rer Arbeit. Wenn Sie jetzt ak zeptieren, dass die einzige Möglichk eit, sch nel­
ler zu arbeiten, darin besteh t, den eigenen Code sauber zu h alten, müssen Sie sich
zwangsläufi g fragen: »Wie sch reibe ich sauberen Code?« Es h at k einen Sinn, zu ver­
such en, sauberen Code zu sch reiben, wenn Sie nich t wissen, wie sauberer Code aus­
sieht!
Leider h aben wir h ier eine sch lech te Nach rich t: Sauberen Code zu sch reiben, h at
seh r viel mit dem Malen eines Bildes zu tun. Die meisten k önnen erk ennen, wann
ein Bild gut oder sch lech t gemalt ist. Aber dies erk ennen zu k önnen, bedeutet nich t,
dass wir auch malen k önnen. Wenn Sie also in der Lage sind, sauberen von sch lech ­
tem Code z u untersch eiden, bedeutet dies nich t automatisch , dass Sie sauberen
Code sch reiben k önnen!
Sauberen Code zu sch reiben, erfordert den disziplinierten Einsatz zah lreich er klei­
ner Tech nik en, die mit einem sorgfältig erworbenen Gefühl für » Sauberk eit« ange­
wendet werden. Dieses »Gefüh l für den Code« ist der Sch lüssel. Einige sind damit
geboren. Einige müssen es sich meh r oder weniger müh sam erarbeiten. Dieses
Gefühl für den Code h ilft uns nich t nur, guten von sch lechtem Code zu untersch ei-
Kapitel l
S a u b e re r Code

den; sondern zeigt uns die Strategie, wie wir unser Arsenal von erworbenen Tech­
nik en anwenden müssen, um sch lech ten Code in guten zu transformieren.
Ein P rogrammierer oh ne dieses »Gefühl für den Code« k ann sich ein ch aotisches
Modul ansch auen und das Ch aos erk ennen, h at aber absolut k eine Vorstellung
davon, was er dagegen tun k önnte. Ein P rogrammierer mit »Gefühl für den Code«
sch aut sich das ch aotisch e Modul an und erk ennt seine Optionen und Änderungs­
möglichk eiten. Sein »Gefüh l für den Code« h ilft ih m dabei, die beste Option aus­
zuwäh len und eine Reih e von Änderungssch ritten festzulegen, die ih n zum Z iel
bringen und zugleich nach jedem Teilsch ritt die volle Funktionsfäh igk eit des Codes
erh alten.
Kurz gesagt: Ein P rogrammierer, der sauberen Code sch reibt, ist ein Künstler, der
einen leeren Bildsch irm mit einer Reih e von Transformationen in ein elegant
codiertes System umwandelt.

Was i st s a u bere r Code?

Es gibt wah rsch einlich so viele Defi nitionen wie P rogrammierer. Desh alb fragte ich
einige seh r bek annte und seh r erfah rene P rogrammierer nach ih rer Meinung.

Bjarne Stroustru p

Abb. 1 .3: Bjarne Stro u stru p

Bjarne Stroustrup, Erfi nder 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 soll-
ten minimal sein, um die Wartung zu vereirifachen, das Fehler-Handling
sollte vollständig gemäß einer vordefinierten Strategie eifolgen, und das Leis­
tungsverhalten sollte dem Optimum so nah wie möglich kommen, damit der
Entwickler nicht versucht ist, den Code durch Ad-hoc-Optimierungen zu ver­
unstalten. Sauberer Code erledigt eine Aufgabe gut.

32
1 .3
D i e Le ben szy k l u s kosten e i nes C h aos

Bj arne verwendet das Wort »elegant«. Was für ein Wort! Im Wörterbuch findet man
auch folgende Synonyme: ansprechende Anmut und Kunstftrtigkeit in Aussehen oder
Verhalten; ansprechende Sinnlichkeit und Einfachheit. Wich tig ist dabei die Betonung
von »ansprech end«. Offensich tlich glaubt Bj arne, dass sauberer Code angenehm zu
lesen sein soll. Solch en Code zu lesen, sollte einen Ausdruck des Woh lgefallens auf
Ih r Gesich t zaubern, den Sie auch vom Ansch auen eines rassigen Automobils k en­
nen.
Bj arne erwäh nt auch die Effizienz des Codes. Vielleich t sollte uns dies bei dem
Erfinder von C++ weniger überrasch en; aber ich glaube, dass er damit meh r als sei­
nen Wunsch nach einer Geschwindigk eit meint. Verschwendete Zyklen sind une­
legant, sie vermitteln k ein angeneh mes Gefühl. Und j etzt beach ten Sie, wie Bj arne
die Folgen dieser Uneleganz besch reibt. Er verwendet den Ausdruck »versuch t
sein«. Darin ist eine tiefe Weish eit verborgen. Schlech ter Code verleitet dazu, das
Ch aos zu vergrößern! Wenn andere schlech ten Code ändern, neigen sie dazu, ih n
noch sch lech ter zu mach en.
Die P ragmatisch en P rogrammierer Dave Thomas und Andy Hunt drückten dasselbe
auf andere Weise aus. Sie verwendeten die Metaph er der zerbroch enen Fenster
( h t t p : //www . p rag p rog . com/t h e - p ragmati c - p rog ramme r/ext racts/softwa re­
e n t ropy) . Ein Gebäude mit zerbroch enen Fenstern sieh t so aus, als würde sich nie­
mand darum kümmern. Desh alb kümmern sich auch andere Entwickler nicht um
den Code. Sie lassen es gewissermaßen zu, dass weitere Fenster zerbroch en werden.
Sch ließlich h elfen sie aktiv dabei. Sie versch mieren die Vorderfront mit Graffiti und
lassen zu, dass sich Müll ansammelt. DerP rozess des Zerfalls beginnt mit einem zer­
broch enen Fenster.
Bj arne erwäh nt auch , dass das Feh ler-Handling vollständig sein sollte. Dies geh ört
zur Disziplin, aufmerk sam in den Details zu sein. Ein verkürztes Feh ler-Handling
ist nur eine Meth ode, wie P rogrammierer Details vernach lässigen. Speich erleck s
und Race-Bedingungen sind weitere Beispiele dafür. Eine ink onsistente Namens­
gebung zäh lt ebenfalls zu. Das Fazit ist: Sauberer Code bedeutet auch große Sorgfalt
im Detail.
Bj arne sch ließt mit der Zusich erung, dass sauberer Code eine Aufgabe gut erledigt.
Es ist k ein Zufall, dass so viele P rinzipien des Software-Designs auf diese einfach e
Mah nung zurück gefüh rt werden k önnen. Autor für Autor h at versuch t, diesen
einen Gedank en zu k ommunizieren. Sch lech ter Code tut zu viel; seine Ab sich t ist
nich t klar zu erk ennen und er versuch t, meh rere Zweck e auf einmal zu erfüllen.
Sauberer Code ist fokussiert. Jede Funktion, j ede Klasse, j edes Modul ist eindeutig
aufi einen einzigen Zweck ausgerich tet und lässt sich von den umgebenden Details
weder ablenk en noch verunreinigen.

33
Kapitel l
S a u b e re r Code

G rady Booch

Abb. 1 .4: G rady Booch

Grady Booch , Autor von Object-Oriented Analysis and Design with Applications
Sauberer Code ist einfach und direkt. Sauberer Code liest sich wie wohlge­
schriebene Prosa. Sauberer Code verdunkelt niemals die Absicht des Designers,
sondern ist voller griffiger (engl. crisp) Abstraktionen und geradliniger Kon­
trollstrukturen.
Einige Punkte von Grady deck en sich mit denen von Bj arne, aber er betrach tet das
Ganze aus der Perspektive der Lesbarkeit. Mir gefällt besonders seine Auffassung,
dass sich sauberer Code wie woh lgesch riebene P rosa lesen lassen soll. Denk en Sie
zurück an ein wirklich gutes Buch , das Sie gelesen h aben. Erinnern Sie sich , wie die
Wörter verschwanden und durch Bilder ersetzt wurden? Es war, als würden Sie
einen Film seh en, nich t wah r? Besser! Sie sah en die Z eich en, Sie h ärten die Geräu­
sch e, Sie erlebten die Leidensch aften und den Humor.
Sauberen Code zu lesen, wird natürlich niemals dasselbe sein, wie Der Herr der
Ringe zu lesen. Dennoch ist die literarisch e Metaph er brauch bar. Wie ein guter
Roman sollte sauberer Code die Spannung in den zu lösenden P roblemen sauber
h erausarbeiten. Diese Spannung sollte einem Höh epunkt zutreiben und dann dem
Leser dieses »Ah a ! Ja natürlich !« vermitteln, wenn die P robleme und Spannungen
bei der Enth üllung einer offensich tlich en Lösung aufgelöst werden.
Für mich ist der Ausdruck »griffige Ab straktion« (im Original: »crisp abstraction«,
wörtl. »k nack ige oder frisch e Ab straktion«, unübersetzbar) ein faszinierendes Oxy­
moron (ein Widerspruch in sich ) ! Sch ließlich bedeutet das Wort »griffig« eh er etwas
Handgreiflich es, Konk retes, praktisch Nutzbares. Trotz dieses sch einbaren Wider­
spruch s der Wörter vermitteln sie eine klare Botsch aft. Unser Code sollte nich t spe­
k ulativ, sondern nüch tern und sach bezogen sein. Es sollte nur das Erforderlich e
enth alten. Unsere Leser sollten unsere Bestimmth eit erk ennen k önnen.

34
1 .3
D i e Le ben szyk l u s kosten e i nes C hao s

Dave Thomas

Abb. 1 .5: Dave T h o m a s

»Big« Dave Th omas, Gründer der OTI , der P ate (Godfath er) der Eclipse-Strategie
Sauberer Code kann von anderen Entwicklern gelesen und verbessert werden.
Er veifü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 Veifügung. Er enthält minimale Abhängigkeiten, die ausdrücklich
defi n iert sind, und stellte ein klares und minimales AP I zur Veifügung. Code
sollte »literate« sein, da je nach Sprache nicht alle eiforderlichen Informatio-
nen allein im Code klar ausgedrückt werden können. (A.d. Ü. : »Literate Pro­
gramming« ist eine Unterströmung, bei der die Einheit von Kommentaren
und Code betont und geifördert wird.)
Auch Big Dave strebt wie Grady Lesbark eit an, fordert aber eine wich tige Ergänzung.
Für Dave ist es wichtig, dass sauberer Code es anderen Entwicklern erleich tert, ih n
zu verbessern. Dies mag off ensichtlich sch einen, aber es k ann nicht genug betont
werden. Schließlich gibt es einen Untersch ied zwisch en Code, der einfach zu lesen
ist, und Code, der einfach zu ändern ist.
Dave mach t Sauberk eit von Tests abh ängig! Vor zeh n Jah ren h ätten viele bei dieser
Forderung die Stirn gerunzelt. Ab er die Disziplin der Test Driven Development
(TDD) h at einen wesentlich en Einfluss auf die Soft ware-Branch e geh abt und h at
sich zu einer der grundlegenden Disziplinen entwick elt. Dave h at recht. Code oh ne
Tests ist nich t sauber. Egal wie elegant er ist, egal wie lesbar und änderungsfteund­
lich er ist, oh ne Tests ist er unsauber.
Dave verwendet das Wort minimal zweimal. Off ensichtlich sch ätzt er Code, der
einen geringen Umfang h at. Tatsächlich h at sich im Laufe der letzten Jah re ein Kon­
sens in der Software-Literatur gebildet: Kleiner ist besser.

35
Kapitel l
S a u b e re r Code

Dave sagt auch , Code solle literate sein. Dies ist ein sanfter Hinweis auf das Literate
Programming von Donald Knuth [Knuth 92]. Die Q uintessenz lautet Code sollte so
aufb ereitet werden, dass er von Mensch en gelesen werden k ann.

M ichael Feathers

Abb. 1 .6: M i chael Feath e rs

Mich ael Feath ers, Autor von Warking Effectively with Legacy Code
Ich könnte alle Eigenschaften auflisten, die mir bei sauberem Code auffa llen;
aber es gibt eine übergre ifende 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 verbes­
sern 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 eigentlich e Th ema dieses Buch es . Vielleich t h ätte ein
passender Untertitel gelautet: Wie man seinem Code Sorgfalt angedeihen lässt.
Mich ael trifft den Nagel auf den Kopf. Sauberer Code ist Code, der sorgfältig erstellt
worden ist. Jemand h at sich die Z eit genommen, den Code sauber zu strukturieren
und zu sch reiben. Jemand h at den Details die erforderlich e Sorgfalt angedeih en las­
sen. Jemand war es nich t egal, wie sein Arbeitsergebnis aussah .
1 .3
D i e Le ben szy k l u s kosten e i nes C h aos

Ron J effi-ies

Abb. 1 .7: Ron J effries

Ron Jeffries, Autor von Extreme Programming Installed und Extreme Programming
Adventures in C#
Ron begann seine Karriere als P rogrammierer in Fortran bei dem Strategie Air
Command und h at Code in fast j eder Sprach e und auf fast j eder Masch ine gesch rie­
ben. Es zah lt sich aus, seine Worte sorgfältig zu überdenk en.
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 eifü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 Dup­
lizierung. Wenn dieselbe Sache immer wieder gemacht wird, ist dies ein Zei­
chen dafür, dass wir einen bestimmten Gedanken in unserem Code nicht gut
genug repräsentiert haben. Dann versuche ich herauszufinden, diesen Gedan­
ken zu fassen und klarer auszudrücken.
Ausdruckskraft umfasst für mich bedeutungsvolle Namen. Häufig ändere ich
die Namen der Dinge mehifach, bis ich die endgültige Version gefunden habe.
Mit modernen Entwicklungswerkzeugen wie etwa Eclipse ist die Umbenen­
nung 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 eifüllt. Ist dies der Fall, zer-

37
Kapitel l
S a u b e re r Code

lege ich ein Objekt in zwei oder mehr kleinere Objekte oderführe ein Refacto­
ring 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 ande­
ren Aspekt meiner Bemühungen, der etwas schwerer zu erklären ist.
Aufisrund 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 abstrak­
tere Methode oder Klasse. Dadurch erziele ich eine Reihe interessanter Vor­
teile.
Ich kann die Funktionalitätjetzt mit etwas Einfachem, etwa einer Hash-Map,
implementieren. Doch da jetzt alle Referenzen auf diese Suche in meiner klei­
nen Abstraktion eingekapselt sind, kann ich die Implementierung jederzeit
ändern. Ich komme schneller voran und bewahre mir trotzdem meine Fähig­
keit, 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 reali­
siere, auch wenn ich wirklich nur eine ziemlich einfache Methode brauche,
um etwas Gesuchtes zu finden.
Reduzierung der Duplizierung, Steigerung der Ausdruckskraft undfrühe For­
mulierung einfacher Abstraktionen machen für mich sauberen Code aus.
Hier h at Ron in einigen k urzen Ab sätzen den I nh alt dieses Buch es zusammenge­
fasst: k eine Duplizierung, eine Aufg abe, Ausdruck sk raft, kleine Ab straktionen. Es
ist alles da.

Ward Cu n n i ngham

Ward Cunningh am, Erfinder des Wil<i, Erfinder von Fit, Miterfinder des eXtreme
P rogramming. Treibende Kraft h inter den Design Patterns. Smalltalk- und 00-Vor­
denk er. Der Pate aller Leute, denen ih r Code nich t egal ist.
1 .3
D i e Le ben szyk l u s kosten e i nes Chaos

Abb. 1 .8: Wa rd C u n n i n g h a m

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.
Solch e Aussagen sind für Ward ch arakteristisch . Sie lesen sie, nick en mit dem Kopf
und wenden sich dann dem näch sten Th ema zu. Die Aussage h ört sich so vernünf•
tig, so offensich tlich an, dass sie k aum als etwas Grundlegendes wah rgenommen
wird. Sie glauben, sie drück e rech t genau das aus, was Sie erwartet h aben. Doch
sch auen wir etwas genauer h in.
» . . . ziemlich genau so, wie Sie es erwartet h aben.« Wann h aben Sie zum letzten Mal
ein Modul geseh en, das ziemlich genau dem entsprach , was Sie erwartet h aben? I st
es nich t wah rsch einlich er, dass die Module, die Sie sich ansch auen, rätselh aft, k om­
pliziert und verworren ausseh en? I st es nich t die Regel, dass Sie in die falsch e Rich ­
tung gelockt werden? Sind Sie e s nich t gewoh nt, verzweifelt und frustriert die
Denk fäden aufz uspüren und durch das ganze System zu verfolgen, aus denen letzt­
lich das Modul gewebt ist? Wann h aben Sie zum letzten Mal Code gelesen und dabei
mit dem Kopf genickt, wie Sie eben die Aussage von Ward aufgenommen h aben?
Ward erwartet, dass Sie beim Lesen von sauberem Code überh aupt k eine Überra­
sch ungen erleben. Tatsächlich sollte das Ganze fast müh elos sein. Sie lesen den
Code, und er entsprich t ziemlich genau dem, was Sie erwartet h aben. Er ist offen­
sich tlich , einfach und überzeugend. Jedes Modul ist eine Stufe für das näch ste.
Jedes gibt vor, wie das näch ste gesch rieben sein wird. P rogramme, die so sauber
sind, sind so außerordentlich gut gesch rieben, dass Sie es gar nich t mal bemerk en.
Der Designer lässt das P roblem läch erlich einfach ausseh en- ein h erausragendes
Merk mal aller außerordentlich en Designs.
Und was ist mit Wards Vorstellung von Sch önh eit? Wir h aben alle sch on darüber
gesch impft, dass unsere Sprach en nich t für unsere P robleme k onzipiert worden
wären. Ab er Wards Aussage gibt uns den Sch warzen Peter zurück . Er sagt, sch öner
Code lasse die Sprache aussehen, als wäre sie für das Problem gemacht worden! Es liegt

39
Kapitel l
S a u b e re r Code

also in unserer Verantwortung, die Sprach e einfach ausseh en zu lassen! Dies sollte
Sprach eiferern jeder Couleur zu denk en geben! Es ist nich t die Sprach e, die ein P ro­
gramm einfach ausseh en lässt. Es ist der P rogrammierer, der die Sprach e einfach
ausseh en lässt!

1 .4 Den ksc h u le n

Abb. 1 .9: U n cle Bob (Robert C. M a rt i n )

Was ist mit mir (Uncle Bob) ? Was ist für mich sauberer Code? Dieses Buch wird
Ih nen bis ins kleinste Detail sagen, was meine Mitstreiter und ich über sauberen
Code denk en. Wir werden Ih nen sagen, was unserer Meinung nach einen sauberen
Variablennamen, eine saubere Funktion, eine saubere Klasse usw. ausmach t. Wir
werden diese Meinungen als Absoluta formulieren, und wir werden uns nich t für
unsere Sch ärfe entsch uldigen. Für uns sind sie, an diesem Punkt unserer Karriere,
absolute P ostulate. Sie sind unsere Denkschule für sauberen Code.
Kampfsportk ünstler sind sich über die beste Kampfsportart oder die beste Tech nik
innerh alb einer Kampfsportart überh aupt nich t einig. Oft gründen Meister einer
Kampfsportart ih re eigene Denk sch ule und sammeln Sch üler um sich , denen sie
ih ren speziellen Kampfstil vermitteln. So gibt es etwa ein Gracie jiu ]istu, das von
der Gracie-Familie in Brasilien begründet wurde und geleh rt wird. Es gibt ein Hak­
koryu]iu]istu, das von Okuyama Ryuh o in Tokyo begründet wurde und geleh rt wird.
Es gibt ein ]eet Kune Do, das von Bruce Lee in den Vereinigten Staaten begründet
wurde und von seinen N ach folgern geleh rt wird.
Sch üler dieser Ansätze unterzieh en sich einem intensiven Studium der Leh ren der
Gründer. Sie widmen ih re Z eit dem Erlernen des speziellen Kampfstils des jewei­
ligen Meisters. Oft blenden sie dabei die Leh ren aller anderen Meister aus. Später,
wenn die Sch üler in ih rem Kampfstil eine gewisse Reife erreich t h aben, k önnen sie
auch bei einem anderen Meister studieren, um ih r Wissen und ih re Kampftech ni­
k en auf eine breitere Basis zu stellen. Einige entwick eln und verfeinern ih re Fäh ig-
1 .5
W i r s i n d Autoren

k eiten sch ließlich so weit, dass sie neue Tech niken entdecken und eigene Sch ulen
gründen.
Keine dieser versch iedenen Sch ulen ist die absolut richtige. Doch innerh alb einer
speziellen Sch ule verhalten wir uns so, als wären die Leh ren und Tech niken rich tig.
Denn sch ließlich gibt es eine korrekte Meth ode, Hakkoryu Jiu Jitsu oder Jeet Kune
Do auszuüben. Aber diese Selbstgerech tigkeit innerh alb einer Sch ule entwertet
nich t die Leh ren einer anderen Sch ule.
Betrach ten Sie dieses Buch als eine Besch reibung der Object Mentor School of Clean
Code (Object-Mentor- Sch ule des sauberen Codes) . Die Tech niken und Leh ren in die­
sem Buch sind die Meth oden, wie wir unsere Kunst praktizieren. Wir geh en so weit
zu beh aupten, dass Sie, wenn Sie diese Leh ren befolgen, die Vorteile erlangen wer­
den, die wir erlangt h aben, und dass Sie lernen werden, sauberen und professio­
nellen Code zu sch reiben. Sie sollten aber nich t den Feh ler mach en zu glauben, dass
wir in irgendeinem absoluten Sinne »rech t« h ätten. Es gibt andere Sch ulen und
andere Meister, die mit demselben Nach druck P rofessionalität für sich in Anspruch
neh men wie wir. Und auch von ih nen zu lernen, würde Ih rem Können nur zugu­
tekommen.
Tatsäch lich werden viele Empfeh lungen in diesem Buch kontrovers diskutiert. Sie
werden wah rsch einlich nich t mit allem einverstanden sein. Vielleich t werden Sie
einige sogar h eftig ableh nen. Das ist in Ordnung. Wir können keinen Anspruch auf
die endgültige Autorität erh eben. Andererseits sind die Empfeh lungen in diesem
Buch Dinge, über die wir lange und gründlich nach gedach t h aben. Sie basieren aufi
j ah rzeh ntelanger Erfah rung und h aben sich in wiederh olten Versuch -und-I rrtum­
Zyklen h erauskristallisiert. Also: Egal, ob Sie mit uns übereinstimmen oder nich t,
es wäre eine Sch ande, wenn Sie unseren Standpunkt nich t kennen lernen und
respektieren würden.

1 .5 Wir s i n d Autore n

Das @au t h o r-Feld einer Javadoc sagt, wer wir sind. Wir sind Autoren. Ein Merkmal
von Autoren ist es, dass sie Leser h aben. Tatsäch lich sind Autoren dafür verantwort­
lich, erfolgreich mit ih ren Lesern zu kommunizieren. Wenn Sie Ih re näch ste Code­
zeile sch reiben, sollten Sie daran denken, dass Sie ein Autor sind, der für Leser
sch reibt, die Ih re Anstrengung beurteilen.
V:ielleich t fragen Sie, wie viel Code wirklich gelesen wird. Steckt der größte Aufwand
nich t darin, den Code zu sch reiben?
Haben Sie jemals ein Play-back einer Edit- Sitzung durch gefüh rt? I n den 8oern und
9 0ern h atten wir Editoren wie Emacs, die jeden Tastenansch lag speich ern konnten.
Sie konnten eine Stunde lang arbeiten und dann ein Play-back Ih rer gesamten Edit­
Sitzung wie im Z eitraffer ablaufen lassen. Als ich dies tat, waren die Ergebnisse fas­
zinierend.

41
Kapitel l
S a u b e re r Code

Der bei Weitem größte Anteil des Play-back s bestand darin, dass ich h erumscrollte
und zu anderen Modulen navigierte!
Bob kommt zu dem Modul.
Er scrollt zu der Funktion herunter, die geändert werden muss.
Er macht eine Pause und denkt über seine Optionen nach.
Oh, er scrollt wieder nach oben an den Anfang des Moduls, um die Initialisie­
rung einer Variablen zu überprüfen.
jetzt scrollt er zurück nach unten und beginnt zu tippen.
Ups, er löscht, was er getippt hat!
Er tippt erneut.
Er löscht erneut!
Er tippt die Hälfte von etwas anderem, aber löscht es dann wieder!
Er scrollt runter zu einer anderen Funktion, die die Funktion aufruft, die er
ändert, um zu sehen, wie sie aufgerufen wird.
Er scrollt zurück und tippt denselben Code ein, den er gerade gelöscht hat.
Er macht eine Pause.
Er löscht den Code wieder!
Er ö.ffn et ein anderes Fenster und schaut sich eine Unterklasse an. Wird die
Funktion überschrieben ?

Sie versteh en, was abgeht. Tatsäch lich beträgt das Verh ältnis der Z eit, die mit Lesen
verbrach t wird, zu der Z eit, die mit Sch reiben verbrach t wird, weit über 1 0 : 1 . Wir
lesen permanent alten Code als Teil unseres Bemüh ens, neuen Code zu sch reiben.
Weil dieses Verh ältnis so h och ist, sollte das Lesen von Code leich t sein, selbst wenn
dadurch das Sch reiben sch werer wird. Natürlich ist es unmöglich , Code zu sch rei­
ben, oh ne ih n zu lesen. Desh alb ist das Bemüh en, das Lesen von Code zu erleichtern,
zugleich ein Bemüh en, das Schreiben von Code leichter zu machen.
Dieser Logik k ann man sich nich t entzieh en. Man k ann k einen Code sch reiben,
wenn man den umgebenden Code nich t lesen k ann. Der Code, den Sie h eute zu
sch reiben versuchen, wird schwer oder leich t zu sch reiben sein, und zwar abh ängig
davon, wie sch wer oder leich t Sie den umgebenden Code lesen k önnen. Wenn Sie
also sch nell vorwärtsk ommen wollen, wenn Sie sch nell fertig werden wollen, wenn
Sie Ih ren Code leich t sch reiben wollen, mach en Sie es leicht, ih n zu lesen.
1 .6
D i e Pfa d fi n d e r- Re g e l

1 .6 Die Pfadfi n d e r- Regel

Es reich t nich t aus, guten Code zu sch reiben. Der Code muss auch im Zeitablauf
sauber gehalten werden. Wir h aben alle erlebt, wie Code im Laufe der Z eit verrottet
und immer schlech ter geworden ist. Desh alb müssen wir ak tiv tätig werden, um die­
sem schleich enden Verfall vorzubeugen.
Bei den P fadfindern gibt es eine einfach e Regel, die wir auch auf unseren Beruf
anwenden k önnen. (Sie wurde aus der Absch iedsbotsch aft, Versuche die Welt ein
wenig besser zu hinterlassen, als du sie gefonden hast, . . . , von Robert Steph enson Smyth
Baden-Poweil an die P fadfinder, abgeleitet.) Die Botsch aft lautet:
Hinterlasse den Campingplatz sauberer, als du ihn gefonden hast.
Wenn wir alle unseren Code ein wenig sauberer einch eck en, als wir ih n ausgech eck t
h aben, k ann der Code einfach nich t verrotten. Es muss k ein Großreinemach en sein.
Verbessern Sie h ier einen Va riablennamen, zerlegen Sie dort eine etwas zu große
Funktion, eliminieren Sie doppelte Codezeilen oder bauen Sie eine zusammenge­
setzte i f-Anweisung um.
Können Sie sich vorstellen, an einem P rojekt zu arbeiten, bei dem der Code im
Laufe der Z eit einfach besser wurde? Glauben Sie, dass ein anderes Verh alten profes­
sionell wäre? Oder ist die laufende Verbesserung vielleich t ein wesentliches Merk ­
mal von P rofessionalität?

1 .7 Vo rläufer u n d Pri n z i p i e n

I n vieler Hinsich t ist dieses Buch ein »Vorläufer« z u meinem Buch Agile Software
Development: Principles, Patterns, and Practices (PPP ) aus dem Jah re 2002. Das PPP ­
Buch beh andelt die P rinzipien des Objekt-orientierten Design (OOD) und viele
Tech nik en, die von professionellen Entwicklern eingesetzt werden. Falls Sie PPP
nich t gelesen h aben, werden Sie meinen, dass es eine Fortsetzung der Gesch ich te
ist, die in diesem Buch erzählt wird. Wenn Sie es bereits gelesen h aben, werden Sie
in dem vorliegenden Buch einen Widerh all vieler Aussagen aus dem PPP - Buch fin­
den, und zwar diesmal auf der Ebene des Codes.
In diesem Buch werden gelegentlich versch iedene Design-P rinzipien referenziert:
das Single-Responsibility-P rinzip ( S RP ) , das Open-Closed-P rinzip (OCP ) und das
Dependency-I nversion-P rinzip (DIP ) und andere. Diese P rinzipien werden in PPP
ausfüh rlich besch rieben.

1 .8 Z u sa m m e nfass u n g

Büch er über Kunst versprech en Ih nen nich t, aus Ih nen einen Künstler zu mach en.
Sie k önnen Ih nen nur einige Werk zeuge, Tech nik en und Gedank enprozesse ver-

43
Kapitel l
S a u b e re r Code

mitteln, die von anderen Künstlern verwendet worden sind. Desh alb versprich t
Ih nen dieses Buch nicht, aus Ih nen einen guten P rogrammierer z u mach en. Es
k ann Ih nen nicht versprech en, Ih nen ein Gefühl für den Code zu vermitteln. Es
k ann Ih nen nur die Gedank enprozesse von guten P rogrammierern aufzeigen und
die Trick s, Tech nik en und Werk zeuge mitteilen, die sie verwenden.
Äh nlich wie ein Kunstbuch enth ält dieses Buch zah lreich e Details. Es enth ält
umfangreich en Code. Sie seh en guten Code, und Sie seh en sch lech ten Code. Es
wird demonstriert, wie sch lech ter Code in guten Code transformiert werden k ann.
Sie finden Listen mit Heuristik en, P rinzipien und Tech nik en. Und es wird Ih nen
ein Beispiel nach dem anderen gezeigt. Danach sind Sie auf sich gestellt.
Kennen Sie die Gesch ich te von dem Konzert-Violinenspieler, der sich aufidem Weg
zur Vorfüh rung verlaufen h atte ? Er fragte einen alten Mann an der Straßeneck e
nach dem Weg zur Carnegie Hall. Der alte Mann sch aute den Violinenspieler an,
sah die Geige unter seinem Arm und sagte: » Übung, mein Sohn. Übung!«

44
Kapitel 2

Aussagekräftige N amen

von Tim Ottinger

2.1 E i nfü h ru n g

Namen kommen in Software überall vor. Wir benennen unsere Va riablen, unsere
Funktionen, unsere Argumente, Klassen und Packages. Wir benennen unsere
Q uelldateien und die Verzeich nisse, in denen sie enth alten sind. Wir benennen
unsere j a r-Dateien und wa r-Dateien und ea r-Dateien. Wir benennen und benen­
nen und benennen. Was wir so h äufig tun, sollten wir besser gut tun. In den fol­
genden Absch nitten finden Sie einige einfach e Regeln für die Bildung guter Namen.

2.2 Zweckbesch re i be n d e N a m e n wä h l e n

Es ist einfach zu sagen, Namen sollten den Zweck besch reiben. Wir möch ten Ih nen
vermitteln, dass wir dies ernst meinen. Gute Namen zu wäh len, brauch t Zeit. spart
aber letztlich meh r Z eit ein. Desh alb sollten Sie Ih re Namen sorgfältig auswähle::
Kapitel 2
A u s s age k räfti g e N a m e n

und ändern, wenn Sie bessere finden. Jeder Leser Ihres Codes ( Sie eingeschlossen)
profitiert davon.
Der Name einer Variablen, Funktion oder Klasse sollte alle großen Fragen beant­
worten. Er sollte Ihnen sagen, warum er existiert. was er tut und wie er benutzt wird.
Wenn ein Name einen Kommentar erfordert, dann drückt er seinen Zweck nicht
aus .

i n t d ; II a b g e l a u f e n d e Z e i t i n Tag e n

Der Name d enthüllt nichts . Er ruft weder das Bild einer Zeitspanne noch einen
Gedanken an Tage hervor. Wir sollten einen Namen wählen. der angibt, was gemes­
sen wird und in welcher Einheit es gemessen wird:

i nt e l a p s edTi me i n Days ;
i nt d a y s S i n c e C r e at i on ;
i nt day s S i n c eModi fi c a t i on ;
i nt fi l eAg e i n Day s ;

Namen zu wählen, die den Zweck ausdrücken, macht es viel leichter. den Code zu
verstehen und zu ändern. Welchen Zweck erfüllt der folgende Code ?

p u b l i c L i s t < i n t [ ] > g e tTh e m ( ) {


Li st<i nt [] > l i stl = new A r r a y l i s t < i n t [ ] > ( ) ;
fo r ( i n t [ ] x : t h e l i s t )
if (x [O] 4)
==

1 i s t l . add ( x ) ;
ret u r n l i stl ;
}

Warum ist es so schwierig zu erkennen, was dieser Code tut? Es enthält keine kom­
plexen Ausdrücke. Die Zeichenabstände und Einrückungen sind vernünftig. Es gibt
nur drei Variablen und zwei Konstanten. Es gibt keine exotischen Klassen oder poly­
morphe Methoden . nur eine Liste von Arrays (so scheint es jedenfalls) .
Das Problem ist nicht die Einfachheit des Codes, sondern seine Implizität (um einen
Begriff zu prägen) : ein Maß dafür, wie weit der Kontext explizit aus dem Code selbst
hervorgeht oder nicht. Der Code erfordert von uns implizit, dass wir die Antworten
auf die folgenden Fragen kennen:
I. Welche Dinge sind in t h e l i s t gespeichert?
2. Welche Bedeutung hat das Subskript n u l l eines Elements von t h e l i s t ?
3 · Welche Bedeutung hat der Wert 4 ?

4 · Wie wird die zurückgegebene Liste verwendet?

Die Antworten auf diese Fragen gehen aus dem Code-Beispiel nicht hervor, aber sie
hätten daraus hervorgehen können. Angenommen, Sie arbeiteten an einem Mine-
2. 3
Feh l i n fo r m a t i o n e n verm e i d e n

Sweeper- Spiel. Sie stellen fest, dass Sie das Spielfeld als eine Liste von Z ellen reprä­
sentieren können, die Sie als t h e l i s t bezeichnen. Wir wollen diese Liste in g am e ­
B o a r d umbenennen.
Jede Z elle des Spielfelds wird durch ein einfaches Array repräsentiert. Sie stellen
weiter fest, dass das Subskript n u l l einen Statuswert enthält und dass der Status­
wert 4 »flagged (markiert)« bedeutet. Einfach, indem Sie diese entsprechenden
Konzepte benennen, k önnen Sie den Code erheblich verbessern:

publ i c Li st<i n t [ ] > getFl aggedCel l s () {


L i s t < i n t [ ] > fl a g g e d C e l l s new A r r a y l i s t < i n t [ ] > ( ) ;
=

fo r ( i n t [ ] c e l l : gameBo a r d )
i f ( c e l l [ STATUS_VA L U E ] F LAGG ED)
==

fl a g g e d C e l l s . ad d ( c e l l ) ;
r e t u rn fl a g g e d C e l l s ;
}

Beachten Sie, dass sich die Einfachheit des Codes nicht geändert hat. Er enthält
immer noch genau dieselbe Z ahl von Operatoren und Konstanten, mit genau der­
selben Z ahl von Verschachtelungsebenen. Aber der Code ist jetzt sehr viel expliziter,
drückt also seinen Zweck sehr viel klarer aus.
Wir k önnen einen Schritt weitergehen und eine einfache Klasse für Z ellen schrei­
ben, anstatt ein Array von i n t s zu benutzen. Die Klasse k ann eine den Zweck aus­
drück ende Funktion (nennen wir sie i s Fl agged) enthalten, um die magischen
Z ahlen zu verbergen. Hier ist die neue Version der Funktion:

publ i c Li st<Cel l > getFl aggedCel l s () {


L i s t < C e l l > fl a g g e d C e l l s =n ew A r r a y l i s t <C e l l > ( ) ;
fo r (Ce l l c e l l : g a m e Bo a r d )
i f ( c e l l . i s F l a g g e d () )
fl a g g e d Ce l l s . ad d ( c e l l ) ;
r e t u r n fl a g g e d C e l l s ;
}

Nach diesen einfachen Namensänderungen ist es nicht mehr schwierig zu verste­


hen, was passiert. Dies ist ein Beispiel für die Kraft, die gut gewählten Namen inne­
liegt.

2.3 Fe h l i nformationen vermeiden

Programmierer sollten k eine irreführenden Hinweise hinterlassen, die die Bedeu­


tung des Codes verdunk eln. Wir sollten Wörter vermeiden, deren etablierte Bedeu­
tungen von unserer beabsichtigten Bedeutung abweichen. Beispielsweise wären h p,
ai x oder s c o als Va riablennamen ungeeignet, weil es sich um die Namen von Unix­
Plattformen oder -Va rianten handelt. Selbst wenn Sie eine Hypotenuse codieren
und h p für eine geeignete Abkürzung halten, könnte dieser Name irreführend sein.

47
I Kapitel 2
A u s s a g ekräfti g e N a me n

Bezeich nen Sie eine Gruppe von Konten nur dann als a c c o u n t l i s t, wenn es sich
wirklich um eine L i s t h andelt. Das Wort Liste bedeutet für einen P rogrammierer
etwas ganz Spezielles. Wenn der Container, der die Konten enth ält, nich t tatsächlich
eine L i s t ist, k önnte der Name zu falsch en Sch lussfolgerungen füh ren. Desh alb
wäre a c c o u n t G r o u p oder b u n c h OfAc c o u n t s oder einfach a c c o u n t s besser. Und
selbst wenn der Container eine Liste ist, wäre es wahrsch einlich besser, den Con­
tainer-Typ nicht im Namen zu codieren. Meh r darüber später.
Achten Sie aufN amen, die sich geringfügig untersch eiden. Wie lange dauert es, den
subtilen Untersch ied zwisch en XYZCo n t ro l l e r Fo r Effi c i e n t H a n d l i n güf­
S t r i ngs in einem Modul und XYZCo n t ro l l e r Fo r Effi c i e n t Sto rag eOfSt r i n g s
an etwas entfernterer Stelle z u entdecken? Die äußere Form der Wörter ist ersch re­
ck end äh nlich .
Äh nlich e Konzepte äh nlich zu sch reiben, vermittelt I nformationen. Eine inkonsis­
tente Sch reibweise ist Desinformation. Moderne Java-Umgehungen bieten uns den
Luxus der automatisch en Code-Ergänzung (code completion). Wir schreiben einige
Z eich en eines Namens und drück en eine Hotkey-Kombination aus (i f th at) und
werden mit einer Liste möglich er Ergänzungen für diesen Namen verwöh nt. Es ist
seh r h ilfreich , wenn Namen für sehr äh nlich e Aufgaben alph abetisch benachbart
steh en und wenn die Untersch iede klar erk ennbar sind, weil der Entwickler wah r­
sch einlich ein Objekt anh and seines Namens auswählt, oh ne Ih re umfangreich en
Kommentare oder sogar die Liste der Meth oden dieser Klasse zu studieren.
Wirk lich absch reck ende Beispiele für irreführende Namen sind der Kleinbuch stabe
l oder der Großbuch stabe 0 als Variablennamen, besonders wenn sie kombiniert
werden. Das P roblem liegt h ier natürlich darin, dass sie fast genau wie die Konstan­
ten eins bzw. null ausseh en.

i nt a 1 ;
=

if ( 0 ==1 )
a =01 ;
e1 se
1 = 01 ;

Wenn Sie meinen, dieses Beispiel wäre getürkt, k önnen wir nur sagen, dass wir
Code untersucht h aben, in dem derartige Dinge in Hülle und Fülle vork amen. I n
einem Fall sch lug der Autor des Codes vor, eine andere Sch riftart zu verwenden,
damit die Untersch iede besser sichtbar wären. Eine solch e Lösung müsste dann
natürlich an alle künftigen Entwickler weitergegeben werden, entweder als münd­
lich e Überlieferung oder in einem sch riftlich en Dokument. Durch eine einfach e
Umbenennung wird das P roblem endgültig und oh ne zusätzlich en AufWand erle­
digt.
2 -4
U n ters c h i e d e d e u t l i ch m achen

2.4 U ntersch iede de utl i c h m achen

P rogrammierer sch affen sich ih re eigenen P robleme, wenn sie Code schreiben, nur
um einem Compiler oder I nterpreter gerecht zu werden. Ein Beispiel: Weil man im
selben Geltungsbereich nicht denselben Namen zur Bezeich nung versch iedener
Aufgaben verwenden darf; könnte man versucht sein, einen Namen willkürlich zu
ändern. Manch mal wird für diesen Zweck einfach der Name falsch geschrieben, was
zu einer überrasch enden Situation füh rt, dass eine Korrektur des vorgeblich en
»Sch reibfehlers« zu Feh lern beim Kompilieren füh rt. Betrachten Sie beispielsweise
die wirklich absch eulich e P raxis, eine Variable namens kl ass zu erstellen, einfach
weil der Name c l a s s für etwas anderes verwendet wird.
Es reicht nicht aus, eine Z ah lenfolge oder leere Wörter anzuh ängen, auch wenn der
Compiler damit zufrieden sein sollte. Wenn die Namen untersch iedlich sein müs­
sen, dann sollten sie auch etwas Versch iedenes bezeichnen.
Namen mit Z ah lenserien (al , a2 , . . aN) sind das Gegenteil einer zweckvollen
Benennung. Solch e Namen sind nicht irreführend - sie sind informationsleer; sie
enth alten keinen Hinweis auf die Absicht des Autors . Ein Beispiel:

p u b l i c s t at i c voi d copyCh a r s ( c h a r al [ ] , c h a r a2 [ ] ) {
fo r ( i n t i = 0 ; i < al . l e n g t h ; i ++) {
a2 [ i ]
= al [ i ] ;
}
}

Diese Funktion liest sich viel besser, wenn sou rce und des t i na t i on als Argument­
Namen benutzt werden.
Leere Wörter sind eine andere Form der bedeutungsleeren Untersch eidung. Ange­
nommen, Sie h ätten eine P ro d u c t - Klasse. Wenn Sie eine andere Klasse namens
P ro d u c t i n fo oder P ro d u c tData h aben, h aben Sie zwar einen anderen Namen,
aber keine andere Bedeutung. I n fo und Data sind unbestimmte Leerwörter wie a,
an und t h e .
Beach ten Sie, dass nichts dagegen einzuwenden ist, wenn Sie P räfix- Konventionen
wie a und t h e verwenden, solange Sie damit eine sinnvolle Untersch eidung aus­
drücken. Beispielsweise könnten Sie a für alle lokalen Variablen und t h e für alle
Funktionsargumente verwenden. (Uncle Bob h at diese Tech nik früh er in C++ ein­
gesetzt, aber dann aufgegeben, weil sie durch moderne I D Es überflüssig wurde.)
Das P roblem tritt auf, wenn Sie besch ließen, eine Variable t heZo r k zu nennen, weil
Sie bereits eine andere Variable namens zo r k h aben.
Leerwörter sind redundant. Das Wort va r i abl e sollte niemals in einem Variablen­
namen ersch einen. Das Wort tab l e sollte niemals in einem Tabellennamen vor­
kommen. Wieso ist Name S t r i ng besser als Nam e ? Könnte ein Name j emals eine
Fließkommazahl sein? Wäre dies der Fall, würden Sie gegen eine früh ere Regel übe
Kapitel 2
A u s s a g ekräfti g e N a m e n

Fehlinformationen verstoßen. Stellen Sie sich vor, Sie stießen auf eine Klasse
namens C u s tome r und eine andere namens C u s tome rObj e c t . Wodurch unter­
sch eiden sich die Klassen? Welch e repräsentiert den besten Pfad zu der Zah lungs­
h istorie eines Kunden?
Wir kennen eine Anwendung, in der dies illustriert wird. Wir h aben den Namen
geändert, um die Sch uldigen zu sch ützen; doch h ier ist die genaue Form des Feh ­
lers:

g e tA c t i veAcco u n t ( ) ;
g e tA c t i veAcco u n t s ( ) ;
g e tAc t i veAccou n t i n fo () ;

Woh er sollen die Programmierer in diesem Projekt wissen, welch e Funktion sie auf­
rufen müssen?
Wenn keine speziellen Konventionen vereinbart sind, ist die Va riable moneyAmo u n t
von m o n e y nicht untersch eidbar; dasselbe gilt für c u s tome r l n fo und c u stome r,
a c c o u n t Data und a c c o u n t sowie t h eMe s s ag e und m e s s ag e . Namen sollten so
untersch ieden werden. dass der Leser weiß, was der Untersch ied bedeutet.

2.5 A u s s p rec h b a re N a me n verwe nden

Mensch en können gut mit Wörtern umgeh en. Ein großer Teil unseres Geh irns
dient dem HerYorbringen und Verarbeiten von Wörtern. Und Wörter sind per Defi­
nition aussprechbar. Es wäre eine Sch ande, diesen riesigen Teil unseres Geh irns,
der für den Cmgang mit gesproch ener Sprach e entwickelt worden ist, nicht zu
unserem Vorteil zu nutzen. Desh alb sollten Ih re Namen aussprech bar sein.
Wenn Sie einen �amen nicht aussprech en können, können Sie nich t darüber dis­
kutieren, oh ne sich \\·ie ein I diot anzuh ören. »Na ja, h ier bei dem be ce er drei ce
en te h aben wir pe es ze qu int, nich t wah r?« Dies spielt eine Rolle; denn Program­
mieren ist eine soziale Aktivität.
Ein mir bekanntes Unterneh men h at g e n ymd h m s (generation date, year, month , day,
h our, minute und second; Erstellungsdatum, Jahr, Monat, Tag, Stunde, Minute und
Sekunde) . Desh alb laufen sie rum und reden von »gen wh y emm dee aich emm ess«
(in Englisch ! ) . I ch h abe die nervige Angewoh nh eit, alles so auszusprech en, wie es
gesch rieben ist. Desh alb fing ich an mit: »gen-yah -mudda-h ims«. Später h aben
meh rere Designer und Analysten meine Sprechweise übernommen, sie h ört sich
trotzdem immer noch albern an. Aber dann war es für uns h alt ein I nsider-Witz.
Spaß oder nicht. wir tolerierten einen schlech ten Namen. Neue Entwickler brauch ­
ten eine Erklärung und fingen dann ebenfalls an, alberne erfundene Wörter anstelle
verständlich er umgangs- oder fach sprachlich er Wörter zu benutzen. Vergleich en
Sie

so
2.6
S u c h b a re N a m e n verwe n d e n

c l a s s DtaRc rd102 {
p r i vate D a t e g e n ym d h m s ;
p r i vate D a t e modymdh m s ;
p r i vate f i n a l S t r i n g p s zq i n t = " 10 2 " ;
!* . . . *!
};

mit

c l a s s C u s tome r {
p r i vate D a t e g e n e r a t i onTi m e s t amp ;
p r i vate D a t e modi f i c a t i o nTi m e s tamp ; ;
p r i vate f i n a l S t r i n g reco r d l d = " 10 2 " ;
/* . . . * /
};

Jetzt kann man sich intelligent darüber unterh alten: »Hey, Mikey, sch au dir diesen
Datensatz an! Der g e n e rati o nTi m e s t amp wird auf das morgige Datum gesetzt!
Wie kann das sein?«

2.6 S u c h bare N a men verwe nden

B e i Namen aus einzelnen Buch staben und numerisch en Konstanten gibt es ein spe­
zielles P roblem: Sie sind in einem Textabsch nitt nur schwer zu finden.
Während es leicht ist, per g rep nach MAX_C LASS E S_P E R_STU D E NT zu such en, berei­
tet die Z ahl 7 woh l mehr Schwierigkeiten. Die Such e weist Ergebnisse aus , die die
Ziffer 7 als Bestandteil eines Dateinamens, in anderen konstanten Definitionen
und in versch iedenen Ausdrücken enth alten, wo sie jeweils untersch iedlich e Zwe­
cke erfüllt. Noch schlimmer ist es bei einer konstanten langen Z ahl: Jemand könnte
aus Verseh en Ziffern vertausch en und damit einen Bug verursach en, wäh rend die
Variable dadurch gleich zeitig durch den Such filter des P rogrammierers fällt.
I n diesem Sinne ist auch der Name e als Variablenname ungeeignet. Weil dieser
Buch stabe zu den h äufigsten der normalen Sprach e geh ört, führt eine Such e nach
diesem Namen zu zahlreich en Nieten. I n dieser Hinsicht sind längere besser als
kürzere, und such bare Name sind besser als Konstanten im Code.
Persönlich zieh e ich es vor, Variablennamen aus einem einzigen Buch staben NUR
als lokale Variablen in kurzen Methoden zu verwenden. Die Länge eines Namens sollte
der Größe seines Geltungsbereiches entsprechen [N5]. Wenn eine Variable oder Kon­
stante an mehreren Stellen des Codes ersch eint oder benutzt wird, muss sie einen
such freundlich en Namen h aben. Vergleich en Sie wieder

fo r ( i n t j -0 ; j < 3 4 ; j ++) {
s += ( t [ j ] * 4) / 5 ;
}
Kapitel 2
A us s a g ekräfti ge N a m e n

mit

i n t r e a l Days P e r i d e a l Day = 4 ;
con s t i n t WORK_DAYS_ P E R_W E E K = 5 ;
i n t sum = 0 ;
fo r ( i n t j =O ; j < N U M B E R_Q F_TAS K S ; j ++) {
i n t r e a l Tas kDays = tas k E s t i mate [ j ] * r e a l Days Pe r i d e a l Day ;
i n t r e a l Tas kWe e k s = ( r e a l days I WORK_DAYS_P E R_� E E� J :
s u m += r e a l Tas kWee k s ;
}

Beachten Sie, dass s u m in dem obigen Beispiel kein besonders nützlich er Name ist,
aber wenigstens ist er such bar. Der Code mit den zwech·ollen Namen ist länger.
Doch bedenken Sie, wie viel leich ter es sein wird, WO RK_DAYS_P E R_W E E K zu such en,
als alle Stellen zu prüf en, an denen 5 verwendet wurde und die Liste aufdie Instan­
zen mit der beabsichtigten Bedeutung zu reduzieren.

2.7 Cod ieru n ge n vermeiden

Wir müssen uns sch on mit genug Codierungen h erumschlagen und brauch en uns
keine weiteren aufzuladen. Inf ormationen über den Typ oder den Geltungsbereich
per Codierung in Namen aufzuneh men, erschwert einfach nur zusätzlich die Last
der Entschlüsselung. Es gibt selten einen vernünftigen Grunci dafur. dass neue Mit­
arbeiter zusätzlich zu dem (normalerweise beträchtlich em vorh andenen Code, mit
dem sie arbeiten sollen, noch eine weitere Verschlüsselungs - ,. Sprach e« lernen müs­
sen. Es ist eine unnötige mentale Belastung, wenn wir versuch en. ein Problem zu
lösen. Codierte Namen lassen sich selten aussprech en und können leicht falsch
getippt werden.

U n garische N otati on

In der guten alten Zeit, als die Länge der Namen in den Sprach en allzu beschränkt
war, mussten wir, leider, zwangsläufig gegen diese Regel verstoßen. In Fortran
musste der erste Buch stabe eines Codes den Typ angeben. In früh en Versionen von
BAS IC durften Namen nur aus einem Buch staben plus einer Ziffer besteh en. Und
die Hungarian Notation (HN; ungarisch e Notation) h ob diese Kunst auf eine ganz
neue Ebene.
Zu Zeiten des C-AP I von Windows, als alles ein Integer-Handle oder ein La ng-Poin­
ter oder ein vo i d-Pointer oder eine von mehreren Implementierungen von »String«
(mit versch iedenen Anwendungszwecken und Attributen) war. galt die HN als h oh e
Kunst. Damals füh rten Compiler keine Typ-Prüfungen durch . desh alb brauch ten
Programmierer eine Krücke, die ih nen h alf; die Typen zu erkennen und auseinan­
derzuh alten.

52
2.7
Cod i e ru n g en verm e i d e n

In modernen Sprachen verfügen wir über viel reichhaltigere Typensysteme, und die
Compiler prüfen die Typen und erzwingen ihre Einhaltung. Darüber hinaus gibt es
einen Trend zu kleineren Klassen und kürzeren Funktionen, wodurch Entwickler
normalerweise die Stelle der Deklaration aller Variablen sehen können, mit denen
sie arbeiten.
Java-P rogrammierer brauchen keine Typ-Codierung. Objekte sind stark typisiert,
und die Entwicklungsumgehungen sind so weit fortgeschritten, dass sie Typenfeh­
ler entdecken, lange bevor Sie das P rogramm kompilieren können! Deshalb sind
heute die HN und anderen Formen der Typ-Codierung einfach nur hinderlich. Sie
erschweren das Ändern des Namens undfa der Typs einer Variablen, Funktion oder
Klasse. Sie erschweren das Lesen des Codes. Und sie schaffen das Risiko, dass das
Codierungssystem den Leser irreführt.

P h o n e N u mbe r p h o n e S t r i n g ;
II N am e wi rd n i c h t g e ä n d e r t , we n n s i c h d e r T y p ä n d e r t !

M em ber- Präfixe

Außerdem braucht man heute keine Member-Variablen mehr mit dem P räfix m_ zu
versehen. I hre Klassen und Funktionen sollten so klein sein, dass Sie es einfach
nicht benötigen. Und Sie sollten eine Entwicklungsumgebung benutzen, die Mem­
ber-Variablen durch eine geeignete Farbe hervorhebt, um sie von anderen zu unter­
scheiden. Also nicht

p u b l i c c l as s P a r t {
p r i vate S t r i n g m_d s c ; II d i e t e x t l i c h e B e s c h r e i b u n g
voi d s e t N am e ( S t r i n g n am e ) {
m_d s c =n am e ;
}
}

sondern

p u b l i c c l as s P a r t {
Stri ng descri pti on ;
voi d s e tD e s c r i p t i o n ( S t r i n g d e s c r i p t i o n ) {
th i s . descri pti on =descri pti on ;
}
}

Außerdem lernen Entwickler schnell, das P räfix (oder Suffix) zu ignorieren, und
achten nur auf den bedeutungsvollen Teil des Namens. Je häufiger wir den Code
lesen, desto weniger bemerken wir die P räfixe. Schließlich werden die P räfixe unbe­
merkter Müll und ein Z eichen für älteren Code.
Kapitel 2
A us s a g e k räfti g e N a m e n

I nterfaces u n d I m p lementieru ngen

Diese sind manch mal spezielle Fälle von Codierungen. Angenommen, Sie wollten
eine Abstract Factory für die Erstellung von geometrisch en Formen entwickeln.
Diese Factory soll ein I nterface h aben und durch eine konkrete Klasse implemen­
tiert werden. Wie sollte sie h eißen? I S h ape Fac t o r y und S h ape Facto ry? I ch zieh e
e s vor, I nterfaces nicht mit einem dekorierten Namen z u benennen. Das vorange­
h ende I, das in den h eutigen Legacy-Biblioth eken so h äufig anzutreffen ist, ist bes­
tenfalls eine Ablenkung und liefert schlimmstenfalls zu viele I nformationen. I ch
möchte nicht, dass meine Benutzer wissen, dass ich Ih nen ein I nterface übergebe.
I ch will nur, dass sie wissen, dass es sich um eine S h a pe Fac t o r y h andelt. Wenn ich
also entsch eiden muss, ob ich entweder das I nterface oder die I mplementierung
codiere, wähle ich die I mplementierung. Ein Name wie S h ape Facto rylmp oder
selbst der schrecklich e Name C S h a p e Facto ry sind einer Codierung des I nterface­
Namens vorzuzieh en.

2.8 M e nta l e M a p p i n gs ve rmeiden

Die Leser sollten Ih ren Namen nicht mental in einen anderen Namen übersetzen
müssen, den sie bereits kennen. Dieses P roblem tritt im Allgemeinen auf, wenn
man weder die Termini der P roblemdomäne noch die der Lösungsdomäne verwen­
det.
Bei Variablennamen aus einem einzigen Buch staben kann es P robleme geben.
Sich er ist ein Schleifenzähler namens i oder j oder k (obwoh l niemals l !) akzep­
tabel, wenn sein Geltungsbereich seh r klein ist und keine Konflikte mit anderen
Namen auftreten können. Derartige Namen für Schleifenzäh ler h aben eine lange
Tradition. Doch in den meisten anderen Kontexten ist ein Name aus einem einzigen
Buch staben schlech t gewählt; er ist nur ein Platzh alter, den der Leser mental in das
tatsächlich e Konzept übersetzen muss. Es gibt keinen sch limmeren Grund dafür,
den Namen c nur desh alb zu verwenden, weil a und b bereits vergeben waren.
I m Allgemeinen sind P rogrammierer ziemlich schlau. Manch e schlaue Leute
geben gerne mit ih rer Schlauh eit an und zeigen, wie gut sie mental jonglieren kön­
nen. Denn sch ließlich müssen sie, wenn sie sich zuverlässig daran erinnern kön­
nen, dass r die Kleinbuch stabenversion eines U RLs oh ne Host und Sch ema ist,
sich er sehr sch lau sein.
Der Untersch ied zwisch en einem schlauen P rogrammierer und einem professio­
nellen P rogrammierer besteh t darin, dass der professionelle P rogrammierer weiß,
dass die Klarheit absoluten Vorrang hat. P rofis nutzen ih re Fäh igkeiten zum Guten
und sch reiben Code, den andere versteh en.

54
2.9
Klassen namen

2.9 Klassen n a m e n

Klassen und Objekte sollten Namen h aben, die aus einem Substantiv oder einem
substantivisch en Ausdruck besteh en: C u s tome r, Wi ki Page, Ac c o u n t oder Add r e s s ­
Pa r s e r. Vermeiden Sie Wörter wie Manage r, P ro c e s s o r, Data oder I n fo im Namen
einer Klasse. Ein Klassenname sollte kein Verb sein.

2.1 0 M ethoden n a m en

Meth oden sollten Namen h aben, die aus einem Verb oder einem Ausdruck mit
einem Verb besteh en: pos t Paym e n t , de l e t e Page oder s av e . Accessoren, Mutato­
ren und P rädikate sollten nach ih rem Wert benannt werden und, dem JavaBean­
Standard folgend, ein P räfix wie g e t , s e t und i s h aben ( h t t p : I jj ava . s u n . comj
j ava s e/te c h n o l ogi e s /d e s ktop/j avabean s / i n d e x . j s p) .

s t r i n g n ame = e m p l o ye e . g e t Name ( ) ;
c u s t ome r . s e t N ame ( " mi k e " ) ;
i f ( p ayc h ec k . i s Po s t e d ( ) ) . . .

Wenn Konstrukta ren überladen werden, sollten Sie statisch e Factory-Meth oden mit
Namen verwenden, die die Argumente beschreiben. Ein Beispiel,

Comp l ex f u l c r u m Po i n t = Com p l e x . F romRe a l N u m be r ( 2 3 . 0) ;

ist im Allgemeinen besser als

Com p l e x fu l c r u m Po i n t = n ew Com p l e x ( 2 3 . 0) ;

Um die Anwendung der entsprech enden Konstrukta ren zu erzwingen, können Sie
sie als p r i vate deklarieren.

2.1 1 Vermeiden Sie h u morige N a m e n

Wenn Namen z u h umorig gewählt sind, erinnern sich nur Entwickler daran, die
denselben Sinn für Humor wie der Autor h aben, und auch nur so lange, wie sie sich
an den Witz erinnern. Werden sie später noch wissen, was die Funktion namens
Hol yHandG r e n ad e tun soll? Sicher, der Name ist h umorig, aber vielleicht wäre in
diesem Fall ein nüch ternes De l e t e l t em s vielleicht doch der bessere Name. Klarh eit
ist wichtiger als der Unterh altungswert
Humorigkeit im Code zeigt sich oft auch in Form von umgangssprachlich en Aus­
drücken oder Slang. Beispielsweise sollten Sie nicht den Namen whac k ( ) für
ki l l ( ) verwenden. Erzählen Sie keine kleinen kulturspezifisch en Witze wie eat ­
MyS h o rt s ( ) , wenn Sie a bo r t ( ) meinen.
Sagen Sie, was Sie meinen. Meinen Sie, was Sie sagen.
Kapitel 2
A u s s a g e kräfti g e N a m e n

2.1 2 Wä h l en Sie ei n Wort pro Ko n zept

Wäh len Sie ein Wort für ein abstraktes Konzept aus und bleiben Sie dabei. Beispiels­
weise ist es verwirrend, wenn Sie fe t c h , ret r i eve und g e t als Namen für gleich ­
wertige Meth oden versch iedener Klassen verwenden. Wie erinnern Sie sich ,
welch er Meth odenname zu welch er Klasse geh ört? Traurigerweise müssen Sie sich
oft merken, welch es Unterneh men, welch e Gruppe oder welch e Person die Library
oder Klasse schrieb, um sich daran zu erinnern, welch e Bezeich nung benutzt
wurde. Andernfalls verbringen Sie sch recklich viel Z eit damit, Header und vorh e­
rige Code-Beispiele zu durch such en.
Moderne Entwicklungsumgehungen wie Eclipse und IntelliJ stellen Ih nen kontext­
sensitive Hinweise zur Verfügung, etwa die Liste der Meth oden, die Sie bei einem
gegebenen Obj ekt aufrufen können. Allerdings zeigt die Liste normalerweise nich t
die Kommentare mit an, die Sie z u Ih ren Funktionsnamen und P arameterlisten
gesch rieben h aben. Wenn Sie Glück h aben, zeigt sie die Parameter-Namen aus den
Funktionsdeklarationen an. Die Funktionsnamen müssen für sich selbst sprech en,
und sie müssen konsistent sein, damit Sie die korrekte Meth ode oh ne zusätzlich e
Such arbeit auswählen können.
Äh nlich ist es auch verwirrend, wenn Sie in einer Code-Basis einen co n t ro l l e r
und einen manag e r und einen d ri ve r verwenden. Was ist der wesentlich e Unter­
sch ied zwisch en einem Devi c eManag e r und einem P rotocol Con t rol l e r ?
Warum sind nich t beide cont rol l e rs oder beide m a n a g e rs? Sind beide wirklich
Drivers ? Der Name verleitet Sie dazu, zwei Objekte zu erwarten, die einem seh r ver­
sch iedenen Typ angeh ören und ganz versch iedene Klassen h aben.
Ein konsistentes Lexikon ist ein großer Vorteil für die P rogrammierer. die Ih ren
Code verwenden müssen.

2.1 3 Ke i n e Worts piele

Verwenden Sie nicht dasselbe Wort für zwei Zwecke. Wenn Sie dieselbe Bezeich ­
nung für zwei versch iedene Konzepte verwenden, treiben Sie ein \Vortspiel.
Wenn Sie die Regel »ein Wort pro Konzept« beach ten, erh alten Sie möglich erweise
viele Klassen. die beispielsweise eine add-Meth ode enth alten. Solange die Parame­
terlisten und Rückgabewerte der versch iedenen add-Meth oden semantisch gleich ­
wertig sind, ist alles in Ordnung.
Doch möglich erweise besch ließen Sie, das Wort add aus Gründen der »Konsistenz«
für einen Zweck zu verwenden, bei dem keine Addition in demselben Sinne erfolgt.
Angenommen, Sie h ätten viele Klassen, in denen mit add ein neuer Wert erstellt
wird, indem zwei vorh andene Werte addiert oder verkettet werden. Doch jetzt woll­
ten Sie eine neue Klasse sch reiben, die über eine Meth ode verfügt, die ih ren einzi­
gen Parameter in eine Collection einfügt. Sollten Sie diese \feth ode add nennen ?

sG
2. 1 4
N a m e n d e r Lös u n g s d o m ä n e verwe n d e n

Vielleich t h alten Sie dies für k onsistent, weil Sie so viele andere add-Meth oden
h aben. Doch in diesem Fall ist die Bedeutung eine andere; desh alb sollten Sie statt­
dessen einen Namen wie i n s e rt oder append verwenden. Die neue Meth ode eben­
falls add zu nennen, wäre ein Wortspiel.
Als Autoren wollen wir Code sch reiben, der so leich t lesbar wie möglich ist. Der
Leser soll den Code sch nell überfliegen k önnen und nich t intensiv studieren müs­
sen. Sie sollten dem beliebten Tasch enbuch -Modell folgen und sich als Autor dafür
verantwortlich fühlen, sich klar auszudrück en. Dagegen ist es beim ak ademisch en
Modell die Aufgabe des Geleh rten, die Bedeutung aus dem Papier auszugraben.

2.1 4 N a m e n der Lös u n gsd o m ä n e verwe n d e n

Denk en Sie daran, dass die Entwickler, die Ih ren Code lesen, Programmierer sind.
Desh alb sollten Sie Fachbegriffe der I nformatik , Algorith mennamen, Pattern­
Namen, math ematisch e Begriffe usw. verwenden. Es ist nicht sinnvoll, jeden
Namen aus der Problemdomäne zu entleh nen, weil unsere Kollegen nicht jedes Mal
gezwungen sein sollten, beim Kunden rück zufragen, um die Bedeutung eines
Namens zu erfah ren, wenn sie das Konzept bereits unter einem anderen Namen
k ennen.
Der Name Ac c o u n tVi s i to r sagt einem Programmierer seh r viel, der mit dem Visi­
tor-Pattern vertraut ist. Dagegen würde ein Programmierer wah rsch einlich nich t
wissen, was eine J o bQu e u e ist. Programmierer müssen zah lreich e seh r tech nisch e
Aufg aben erledigen. Tech nisch e Namen für diese Aufgaben zu wäh len, ist norma­
lerweise die angemessenste Vorgeh ensweise.

2.1 5 N a m e n der Problemd o m ä n e verwe n d e n

Wenn e s keine Termini aus der I nformatik für Ih re Aufgaben gibt, sollten Sie die
Namen aus der Problemdomäne entleh nen. Dann k önnen Programmierer, die
Ih ren Code warten, wenigstens einen Bereich sexperten nach der Bedeutung fragen.
Das Konzept der Lösungs- und der Problemdomäne zu trennen, geh ört zu den Auf­
gaben eines guten Programmierers und Designers. Der Code, der meh r mit Kon­
zepten der Problemdomäne zu tun h at, sollte entsprech end meh r Namen aus der
Problemdomäne enth alten.

2.1 6 Bedeutu n gsvo l l e n Kontext h i n z u fü ge n

Es gibt einige Namen, die a n sich sch on bedeutungsvoll sind - die meisten sind e s
nich t. Stattdessen müssen Sie die Namen für Ih re Leser i n einen Kontext stellen.
indem Sie die Namen in wohlbenannte Klassen, Funktionen oder Namespaces ein-

57
Kapitel 2
A u s s a g e k räfti g e N a m e n

fügen. Wenn alles andere k einen Erfolg h at, ist möglich erweise ein Präfix als letzter
Ausweg erforderlich .
Stellen Sie sich vor, Sie h ätten Variablen namens fi r s t N ame, l a s t N ame, s t r e e t ,
h o u s e N u m b e r, c i ty, s t ate und z i p co d e . Zusammengenommen ist es ziemlich
klar, dass sie eine Adresse bilden. Aber was wäre, wenn Sie nur die s tate-Variable
allein in einer Meth ode seh en würden? Würden Sie automatisch sch ließen, dass es
sich um einen Teil einer Adresse h andelte?
Sie k önnen den Kontext mith ilfe von Präfixen h inzufügen: add r F i r s t N ame,
add r Las t N am e , add r State usw. Wenigstens versteh t dann der Leser, dass diese
Variablen zu einer größeren Struktur geh ören. Natürlich wäre es besser, eine Klasse
namens Add r e s s zu erstellen. Dann wüsste sogar der Compiler, dass die Variablen
zu einem größeren Konzept geh örten.
Betrach ten Sie die Meth ode in Listing 2.r. Brauch en die Variablen einen bedeu­
tungsvollereD Kontext? Der Funktionsname stellt nur einen Teil des Kontextes zur
Verfügung; der Algorith mus liefert den Rest. Wenn Sie die Funktion lesen, seh en
Sie, dass die drei Variablen, n u mbe r, ve r b und p l u ra l Mod i fi e r zu der Nach rich t
»guess statistics« (etwa: »Statistisch e Daten erraten«) geh ören. Leider muss der
Kontext ersch lossen werden. Wenn Sie sich die Meth ode zum ersten Mal
ansch auen, sind die Bedeutungen der Variablen nich t zu erk ennen.

listi ng 2.1 : Vari a blen m it u n klarem Kontext


p r i vate voi d p r i n tG u e s s S t a t i s t i c s ( c h a r c a n d i d a t e , i n t c o u n t ) {
S t r i n g n u m be r ;
Stri ng verb ;
S t ri n g p l u ral Mod i fi e r ;
i f (co u n t 0) {
==

n umbe r = " no" ;


ve r b = " a re" ;
p l u r a l Mod i fi e r "s" ; =

} e l s e i f ( co u n t == 1) {
numbe r "1" ;
=

ve r b = "i s" ;
p l u r a l Modi fi e r = " " ·
'

} el se {
n umbe r = I n t e g e r . to S t r i n g ( c o u n t ) ;
ve r b = " a re" ;
p l u ra l Modi fi e r = "s" ;
}
Stri ng guessMessage S t r i n g . fo rmat (
=

" Th e r e %s %s %s%s " , ve r b , n u m be r , c a n d i d a t e , p l u r a l Modi fi e r


);
p ri nt (gues sMessage) ;
}
2.1 6
B e d e u t u n g svo l l e n Kon text h i n z ufü g e n

Die Funktion ist ein wenig zu lang und die Variablen werden in der ganzen Funktion
benutzt. Um die Funktion in kleinere Teile zu zerlegen, müssen wir eine G u e s s ­
Stati s t i c s M e s s a g e Klasse erstellen und die drei Variablen als Felder dieser
-

Klasse deklarieren. Dadurch erstellen wir einen klaren Kontext für die drei Variab­
len. Sie gehören definitiv zu der G u e s s Stati s t i c s Me s s ag e . Wegen der Verbesse­
rung des Kontextes wird auch der Algorithmus viel sauberer, indem wir ihn in viele
kleinere Funktionen zerlegen (siehe Listing 2 . 2 ) .

listi ng 2.2: Variablen mit Kontext


p u b l i c c l a s s G u e s s S t at i s t i c s M e s s ag e {
p r i vate S t r i n g n u mbe r ;
p r i vate S t r i n g ve r b ;
p r i vate S t r i n g p l u r a l Modi fi e r ;

p u b l i c S t r i n g make ( c h a r c a n d i d a t e , i n t c o u n t ) {
c r eate P l u r a l D e p e n d e n t Me s s ag e P a r t s ( c o u n t ) ;
r e t u rn S t r i n g . fo rmat (
" Th e r e %s %s %s%s " ,
ve r b , n u mbe r , c a n d i dat e , p l u r a l Mod i fi e r ) ;
}

p r i vate voi d c re a t e P l u r al D e p e n d e n t Me s s ag e P a r t s ( i n t cou n t ) {


i f (cou n t == 0) {
the reAreNolette rs () ;
} e l s e i f (c o u n t == 1) {
t h e re i sO n e l e t t e r () ;
} e l se {
t h e reA r e M a n y l e tt e r s ( co u n t ) ;
}
}

p r i vate voi d t h e reA reMany l e t t e r s ( i n t cou n t ) {


n u mbe r = I n t e g e r . t o S t r i n g ( c o u n t ) ;
ve r b = " a r e " ;
p l u r a l M odi fi e r = " s " ;
}

p r i vate voi d t h e r e i sO n e l e t t e r () {
n u mbe r = "1" ;
ve r b = " i s " ;
p l u r a l Mod i fi e r = " " ·
'

p r i vate voi d t h e r e A r e N o l e t t e r s ( ) {
n u mbe r = " no " ;
verb = "are" ;
p l u r a l Mod i fi e r = " s " ;
}
}
Kapitel 2
A u s s a g ekräfti g e N a m e n

2.1 7 Kei nen ü be rfl ü ss i ge n Ko ntext h i nz ufü ge n

Angenommen, Sie erstellten eine Anwendung namens »Gas Station Deluxe«. Dann
wäre es keine gute Idee, jede Klasse mit dem P räfix GSD zu beginnen. Offen gesagt:
Sie würden dann gegen Ihre Tools arbeiten. Sie tippen G ein, drücken au:fi Cample­
tion Key und werden mit einer ellenlangen Liste aller Klassen des Systems belohnt.
I st das intelligent? Warum sollten Sie es der I D E schwermachen, Ihnen zu helfen?
Ein ähnlicher Fall: Sie habe eine Mai l i n gAdd r e s s - Kl asse in dem Buchhaltungsmo­
dul von GSD entwickelt und nennen Sie GSDAc c o u n tAdd r e s s . Später brauchen Sie
eine Postanschrift für Ihre Kundenkontakt-Anwendung. Verwenden Sie G S D ­
A c c o u n tAdd r es s ? Hört sich das wie der richtige Name an? Zehn von 17 Zeichen
sind redundant oder irrelevant.
Kürzere Namen sind im Allgemeinen besser als längere, solange sie klar sind.
Fügen Sie nicht mehr Kontext zu einem Namen hinzu, als erforderlich ist.
Die Namen a c c o u n tAd d r e s s und c u s tome rAd d r e s s sind geeignete Namen für
Instanzen der Klasse Add r e s s , könnten aber für Klassen ungeeignet sein. Add r e s s
ist ein geeigneter Name für eine Klasse. Wenn ich zwischen MAC-Adressen, P ort­
Adressen und Web-Adressen unterscheiden muss, würde ich Postal Ad d r e s s , MAC
und U R I in Erwägung ziehen. Die fertigen Namen sind präziser, und darum geht
es bei der Benennung.

2.1 8 Absch l ieße n d e Wo rte


Die Schwierigkeit, gute Namen zu wählen, geht auf zwei Faktoren zurück. Erstens
muss man über gute Beschreibungsfahigkeiten verfügen. Zweitens braucht man
einen gemeinsamen kulturellen Hintergrund. Dies ist ein P roblem des Lebrens
und Lernens und kein technisches, geschäftliches oder organisatorisches P roblem.
Deshalb haben viele Entwickler auf diesem Teilgebiet nicht sehr viel gelernt.
Viele haben auch Angst, Dinge umzubenennen, weil sie P roteste ihrer Kollegen
fürchten. Wir teilen diese Angst nicht und sind eigentlich dankbar, wenn Namen
verbessert werden. Meistens lernen wir die Namen von Klassen und Methoden
nicht auswendig. Wir verwenden unsere modernen Werkzeuge, um die Details zu
handhaben, damit wir uns darau:fi konzentrieren können, ob sich der Code wie
Absätze und Sätze oder wenigstens wie Tabellen und Datenstrukturen lesen lässt.
(Ein Satz ist nicht immer die beste Form, Daten anzuzeigen. ) Wahrscheinlich wer­
den Sie jeden überraschen, wenn Sie etwas umbenennen; aber das gilt für andere
Code-Verbesserungen auch. Lassen Sie sich davon nicht abhalten.
Befolgen Sie einige dieser Regeln und prüfen Sie, ob Sie damit die Lesbarkeit Ihres
Codes verbessern. Wenn Sie den Code eines anderen Entwicklers warten, sollten Sie
Refactoring-Werkzeuge heranziehen, die Ihnen helfen, diese P robleme zu lösen. Es
zahlt sich schon kurzfristig aus, und auch langfristig werden Sie immer weiteren
Nutzen ernten.

Go
Kapitel 3

Fu n ktionen

In den Anfangstagen der P rogrammierung setzen wir unsere Systeme aus Routi­
nen und Subroutinen zusammen. Dann, in der Ära von Fortran und P L/ I , setzen
wir unsere Systeme aus P rogrammen, Unterprogrammen und Funktionen zusam­
men. Heutzutage haben nur die Funktionen aus den Anfangstagen überlebt. Funk­
tionen sind die ersten Organisationseinheiten j edes P rogramms. Wie man gute
Funktionen schreibt, ist Thema dieses Kapitels.
Betrachten Sie den Code in Listing 3 - l · Es ist schwer, eine lange Funktion in Fit­
Nesse, einem Open- Source-Testwerkzeug ( h t t p : I /fi t n e s s e . o rg) , zu finden;
aber nachdem ich ein wenig gesucht hatte, stieß ich auf die hier gezeigte Funktion.
Sie ist nicht nur lang, sondern sie enthält duplizierten Code, zahlreiche komische
Strings und viele seltsame und nicht offensichtliche Datentypen und AP is. Versu­
chen Sie, ob Sie in den nächsten drei Minuten daraus schlau werden.
Kapitel 3
F u n kt i o n e n

Listi ng 3.1: Html U t i 1 . j ava (FitNesse 2007061 9)


p u b l i c s t at i c S t r i n g t e s t a b l e H t m l (
PageData pageDat a ,
bool e a n i n c l u d e S u i t e S e t u p
) t h rows E x c e p t i on {
Wi ki Page wi ki Page = p a g e Dat a . g e tWi k i Page ( ) ;
S t r i n g ß u ffe r b u ffe r = n ew S t r i n g ß u ffe r ( ) ;
i f ( pageData . h asAtt r i b u t e ( "Tes t " ) ) {
i f ( i n c l u d e S u i t e S e t u p) {
Wi ki Page s u i t e S e t u p =
PageC rawl e r i m p l . g e t i n h e r i t e d P ag e (
S u i t e Re s po n d e r . S U ITE_S ETU P_NAM E , wi ki Page
);
i f (sui teSetup ! = nul l ) {
Wi ki P a g e P a t h p a g e P a t h =
s u i t e S e t u p . g e t PageC r awl e r ( ) . g e t F u l l Pat h ( s u i t e S e t u p) ;
S t r i n g pag e P a t h N ame = Pat h P a r s e r . r e n d e r ( p a g e P a t h ) ;
b u ffe r . a p p e n d ( " ! i n c l u d e - s e t u p . " )
. a ppe n d ( pa g e P a t h N ame)
. append ( "\n " ) ;
}
}
Wi k i Page s e t u p =
PageC rawl e r i m p 1 . g e t i n n e r i t e d Page ( " S e t U p " , wi ki Page) ;
i f (setup ! = nul l ) {
Wi ki P a g e P a t h s e t u p Pa t h =
wi ki Page . g e t PageC ra� l e r ( ) . g e t F u l l Pat h ( s e t u p ) ;
S t r i n g s e t u p P a t h � a - e = Pat h Pa r s e r . r e n d e r ( s e t u p Pat h ) ;
b u ffe r . a p p e n d ( " ! i n c l u d e - s e t u p . " )
. a p p e n d ( s e t u p Pa t h N am e )
. append ( " \ n " ) ;
}
}
b u f fe r . a p p e n d ( pageData . g e tCon t e n t () ) ;
i f ( pageData . h asAtt r i b u t e ( " Te s t " ) ) {
Wi ki Page t e a rdo�n =

PageC rawl e r i m p l . g e t i n h e r i t e d P ag e ( "Tea rDown " , wi ki Page) ;


i f ( t e a rdown ! = n u l l ) {
Wi ki P a g e P a t h t e a rDown Path =
wi k i Page . g e t PageC rawl e r ( ) . g e t F u l l Pat h ( t e a rdown ) ;
S t r i n g tea rDo � n P a t h Name = Pat h Pa r s e r . r e n d e r ( t e a rDown Pat h ) ;
b u ffe r . a p p e n d ( " \ n " )
. a p p e n d C ! i n c l u d e - t e a rdown . " )
. a ppe n d ( t e a rDown P at h Name)
. a p p e n d ( " \n " ) ;
}
i f ( i n c l u d e S u i t e S e t u p) {
Wi ki Page s u i teTea rdown =
Pag e C r awl e r i m p l . g e t i n h e r i t e d Pag e (

62
2.18
Absc h l ieße n d e Worte

S u i t e R e s p o n d e r . SU ITE_TEARDOWN_NAM E ,
wi ki Page
);
i f ( s u i teTea rdown ! = n u l l ) {
Wi k i Pag e Pa t h p a g e P a t h =
s u i teTe a r down . g e t Pag e C r awl e r ( ) . g e t Fu l l P a t h ( s u i t eTe a r down ) ;
S t r i n g pag e Pa t h Name = Pat h P a r s e r . r e n d e r ( p a g e Pat h ) ;
b u ffe r . a p p e n d ( " ! i n c l u d e - t e a r down . " )
. ap p e n d ( p a g e P a t h N am e )
. ap p e n d ( " \ n " ) ;
}
}
}
p a g e Data . s e tCon t e n t ( b uffe r . to S t r i n g ( ) ) ;
r e t u rn pageData . g e t H t m l ( ) ;
}

Versteh en Sie die Funktion nach drei Minuten Studium ? Wah rsch einlich nicht. Es
passiert zu viel auf zu vielen verschiedenen Abstraktionsebenen. Es gibt seltsame
Strings und gelegentlich e Funktionsaufrufe, die mit doppelt versch achtelten i f­
Anweisungen vermengt sind, die durch Flags gesteuert werden.
Doch durch Extrah ieren einiger einfach er Meth oden, einige Umbenennungen und
ein wenig Umstrukturierung konnte ich den Zweck der Funktion in den neun Z ei­
len von Listing 3 . 2 zum Ausdruck bringen. Sch auen Sie, ob Sie das in den näch sten
drei Minuten versteh en können.

Listi ng 3.2: Html U t i l . j ava (nach Refactori ng)


p u b l i c s t a t i c S t r i n g r e n d e r Pag eWi t h S e t u psAndTea rdown s (
PageData p a g e D at a , bool ean i s S u i t e
) t h rows E x c e p t i on {
boo l e a n i sT e s t Page = pageData . h asAtt r i b u t e ( "Tes t " ) ;
i f ( i sTe s t Pa g e ) {
Wi k i Page t e s t Pa g e = pageData . g etWi k i Pag e ( ) ;
S t r i n g B u ffe r n ewPageCo n t e n t = new S t r i n g B u ffe r () ;
i n c l u d e S e t u p Pag e s ( t e s t Pa g e , n ewPag eCon t e n t , i s S u i t e ) ;
n ewPageCo n t e n t . a p p e n d ( p a g e D a t a . g etCon te n t () ) ;
i n c l u d eTe a r d own Pag e s ( t e s t Page , n ewPageCo n t e n t , i s S u i t e ) ;
p a g e D a t a . s e tCon t e n t ( n ewPageCo n t e n t . t o St r i n g ( ) ) ;
}

ret u r n pageData . g etHtml () ;


}

Wenn Sie FitNesse nicht näh er studiert h aben, versteh en Sie wah rsch einlich nicht
alle Details. Dennoch versteh en Sie wah rsch einlich , dass diese Funktion einige
Setup- und Teardown-Seiten in eine Test- Seite einfügt und dann diese Seite i1:
HTIM L darstellt. Wenn Sie JUnit, ein Open- Source-Testwerkzeug für ' _ _
Kapitel 3
F u n kt i o n e n

(www . j u n i t . o rg) , kennen, erkennen Sie wahrscheinlich, dass diese Funktion zu


einem webbasierten Test-Framework gehört. Das stimmt natürlich. Diese Informa­
tionen lassen sich aus Listing 3 . 2 recht leicht erschließen. dagegen sind sie in Listing
3 . 1 ziemlich gut verborgen.
Also: Wodurch wird eine Funktion wie Listing 3.2 leicht lesbar und verstehbar? Wie
können wir den Zweck einer Funktion klar kommunizieren ? Welche Eigenschaften
müssen unsere Funktionen haben, damit ein zufälliger Leser die Art von Programm
erschließen kann, zu der die Funktion gehört?

3.1 Klei n !

Die erste Regel für Funktionen lautet: Funktionen sollten klein sein. Die zweite
Regel für Funktionen lautet: Funktionen sollten noch kleiner sein . Diese Aussage kann
ich nicht weiter begründen. Ich kann keine professionellen Forschungsarbeiten
zitieren, die gezeigt haben, dass sehr kleine Funktionen besser sind. Ich kann Ihnen
allerdings sagen, dass ich in fast vier Jahrzehnten Funktionen aller Größen
geschrieben habe: sehr hässliche 3.ooo Zeilen lange Monster: tonnenweise Funk­
tionen im Bereich von 1 0 0 bis 300 Zeilen; zahlreiche Funktionen . die 20 bis 30 Zei­
len lang waren. Aus dieser Erfahrung habe ich durch Versuch und Irrtum gelernt,
dass Funktionen sehr klein sein sollten.
In den 8oer-Jahren pflegten wir zu sagen, dass eine Funktion nicht länger als eine
Bildschirmseite sein sollte. Allerdings waren damals unsere VT10o-Bildschirme 24
Zeilen hoch und 8o Spalten breit; und unsere Editoren brauchten vier Zeilen für
administrative Zwecke. Heute könnten Sie mit einem kleinen Font und einem schö­
nen großen Monitor 150 Zeichen in einer Zeile und etwa 100 Zeilen oder mehr auf
einem Bildschirm unterbringen. Zeilen sollten nicht länger als 150 Zeichen sein.
Funktionen sollten nicht länger als 100 Zeilen sein. Funktionen sollten kaum
jemals länger als 20 Zeilen sein.
Wie kurz sollte eine Funktion sein? 1 9 9 9 besuchte ich Kent Beck zu Hause in Ore­
gon. Wir setzten uns zusammen und programmierten ein wenig. Irgendwann
zeigte er mir ein hübsches kleines JavajSwing-Programm, das er Sparkle nannte. Es
produzierte auf dem Bildschirm einen visuellen Effekt, der dem Feenstaub ähnelte,
den der Zauberstab der Feenmutter aus dem Märchen-Zeichentrickfilm Aschen­
puttel von Walt Disney versprühte. Wenn man die Maus bewegte. lösten sich die
Staubkörnchen mit einem befriedigenden Funkeln vom Cursor und fielen dann
durch ein simuliertes Gravitationsfeld auf den »Boden« des Fensters. Als Kent mir
den Code zeigte, war ich überrascht, wie viele kleine Funktionen der Code enthielt.
Ich war an die Funktionen in Swing-Programmen gewöhnt. die vertikal sehr viel
Platz beanspruchten. Jede Funktion in Becks Programm war nur zwei oder drei oder
vier Zeilen lang. Jede hat einen klar erkennbaren Zweck. Jede erzählte eine
Geschichte. Und eine Funktion führte zwangsläufig zur nächsten. Das Programm
zeigt eindringlich, wie kurz Ihre Funktionen sein sollten! Ich habe Kent gefragt, ob
3 -2
E i n e Aufg abe e rfü l l e n

er noch eine Kopie dieses Programms hätte; leider konnte er keine finden. Ich habe
auch alle meine alten Computer durchsucht. Leider ebenfalls vergeblich. Ich habe
nur noch meine Erinnerung an dieses Programm.
Wie kurz sollten Ihre Funktionen sein? Normalerweise sollten sie kürzer sein als
Listing 3-2 ! Tatsächlich sollte Listing 3-2 zu Listing 3·3 verkürzt werden.

listi ng 3.3: Html U t i l . j ava (nach erneutem Refactori ng)


p u b l i c s t a t i c S t r i n g r e n d e r Pag eWi t h S e t u psAn dTea rdown s (
PageData pageData , bool e a n i s S u i t e ) t h rows E x c e p t i on {
i f ( i sTe s t P ag e ( pageData) )
i n c l u de S e t u pAndTe a r down P a g e s ( pageData , i s S u i t e ) ;
r et u r n pageDat a . g e t H tm1 () ;
}

B l öc ke u nd E i n rücku n gen

Dies bedeutet auch, dass die Blöcke innerhalb von i f-, e 1 se-, w h i 1 e- und ähnlichen
Anweisungen eine Zeile lang sein sollten. Wahrscheinlich sollte diese Zeile einen
Funktionsaufruf enthalten. Dadurch wird nicht nur der Umfang der einschließen­
den Funktion kleiner gehalten, sondern auch ihr dokumentarischer Wert erhöht,
weil die Funktionsaufrufe innerhalb der Blöcke aussagestarke beschreibende
Namen haben können.
Dies bedeutet auch, dass Funktionen nicht groß genug sind, um verschachtelte
Strukturen aufzunehmen. Deshalb sollte die Einrückungstiefe einer Funktion nicht
größer als eine oder zwei Ebenen sein. Dadurch wird es natürlich leichter, die Funk­
tionen zu lesen und zu verstehen.

3.2 E i n e Aufga be erfü l le n

Aus Listing 3 - 1 sollte ganz klar hervorgehen, dass die Funktion sehr viel mehr als
eine Aufgabe erfüllt. Sie erstellt Puffer, ruft Seiten ab, sucht nach geerbten Seiten,
setzt Pfade zusammen, hängt geheime Strings an, generiert HTM L u.a. Die Funk­
tion in Listing 3- 1 ist stark damit beschäftigt, zahlreiche verschiedene Aufgaben zu
erfüllen. Andererseits erfüllt die Funktion in Listing 3 ·3 eine einfache Aufgabe. Sie
fügt Setups und Teardowns in Testseiten ein.
Der folgende Rat wird in der ein oder anderen Form seit über 30 Jahren ausgespro­
chen:
Funktionen sollten eine Aufgabe erledigen. Sie sollten sie gut erledigen. Sie soll­
ten nur diese Aufgabe erledigen.
Dieser Rat ist in einer Hinsicht problematisch: Es ist schwer zu erkennen, was »eine
Aufgabe« ist. Erledigt Listing 3 · 3 eine Aufgabe ? Man könnte leicht begründen, dass
sie drei Aufgaben erfüllt:
Kapitel 3
F u n kt i o n e n

1. Sie bestimmt, ob die Seite eine Testseite ist.


2. Falls ja, schließt sie Setups und Teardowns ein.
3 · Sie stellt die Seite in HTML dar.
Was ist denn nun richtig? Erledigt die Funktion eine Aufgabe oder drei Aufgaben?
Beachten Sie, dass die drei Schritte der Funktion eine Abstraktionsebene unter dem
Zweck liegen, der durch den Namen der Funktion ausgedrückt wird. Wir können
die Funktion beschreiben, indem wir sie mit einem kurzen TO-Absatz (UM-ZU­
Absatz) beschreiben:
TO Rende rPageWi thSetupsAndTea rdowns, prüfen wir, ob die Seite eine
Testseite ist, und wenn dies der Fall ist, schließen wir die Setups und Teardowns
ein. In beiden Fällen stellen wir die Seite in HTML dar.
Die Technik ist der Programmiersprache LOGO entlehnt. In LOGO wurde das
Schlüsselwort TO in derselben Art und Weise verwendet wie d e f in Ruby oder
Python. Deshalb begann jede Funktion mit dem Schlüsselwort TO. Dies hatte eine
interessante Auswirkung auf das Design von Funktionen.
Wenn eine Funktion nur solche Schritte ausführt, die eine Abstraktionsebene unter
dem im Namen der Funktion ausgedrückten Zweck liegen, dann erledigt die Funk­
tion eine Aufgabe. Schließlich besteht der Grund, warum wir Funktionen schreiben,
darin, dass wir ein größeres Konzept (anders ausgedrückt: den Namen der Funktion)
in einen Satz von Schritten auf der nächsttieferen Abstraktionsebene zerlegen.
Es sollte klar sein. dass Listing 3 - 1 Schritte aufi vielen verschiedenen Abstraktions­
ebenen enthält. Deshalb erfüllt die Funktion zweifellos mehr als eine Aufgabe. Sogar
Listing 3 - 2 enthält zwei Abstraktionsebenen. Wir konnten dies durch unsere Fähig­
keit beweisen, die Funktion zu verkürzen. Aber es wäre sehr schwer. Listing 3 · 3 sinn­
voll zu verkleinern. Wir könnten die i f-Anweisung in eine Funktion namens
i n c 1 u d e S e t u p sAndTe a rdown s i fTe s t Page extrahieren, aber damit würde nur der
Code unter einem neuen Namen an eine andere Stelle verlagert. ohne die Abstrak­
tionsebene zu ändern.
Damit haben Sie eine andere Methode, zu erkennen, dass eine Funktion mehr als
»eine Aufgabe« erfüllt: wenn Sie aus ihr eine andere Funktion mit einem Namen
extrahieren können, der nicht nur eine Neuformulierung ihrer Implementierung
ist [G34] .

Absc h n itte i n nerh a l b von Fu n ktionen

Blättern Sie vor zu Listing 4·7 im folgenden Kapitel. Beachten Sie. dass die Funktion
g e n e r a t e P r i mes in Abschnitte unterteilt ist, wie etwa dedarations, initializations
und sieve. Dies ist offensichtlich ein Symptom dafür, dass sie mehr als eine Aufgabe
erfüllt. Funktionen, die eine Aufgabe erledigen, können nicht \"ernünftigerweise in
Abschnitte zerlegt werden.

66
3·3
E i n e Abstra kti o n s e b e n e p ro F u n kt i o n

3·3 E i n e Abstra ktionsebene p ro Fu n ktion

Wenn unsere Funktionen »(nur) eine Aufgabe« erledigen sollen, müssen sich die
Anweisungen innerhalb unserer Funktion alle auf derselben Abstraktionsebene
befinden. Es ist einfach zu sehen, wie Listing 3 - 1 gegen diese Regel verstößt. Die
Funktion enthält Konzepte, die auf einer sehr hohen Abstraktionsebene angesiedelt
sind, wie etwa g e t H tm l () ; andere befinden sich auf mittleren Abstraktionsebenen,
wie etwa: St r i ng pag e Pat h N ame Pat h Pa r s e r . r e n d e r ( pag e Pat h ) ; und wieder
=

andere sind auf einer bemerkenswert tiefen Ebene angesiedelt, wie etwa:
. append ( " \n " ) .
Abstraktionsebenen innerhalb einer Funktion zu vermischen, ist immer verwir­
rend. Möglicherweise können die Leser nicht erkennen, ob ein spezieller Ausdruck
ein wesentliches Konzept oder ein Detail ist. Noch schlimmer: Ähnlich wie ein zer­
brochenes Fenster den Verfall einleitet, führen Details, die mit wesentlichen Kon­
zepten vermischt sind, dazu, dass die Funktion im Laufe der Zeit immer mehr
Details anzieht.

Code Top-down lese n : d i e Stepdow n - Regel

Code sollte wie eine Erzählung von oben nach unten gelesen werden können
([KP78], S. 37) . Danach sollten hinter jeder Funktion andere Funktionen auf der
nächsttieferen Abstraktionsebene stehen, damit wir das Programm lesen können,
indem wir jeweils eine Abstraktionsebene tiefer gehen, wenn wir die Liste der Funk­
tionen von oben nach unten lesen. Ich bezeichne dies als die Stepdown-Regel (»eine
Treppe runtergehen«) .
Anders ausgedrückt: Wir sollten das Programm wie eine Folge von UM-Z U-Absät­
zen lesen können, die jeweils die gegenwärtige Abstraktionsebene beschreiben und
die eine Abstraktionsebene tiefer liegenden UM-Z U-Absätze referenzieren.
Um die Setups und Teardowns einzuschließen, schließen wir Setups ein, dann
schließen wir den Inhalt der Testseite ein, und dann schließen wir die Tear­
downs ein.
Um die Setups einzuschließen, schließen wir das Suite-Setup ein, wenn dies
eine Suite ist; dann schliqsen wir das normale Setup ein.
Um das Suite-Setup einzuschließen, durchsuchen wir die Parent-Hierarchie
nach der »Suite Set Up«-Seite und fügen eine »include«-Anweisung mit dem
Pfad dieser Seite hinzu.
Um die Parent-Hierarchie . . .
Es hat sich gezeigt, dass Programmierer nur sehr schwer lernen, diese Regel zu
befolgen und Funktionen zu schreiben, die auf einer einzigen Abstraktionsebene
bleiben. Doch diese Technik beherrschen zu lernen, ist ebenfalls sehr wichtig. Sie
ist der Schlüssel dazu, kurze Funktionen zu schreiben, die »eine Aufgabe« erfüllen
Kapitel 3
F u n kt i o n e n

Den Code so zu strukturieren, dass er wie ein Top-down-Satz von UM-Z U-Absätzen
gelesen werden kann, ist eine wirksame Technik, um das Abstraktionsniveau kon­
sistent zu halten.
Betrachten Sie Listing 3 ·7 am Ende dieses Kapitels. Es zeigt, wie ein Refactoring der
kompletten tes tabl eHtml -Funktion nach den hier beschriebenen Prinzipien
durchgeführt wurde. Beachten Sie, wie j ede Funktion die nächste einführt, und jede
Funktion auf einer konsistenten Abstraktionsebene bleibt.

3 ·4 Switch -Anwei s u n gen

Es ist schwer, kleine swi t c h -Anweisungen zu schreiben. (Das gilt natürlich auch
für i fIe l s e-Ketten.) Selbst eine swi t c h -Anweisung mit nur zwei Fällen ist größer,
als ein einziger Block oder eine Funktion für meinen Geschmack sein sollte. Es ist
ebenfalls schwer, eine swi t c h-Anweisung zu schreiben, die nur eine Aufgabe
erfüllt. Von Natur aus sind swi t c h-Anweisungen immer auf N Aufgaben ausgelegt.
Leider können wir swi t c h-Anweisungen nicht immer vermeiden, aber wir können
dafür sorgen, dass jede swi t c h-Anweisung tief in einer niedrig angesiedelten
Klasse vergraben ist und niemals wiederholt wird. Wir verwenden zu diesem Zweck
natürlich den Polymorphismus.
Betrachten Sie Listing 3 + Es zeigt nur eine der Operationen . die vom Typ des Mit­
arbeiters abhängen könnten.

Listing 3 .4: Payrol l . j ava


p u b l i c M o n e y c a l c u l ate Pay ( Em p l o ye e e)
t h rows I nval i d Em p l oyeeTyp e {
swi t c h ( e . t y p e ) {
c a s e COMM I S S IONED :
r et u rn c a l c u l at eCommi s s i o n e d Pay ( e ) ;
c a s e HOU R LY :
r e t u rn c a l c u l a t e Ho u r l y Pay ( e ) ;
c a s e SALARI ED :
r e t u rn c a l c u l a t e S a l a r i e d Pay ( e ) ;
defaul t :
t h row n ew I n v a l i d Em p l oyeeTy p e ( e . t y p e ) ;
}
}

Bei dieser Funktion gibt es mehrere Probleme:


• Erstens: Sie ist groß; und wenn neue Mitarbeiter-Typen hinzugefügt werden,
wird sie noch größer.
• Zweitens: Sie erfüllt mehr als eine Aufgabe.
• Drittens: Sie verstößt gegen das Single-Responsibility-Prinzip (SRP), weil es
mehr als einen Grund für eine Änderung gibt; siehe:

68
H
Switch-Anwe i s u n ge n

h t t p : //en . wi ki p e d i a . o rg/wi ki /Si n g l e_ r e s p on s i b i l i ty_p ri n c i p l e,


h t t p : //www . obj ectme n to r . com/ r e s o u r c e s j a r t i c l e s / s rp . p d f

• Viertens : Sie verstößt gegen das Open-Closed-Prinzip (OCP) , weil sie geändert
werden muss , wenn ein neuer Typ hinzugefügt wird; siehe:
h t t p : //en . wi ki p e d i a . o rg/wi ki /Open_c l o s ed_p r i n c i p l e,
h t t p : //www . obj e c tmento r . com/ r e s o u r c e s j a r t i c l e s /o c p . pd f

• Fünftens: Doch möglicherweise am schlimmsten ist es, dass es eine unbe­


grenzte Anzahl anderer Funktionen mit derselben Struktur gibt. So könnten
wir beispielsweise die Funktion

i s Payday ( E m p l oyee e , Date d a t e ) ,

oder

d e l i ve r Pay ( E m p l oyee e , Mo n e y pay) ,

oder zahlreiche andere haben, die alle dieselbe schädliche Struktur hätten.
Die Lösung für dieses Problem (siehe Listing 3-5) besteht darin, die swi t c h -Anwei­
sung in den Keller einer Abstract Factory [GOF] zu verbannen und niemals von
jemandem sehen zu lassen. Die Factory erstellt anhand der swi t c h-Anweisung die
entsprechenden Instanzen der abgeleiteten Klassen von Emp l oyee. Die verschiede­
nen Funktionen, wie etwa c a l c u l atePay, i s Payday und d e l i ve r Pay, werden
polymorph von dem E m p l o yee -lnterface an die richtige Stelle dirigiert.

Listi ng 3-5: Employee u nd Factory


p u b l i c abs t r a c t c l a s s Empl oyee {
p u b l i c a b s t r a c t bool e a n i s Payd a y ( ) ;
p u b l i c a b s t r a c t M o n e y cal c u l ate Pay ( ) ;
p u b l i c a b s t ra c t voi d d e l i ve r Pay (Mo n e y pay) ;
}

p u b l i c i n t e rface Empl o y e e F a c t o r y {
p u b l i c E m pl oyee m a k e E m p l oyee ( E m p l o y e e R e co rd r) t h rows I n va l i d E m p l oyeeType ;
}

p u b l i c c l a s s E m p l o y e e F a c t o r y i m p l i mp l e m e n t s E mp l oyee Fac t o r y {
p u b l i c Emp l oyee make Emp l oyee ( Em p l oyeeReco r d r) t h rows I nva l i d E m p l o y e eType {
swi t c h ( r . t y p e ) {
c a s e COMM I S SIONED :
r e t u r n new Commi s s i o n e d Em p l o ye e ( r)
c a s e HOU R LY :
r e t u r n new Hou r l yEmpl oyee ( r ) ;
c a s e SALARI ED :
r e t u r n new S a l a r i ed Em p l oye ( r ) ;
d e fau l t :
t h row n ew I n v a l i d E m p l oyeeType ( r . ty p e ) ;
Kapitel 3
F u n kt i o n e n

}
}
}

Meine allgemeine Regel für swi t c h -Anweisungen lautet: Sie können toleriert wer­
den, wenn sie nur einmal auftauchen, zur Erstellung polymorpher Objekte verwen­
det werden und hinter einer Vererbungsbeziehung verborgen werden, damit sie für
den Rest des Systems unsichtbar sind [G23] . Natürlich ist jeder Fall einzigartig; und
es gibt Gelegenheiten, bei denen ich gegen einen oder mehrere Teile dieser Regel
verstoße.

3·5 Besch rei bende N a m e n verwe n d e n

In Listing 3 ·7 habe ich den Namen unserer Beispielfunktion von te s t a b l e H t m l in


S e t u pTea rdown i n c l u d e r . r e n d e r geändert. Dieser Name ist erheblich besser,
weil er die Aktion der Funktion besser beschreibt. Ich habe auch alle privaten Metho­
den mit gleichermaßen beschreibenden Namen versehen, wie etwa i sTe s t a b l e
oder i n c l u d e S et u pAn dTe a r down Pag e s . Es ist schwer, den Wert guter Namen zu
überschätzen. Erinnern Sie sich an Wards Prinzip: »Sie erkennen, dass Sie mit sau­
berem Code arbeiten. wen njede Routine im Wesentlichen das tut, was Sie erwartet haben. «
Die halbe Schlacht im Kampf um die Realisierung dieses Prinzips besteht darin,
gute Namen für kleine Funktionen zu finden, die eine Aufgabe erledigen. Je kleiner
und fokussierter eine Funktion ist, desto leichter finden Sie einen beschreibenden
Namen.
Haben Sie keine Angst vor langen Namen. Ein langer beschreibender Name ist bes­
ser als ein kurzer geheimnisvoller Name. Ein langer beschreibender Name ist bes­
ser als ein langer beschreibender Kommentar. Verwenden Sie eine
Namenskonvention. die die Unterscheidung mehrerer Wörter in Funktionsnamen
leicht macht. Nutzen Sie dann diese mehreren Wörter, um der Funktion einen
Namen zu geben. der beschreibt, was sie tut.
Haben Sie keine Angst davor, sich Zeit für die Auswahl eines Namens zu nehmen.
Tatsächlich sollten Sie mehrere Namen ausprobieren und den Code probehalber
mit ihnen lesen. Bei modernen IDEs wie Eclipse oder IntelliJ ist es trivial, Namen
zu ändern. Arbeiten Sie mit einer dieser I D E s und probieren Sie verschiedene
Namen aus, bis Sie einen finden, der so beschreibend wie möglich ist.
Beschreibende Namen verhelfen Ihnen in Ihrer Vorstellung zu einem klareren Bild
des Designs des Moduls und helfen Ihnen, es zu verbessern. Es ist nicht ungewöhn­
lich, dass die Suche nach einem guten Namen zu einer vorteilhaften Umstruktu­
rierung des Codes führt.
Vergeben Sie Namen konsistent. Verwenden Sie dieselben Ausdrücke, Substantive
und Verben in den Funktionsnamen, die Sie für Ihre Module wählen. Betrachten
Sie beispielsweise die !\amen i n c l u d e S e t u pA n dTe a r down Pag e s , i n c l u d e S e t u p -

]0
3-6
F u n kt i o n s a r g u m ente

Pag e s , i n c l u d e S u i t e S e t u pPage und i n c l u d e S e t u p Page. Wegen der ähnlichen


Ausdrücke in diesen Namen kann diese Aufreihung eine Geschichte erzählen. Tat­
sächlich könnten Sie, wenn ich Ihnen nur die obige Folge von Namen zeigen würde,
sich fragen: »Was ist mit i n c l u d eTea rdown Pag e s , i n c l u d e S u i t eTe a rdown Page
und i ncl u d eTe a rdown Page passiert?« Wäre das nicht ein Beispiel für » ... im
Wesentlichen das, was Sie erwartet haben«?

3.6 Fu n ktio n s a rgu m e nte

Die ideale Anzahl von Argumenten für eine Funktion ist null (niladisch) . Als Nächs­
tes kommt eins (monadisch) , dicht gefolgt von zwei (dyadisch) . Drei Argumente (tri­
adisch) sollten, wenn möglich, vermieden werden. Mehr als drei (polyadisch)
erfordert eine sehr spezielle Begründung - und sollte dann trotzdem nicht benutzt
werden.
Argumente sind schwer. Sie erfordern eine beträchtliche konzeptionelle Kraft. Des­
halb habe ich in dem Beispiel fast keine Argumente verwendet. Betrachten Sie etwa
den S t r i n g ß u ffe r in dem Beispiel. Wir hätten ihn als Argument herumreichen
können, anstatt ihn zu einer Instanzvariablen zu machen, aber dann hätte der Leser
ihn jedes Mal interpretieren müssen, wenn er ihn gesehen hätte. Wenn Sie die
Geschichte lesen, die von dem Modul erzählt wird, ist i n c l u d e S et u p Page () leich­
ter zu verstehen als i n c l u d e S et u p Pa g e l n t o ( n ewPageCon t e n t ) . Das Argument
befindet sich auf einer anderen Abstraktionsebene als der Funktionsname und
zwingt Sie, ein Detail (anders ausgedrückt: S t r i n g ß u ffe r) zu kennen, das an die­
sem Punkt nicht besonders wichtig ist.
Vom Gesichtspunkt des Testens aus sind Argumente noch schwieriger. Stellen Sie
sich vor, wie schwierig es ist, alle Testfälle zu schreiben, um zu gewährleisten, dass
alle verschiedenen Kombinationen von Argumenten korrekt funktionieren. Gibt es
keine Argumente, ist diese Aufgabe trivial. Bei einem Argument ist es nicht zu
schwer. Bei zwei Argumenten wird die Lösung des Problems etwas schwieriger. Bei
mehr als zwei Argumenten kann das Testen aller Kombinationen von entsprechen­
den Werten eine Riesenaufgabe sein.
Output-Argumente sind schwerer zu verstehen als Input-Argumente. Wenn wir
eine Funktion lesen, sind wir an die Idee gewöhnt, dass Informationen als Argu­
mente in die Funktion hineingehen und als Rückgabewert aus der Funktion her­
auskommen. Normalerweise erwarten wir nicht, dass Informationen durch die
Argumente herauskommen. Deshalb müssen wir bei Output-Argumenten oft dop­
pelt hinschauen.
Ein Input-Argument ist nach null Argumenten die nächstbeste Variante. S e t u p ­
Te a r down l n c l u d e r . r e n d e r ( p a g e Data) ist ziemlich leicht z u verstehen. Daraus
geht klar hervor, dass wir die Daten in dem pageDat a-Obj ekt darstellen werden.
Kapitel 3
F u n kt i o n e n

Gebrä u c h l iche m o n ad ische Formen

Es gibt zwei sehr verbreitete Gründe, ein einziges Argument an eine Funktion zu
übergeben. Sie können eine Frage über das Argument stellen, wie etwa in boo l ean
fi l e E x i s t s ( " My F i l e " ) . Oder Sie möchten das Argument manipulieren, etwa
indem Sie es in etwas anderes umwandeln und dann zurückgeben. Beispielsweise
wandelt I n p u t St ream fi l eüpen ( " My Fi l e " ) einen Dateinamens-St r i n g in einen
I n p u t S t r e am -Rückgabewert um. Diese beiden Anwendungen werden von dem
Leser erwartet, wenn sie eine Funktion sehen. Sie sollten Namen wählen, die diesen
Unterschied deutlich machen, und die beiden Formen immer in einem konsisten­
ten Kontext verwenden (siehe den Abschnitt Anweisung und Abfrage trennen etwas
später) .
Eine etwas weniger gebräuchliche, aber immer noch sehr nützliche Form einer
Funktion mit einem einzigen Argument ist ein Event (Ereignis) . Diese Form hat ein
Input-Argument, aber kein Output-Argument. Das übergreifende Programm soll
die Funktionsaufrufe als Events interpretieren und mit dem Argument den Zustand
des Systems verändern, beispielsweise voi d pas swo r dAttem p t F a i l e d N ­
t i mes C i n t attempt s ) . Verwenden Sie diese Form mit Bedacht. Es sollte für den
Leser ganz deutlich sein, dass dies ein Event ist. Wählen Sie Namen und Kontexte
sorgfältig.
Verwenden Sie möglichst keine monadische Funktionen, die nicht eine dieser For­
men verwenden, beispielsweise voi d i n c l u d e S e t u p Pag e i n to ( S t ri n g ß u ffe r
pageTex t) . Ein Output-Argument anstelle eines Rückgabewerts für eine Transfor­
mation zu verwenden, ist verwirrend. Wenn eine Funktion ihr Input-Argument
transformiert, sollte die Transformation als Rückgabewert zurückgegeben werden.
Tatsächlich ist St ri n g ß u ffe r t ra n s fo rm ( S t ri n g ß u ffe r i n ) besser als voi d
t r a n s fo rm- ( S t r i n g ß u ffe r o u t ) , selbst wenn die Implementierung im ersten
Fall einfach das Input-Argument zurückgibt. Wenigstens folgt sie immer noch der
Form einer Transformation.

Fl ag-Argu m e nte

Flag-Argumente sind hässlich. Ein boolesches Argument an eine Funktion zu über­


geben, ist eine wirklich schreckliche Technik. Es verkompliziert sofort die Signatur
der Methode und gibt laut und deutlich zu verstehen, dass diese Funktion mehr als
eine Aufgabe erfüllt: eine, wenn das Flag wahr ist, und eine andere, wenn es falsch
ist!
In Listing 3·7 hatten wir keine Wahl, weil die Aufrufer bereits dieses Flag übergeben
hatten und ich den Umfang des Refactorings aufdie Funktion und tiefer begrenzen
wollte. Dennoch ist der Methodenaufruf r e n d e r ( t r u e ) für einen armen Leser ein­
fach nur verwirrend. Mit der Maus über den Aufruf zu fahren und r e n d e r ( boo l ean
i s S u i te) zu sehen, hilft nicht allzu viel. Wir hätten die Funktion in zwei zerlegen
sollen: r e n d e r Fo r S u i t e ( ) und r e n d e r Fo r S i n g l eTe s t ( ) .

72
3·6
F u n kt i o n s a r g u m e n te

Dyad ische Fu n ktionen

Eine Funktion mit zwei Argumenten ist schwerer zu verstehen als eine monadische
Funktion. Beispielsweise ist w r i t e F i e l d ( n am e ) leichter zu verstehen als w r i t e ­
F i e l d ( o u t p u t S t ream , n am e ) . (Ich habe gerade das Refactoring eines Moduls
durchgeführt, das eine dyadische Form verwendete. Ich konnte den o u t p u t S t r e am
zu einem Feld der Klasse machen und alle w r i t e F i e l d-Aufrufe in eine monadische
Form umwandeln. Das Ergebnis war viel sauberer.) Obwohl die Bedeutung der bei­
den Argumente klar ist, liest man leicht über das erste hinweg und verpasst seine
Bedeutung. Das zweite Argument erfordert eine kurze Pause, bis wir gelernt haben,
den ersten Parameter zu ignorieren. Und das führt natürlich zu Problemen, weil wir
niemals irgendeinen Teil des Codes ignorieren sollten. Die Teile, die wir ignorieren,
sind die Stellen, an denen sich die Bugs verbergen.
Manchmal sind natürlich zwei Argumente die passende Lösung. Beispielsweise ist
an Poi n t p n ew Poi n t (0 , 0) ; überhaupt nichts auszusetzen. Kartesische Koor­
=

dinaten erfordern von Natur aus zwei Argumente. Tatsächlich wären wir sehr über­
rascht, n ew Poi n t (O) zu sehen. Doch die beiden Argumente sind in diesem Fall
geordnete Komponenten eines einzigen Werts! Dagegen haben o u t p u t S t r e am und
n ame weder eine natürliche Kohäsion noch eine natürliche Reihenfolge.

Selbst offensichtlich dyadische Funktionen wie a s s e r t Eq u a l s ( e x p e c t e d ,


a c t u a l ) sind problematisch. Wie oft haben Sie das a c t u a l an die Stelle gesetzt, an
der e x p e c t e d stehen sollte? Die beiden Argumente haben keine natürliche Reihen­
folge. Die Reihenfolge e x p e c t e d , a c t u a l ist eine Konvention, die durch Übung
gelernt werden muss.
Dyaden sind kein Übel, und Sie werden sie sicher schreiben müssen. Doch Sie soll­
ten wissen, dass sie mit gewissen Kosten verbunden sind und Sie sollten jede Mög­
lichkeit nutzen, sie in Monaden umzuwandeln. Beispielsweise könnten Sie die
w r i t e F i e l d-Methode zu einem Element von o u t p u t S t ream machen, damit Sie
o u t p u t S t ream . w r i t e F i e l d ( n am e ) sagen können. Oder Sie könnten o u t p u t ­
St ream z u einer Member-Variablen der gegenwärtigen Klasse machen, damit Sie
ihn nicht übergeben müssen. Oder Sie könnten eine neue Klasse wie Fi e l dWri t e r
extrahieren, die den o u t p u t S t r e am in ihrem Konstruktor übernimmt und über
eine w r i te-Methode verfügt.

Triaden

Funktionen, die drei Argumente übernehmen, sind erheblich schwerer zu verste­


hen als Dyaden. Die Probleme, zum Beispiel der Reihenfolge, des mehrmaligen
Lesens und des Übersehens, werden mehr als verdoppelt. Ich rate Ihnen, sehr sorg­
faltig nachzudenken, bevor Sie eine Triade erstellen.
Betrachten Sie beispielsweise die gebräuchliche Überladung der Funktion von
a s s e r t E q u a l s , die drei Argumente übernimmt: a s s e r t E q u a l s ( m e s s a g e ,
e x p e c ted , a c t u a l ) . Wie oft haben Sie m e s s ag e gelesen und gedacht, es wäre

73
Kapitel 3
F u n kt i o n e n

e x p e c t e d ? Ich bin sehr oft über diese Triade gestolpert und musste mehrfach nach­
lesen. Tatsächlich schaue ichjedes Mal, wenn ich sie sehe, doppelt nach und ignoriere
dann die Nachricht.
Andererseits gibt es auch Triaden, die nicht ganz so tückisch sind: as s e r t ­
E q u a l s ( 1 . 0 , amo u n t , . 001) . Obwohl Sie auch hier doppelt hinschauen müssen,
lohnt es in diesem Fall. Es ist immer gut, daran erinnert zu werden, dass die Gleich­
heit von Fließkommawerten eine relative Sache ist.

Argu m e nt-Objekte

Wenn eine Funktion anscheinend mehr als zwei oder drei Argumente benötigt, ist
es wahrscheinlich, dass einige dieser Argumente in eine separate Klasse eingehüllt
werden sollten. Betrachten Sie beispielsweise den Unterschied zwischen den bei­
den folgenden Deklarationen:

Ci r c l e m a k e C i r c l e ( d o u b l e x , d o u b l e y , d o u b l e radi u s ) ;
C i r c l e makeCi r c l e ( Poi n t c e n t e r , d o u b l e r a d i u s ) ;

Die Anzahl der Argumente zu reduzieren, indem daraus Obj ekte erstellt werden,
mag wie Schummelei aussehen, ist es aber nicht. Wenn Gruppen von Variablen
zusammen übergeben werden, wie etwa x und y in dem obigen Beispiel, gehören
sie wahrscheinlich zu einem Konzept, das einen eigenen Namen haben sollte.

Argu ment- Li ste n

Manchmal wollen wir eine Yariable Anzahl von Argumenten an eine Funktion über­
geben. Betrachten Sie beispielsweise die Methode St r i n g . fo rmat:

S t r i n g . fo rmat ( "� s v. o r ke d % . 2 f h o u r s . " , name , h o u r s ) ;

Wenn die variablen Argumente alle identisch behandelt werden. wie in dem obigen
Beispiel, dann entsprechen sie einem einzigen Argument vom Typ L i s t . Folgt man
dieser Auffassung, ist St r i ng . fo rmat faktisch dyadisch. Tatsächlich ist die fol­
gende Deklaration von St r i n g . fo rmat deutlich dyadisch.

p u b l i c S t r i n g fo rmat ( S t r i n g format , O b j e c t . . . a rg s )

Deshalb gelten alle entsprechenden Regeln. Funktionen, die eine Yariable Anzahl
von Argumenten übernehmen, können Monaden, Dyaden oder sogar Triaden sein.
Aber es wäre ein Fehler, ihnen noch mehr Argumente zu übergeben.

voi d mo n a d ( I nt e g e r . . . a rg s ) ;
voi d dyad ( S t ri n g name , I n t e g e r . . . a r g s ) ;
voi d t r i ad ( S t r i n g name , i n t cou n t , I n t eg e r . . . a rg s ) :

74
3-7
N e b e n effekte ve r m e i d e n

Verben u n d Sch l ü sselwörter

Ein guter Name für eine Funktion kann sehr viel dazu beitragen, den Zweck der
Funktion und die Reihenfolge und den Zweck der Argumente zu erklären. Bei einer
Monade sollten Funktion und Argument ein aussagestarkes Verb/ Substantiv-Paar
bilden. Beispielsweise erklärt sich w r i te ( n ame) von selbst. Was immer » n ame« sein
mag, es wird »geschrieben«. Möglicherweise wäre ein Name wie w r i t e ­
F i e l d ( n ame) noch besser, weil e r uns zugleich sagt, dass der » n ame« ein »Feld« ist.
Diese letzte Variante ist ein Beispiel für die Schlüsselwort-Form eines Funktionsna­
mens . Bei dieser Form codieren wir die Namen der Argumente in den Funktions­
namen. Beispielsweise könnte a s s e r t E q u a l s besser als a s s e r t E x p e c t e d E q u a l s
A c t u a l ( e x p e c t e d , a c t u a l ) geschrieben werden. Dadurch wird das Problem, sich
die Reihenfolge der Argumente merken zu müssen, erheblich geringer.

3·7 N eben effekte vermeiden

Nebeneffekte sind Lügen. Ihre Funktion verspricht, eine Aufgabe zu erfüllen, aber
sie erledigt auch andere verborgene Aufgaben. Manchmal führt sie unerwartete
Änderungen an Variablen ihrer eigenen Klasse durch. Manchmal macht sie daraus
Parameter, die an die Funktion übergeben werden, oder System-Globals. In jedem
Fall sind sie unaufrichtige und schädigende Falschheiten, die oft zu seltsamen zeit­
lichen Kopplungen und anderen Abhängigkeiten führen.
Betrachten Sie beispielsweise die anscheinend unverfängliche Funktion in Listing
3 . 6 . Diese Funktion verwendet einen Standardalgorithmus, um einen u s e r N am e
mit einem p a s s wa r d abzugleichen. Bei einem Treffer gibt sie t r u e zurück, andern­
falls fa l s e . Aber sie hat auch einen Nebeneffekt Können Sie ihn entdecken?

Listi ng 3.6: Use rVal i dator . j ava


p u b l i c c l a s s U s e rVa l i d a t o r {
p r i vat e C ry p t o g r a p h e r c ryptog r a p h e r ;

p u b l i c boo l ean c h e c k Pa s s wo rd ( S t r i n g u s e rName , S t r i n g p a s s wo rd ) {


U s e r u s e r = U s e rGat eway . fi n d ByName ( u s e rName) ;
i f (user ! = Use r . NULL) {
S t ri n g c o d e d P h r a s e=u s e r . g e t P h r as e E n co d e d B y P a s swo rd ( ) ;
S t ri n g p h r a s e = c ryptog r a p h e r . d e c rypt ( c o d e d P h r a s e , pas swo rd ) ;
i f ( " Val i d Pas swo rd " . eq u a l s ( p h r a s e ) ) {
S e s s i on . i n i t i al i ze () ;
r e t u rn t r u e ;
}
}
r e t u r n fal s e ;
}
}

75
Kapitel 3
F u n kt i o n e n

Der Nebeneffekt ist natürlich der Aufrufvon S e s s i on . i ni t i a l i z e () . Die c h e c k ­


Passw o rd -Funktion sagt laut Name, dass sie Passwörter prüft. Der Name impliziert
nicht, dass sie die Sitzung initialisiert. Deshalb läuft ein Aufrufer, der glaubt, was
der Name der Funktion sagt, Gefahr, die vorhandenen Sitzungsdaten zu löschen,
wenn er die Validität des Benutzers prüfen will.
Dieser Nebeneffekt erzeugt eine zeitliche Kopplung. Das heißt, c h e c kPas swa rd
kann nur zu bestimmten Zeiten aufgerufen werden (anders ausgedrückt: wenn es
sicher ist, die Sitzung zu initialisieren) . Wenn die Funktion nicht zum normalen
Zeitpunkt aufgerufen wird, können Sitzungsdaten versehentlich verloren gehen.
Zeitliche Kopplungen sind verwirrend, besonders wenn sie als Nebeneffekt verbor­
gen sind. Wenn Sie eine zeitliche Kopplung brauchen, sollten Sie dies im Namen
der Funktion klar zum Ausdruck bringen. In diesem Fall könnten wir die Funktion
in c h e c kPas swo rdAn d i n i ti al i z e S e s s i on umbenennen, obwohl dies sicherlich
gegen »Tue eine Aufgabe« verstößt.

Outp ut-Argu m ente

Argumente werden auf natürlichste Weise als Inputs einer Funktion interpretiert.
Wenn Sie schon länger programmieren, haben Sie sicher schon Argumente näher
analysiert, die tatsächlich nicht als Input, sondern als Output verwendet wurden. Ein
Beispiel:

a p p e n d Foot e r ( s ) ;

Hängt diese Funktion s als Fußzeile an etwas an? Oder hängt sie eine Fußzeile an
s an? Ist s ein Input oder ein Output? Es dauert nicht lange, sich die Funktionssi­
gnatur anzuschauen:

p u b l i c vo i d a p p e n d Foot e r ( S t r i n g B u ffe r r e p o r t )

Damit wird die Frage geklärt, aber nur auf Kosten der Prüfung der Funktionsdekla­
ration. Alles, was Sie zwingt, die Funktionssignatur zu prüfen. ist gleichwertig mit
einem zweimaligen Nachschauen. Es ist eine kognitive Unterbrechung und sollte
vermieden werden.
Vor dem Aufkommen der objektorientierten Programmierung musste man manch­
mal Output-Argumente verwenden. Doch in 00-Sprachen werden Output-Argu­
mente weitgehend überflüssig, weil es eine Aufgabe von t h i s ist, als Output­
Argument zu agieren. Anders ausgedrückt: Es wäre besser. wenn appe n d Foote r
wie folgt aufgerufen werden würde:

r e po r t . a p p e n d Foote r ( ) ;

Im Allgemeinen sollten Sie keine Output-Argumente verwenden. Wenn Ihre Funk­


tion den Status einer Komponente ändern muss, sollte sie den Status des Eigentü­
merobjekts ändern.
3 ·8
Anwei s u n g u n d Abfra g e tre n n e n

3.8 Anwei s u n g u n d Abfrage tren n e n

Funktionen sollten entweder etwas tun oder etwas antworten, aber nicht beides. Ent­
weder sollte Ihre Funktion des Status eines Objekts ändern oder sie sollte Informa­
tionen über das Objekt zurückgeben. Beides zu tun, führt oft zu Verwirrung.
Betrachten Sie beispielsweise die folgende Funktion:

p u b l i c bool e a n s e t ( St r i n g at t r i b u t e , S t r·i n g val u e ) ;

Diese Funktion setzt den Wert eines benannten Attributs und gibt t r u e zurück,
wenn dies erfolgreich ist, und fa l s e , wenn kein solches Attribut existiert. Dies führt
zu seltsamen Anweisungen wie dieser:

i f ( s e t ( " u s e r n ame " , " u n c l e b o b " ) ) . . .

Betrachten Sie dies aus der Sicht des Lesers. Was bedeutet dies? Fragt die Anwei­
sung, ob das » u s e r n ame«-Attribut vorher aufi » U n e l ebob« gesetzt war? Oder fragt
sie, ob das » U s e r n ame«-Attribut erfolgreich auf » U n e l e bob« gesetzt worden ist? Es
ist schwer, die Bedeutung aus dem Aufruf abzuleiten, weil nicht klar ist, ob das Wort
»S et« ein Verb oder ein Adjektiv ist.
Für den Autor sollte s e t ein Verb sein, aber im Kontext der i f-Anweisungfohlt sich
das Wort wie ein Adjektiv an. Deshalb bedeutet sie: »Wenn das u s e r n ame-Attribut
vorher auf u n c l ebob gesetzt war . . . « und nicht »Setze das u s e r n ame-Attribut auf
u n c l ebob und falls dies funktioniert, dann . . . «. Wir könnten versuchen, dieses Pro­
blem zu beseitigen, indem wir die s et-Funktion in s etAn d C h e c kifExi s t s umbe­
nennen, aber das hilft dem Leser der i f-Anweisung auch nicht viel weiter. Die
richtige Lösung besteht darin, die Anweisung von der Abfrage zu trennen, damit die
Mehrdeutigkeit nicht auftreten kann.

i f ( a t t r i b u t e E x i s t s ( " u s e r n ame " ) ) {


s e tAtt r i b u t e ( " u s e r n ame " , " u n c l ebob " ) ;

3·9 Au s n a h m e n s i n d besser a l s Fe h l er-Cod es

Fehler-Codes von Befehlen zurückzugeben, ist eine subtile Verletzung der Anwei­
sung-Abfrage-Trennung. Diese Technik fördert den Gebrauch von Anweisungen als
Ausdrücke in den Prädikaten von i f-Anweisungen.

i f ( d e l e t e P ag e ( pa g e ) == E_OK)

77
Kapitel 3
F u n kt i o n e n

Diese Anweisung leidet nicht unter der Verb f Adjektiv-Verwechslung, führt aber zu
tief verschachtelten Strukturen. Wenn Sie einen Fehler-Code zurückgeben, schaf­
fen Sie das Problem, dass der Aufrufer den Fehler sofort behandeln muss.

i f ( d e 1 e t e Page ( p a g e ) E_OK) {
==

i f ( r e g i s t ry . d e 1 e t e Refe r e n c e ( p a g e . n ame) == E_OK) {


i f ( c o n f i g Ke y s . de 1 e t e K e y ( pa g e . n ame . makeKey ( ) ) == E_OK) {
1 og g e r . 1 og ( " pa g e d e 1 e t e d " ) ;
} e1 se {
1 og g e r . 1 og ( " co n f i g Key not d e 1 e t ed " ) ;
}
} e1 se {
1 og g e r . l og ( " d e 1 e t e Refe r e n c e f ro� r eg i s t r y fai 1 ed " ) ;
}
} e1 se {
1 og g e r . 1 og ( " d e1 e t e fai l e d " ) ;
r e t u r n E_E RROR ;
}

Wenn Sie dagegen Ausnahmen anstelle von Fehler-Codes \·erwenden, dann können
Sie den Code für die Fehler-Verarbeitung von dem Code des Normalverlaufs tren­
nen und sehr vereinfachen:

t ry {
d e l e t e Pa g e ( p a g e ) ;
r e g i s t r y . d e 1 e t e R e fe re n ce ( pa g e . n ame) :
confi g K e y s . d e 1 e t e K e y ( p a g e . n ame . m a k e K e : )-
}
c a t c h ( E x c e pt i o n e ) {
1 og g e r . 1 og (e . g e t Me s s ag e ( ) ) ;
}

TryJCatc h - B i öcke extra h i eren

T ry/c at c h - Blöcke sind von Natur aus hässlich . S : e .::::- .::.::.keln die Struktur des
-•

Codes und vermengen die Fehler-Verarbeitung :::: : :.,o::- :1 : :-malen Verarbeitung.


Deshalb ist es besser, die Körper der t ry- und catc � - :: :(üe ::1 separate Funktionen
zu extrahieren.

p u b l i c voi d d e 1 e t e ( Pa g e p a g e ) {
t ry {
d e 1 e t e PageAndA1 1 Refe r e n c e s ( p a g e ) ;
}
c a t c h ( Ex c e pt i on e) {
l og E r ro r ( e ) ;
}
}

p r i vate voi d d e 1 e t e PageAndAl 1 Re f e r e n ce s ( Pag e = � =�


3·9
Au s n a h m e n s i n d bes s er a l s F e h l er-Codes

t h rows E x c e pt i on {
d e l e t e P a g e ( pa g e ) ;
r e g i s t r y . d e l e t e Re f e r e n c e ( p age . n ame) ;
c o n f i g K e y s . d e l e t e Key ( p a g e . n ame . m a k e Key () ) ;
}

p r i vate voi d l og E r ro r ( E x c e pt i on e) {
l og g e r . l og ( e . g e t Me s s ag e ( ) ) ;
}

In dem obigen Code hat die de l ete-Funktion die Aufgabe der Fehler-Verarbeitung.
Man kann sie einfach verstehen und dann ignorieren. Die Funktion de l e t e ­
PageAndA l l Refe r e n c e s hat nur die Aufgabe, eine page komplett z u löschen. Die
Fehler-Verarbeitung kann ignoriert werden. Damit haben wir eine saubere Tren­
nung, die es erleichtert, den Code zu verstehen und zu ändern.

Feh l er-Vera rbeitu n g i st e i n e Aufgabe

Funktionen sollten eine Aufgabe erfüllen. Fehler-Verarbeitung ist eine Aufgabe.


Deshalb sollte eine Funktion, die Fehler verarbeitet, nichts anderes tun. Dies imp­
liziert (wie in dem obigen Beispiel) Folgendes : Wenn eine Funktion das Schlüssel­
wort t ry enthält, sollte es das allererste Wort in der Funktion sein und nach den
catc h/fi na l l y-Blöcken sollte nichts anderes stehen.

Der A b h ä n gi gkeits m agnet Error.j ava

Fehler-Codes zurückzugeben, bedeutet normalerweise auch, dass es eine Klasse


oder e n u m gibt, in der alle Fehler-Codes definiert sind.

p u b l i c e n u m E r ro r {
OK ,
I NVAL ID ,
NO_SUCH ,
LOCKED ,
OUT_OF_R ESOU RC E S ,
WAITING_FOR_EVENT ;
}

Klassen wie diese sind ein Abhängigkeitsmagnet; viele andere Klassen müssen sie
importieren und verwenden. Wird e n u m E r ro r geändert, ist eine Neukompilierung
und ein Redeployment all dieser anderen Klassen erforderlich. Dies übt einen nega­
tiven Druck auf die E r ro r-Klasse aus . Programmierer wollen keine neuen Fehler
hinzufügen, weil sie dann alles neu erstellen und ausliefern müssen. Deshalb wie­
derverwenden sie alte Fehler-Codes, anstatt neue hinzuzufügen.
Wenn Sie nicht mit Fehler-Codes, sondern mit Ausnahmen arbeiten, dann sind
neue Ausnahmen abgeleitete Klassen der Excepti on-Klasse (Ausnahme- Klasse) . Sie
Kapitel 3
F u n kt i o n e n

können sie hinzufügen, ohne dass eine Neukompilierung und ein Redeployment
erforderlich sind. Dies ist ein Beispiel für das Open-Closed-Prinzip (OCP) [PP Po2] .

3.1 0 Do n 't Repeat Yo u rself

Don't-Repeat-Yourself-Prinzip (DRY:; »Wiederhole dich nicht!«; [PRAG]) . Wenn Sie


sich Listing p weiter vorne noch einmal sorgfältig anschauen, stellen Sie fest, dass
ein Algorithmus vier Mal wiederholt wird, einmal für jeden Fall von S e t U p , S u i t e ­
S e t U p , Tea rDown und S u i teTea rDow n . Es ist nicht leicht, diese Duplizierung zu
erkennen, weil die vier Instanzen mit anderem Code vermischt sind und nicht ein­
heitlich dupliziert werden. Dennoch ist die Duplizierung ein Problem, weil sie den
Code aufbläht und eine vierfache Änderung erfordert, sollte der Algorithmus jemals
geändert werden müssen. Außerdem bietet er vier Mal die Gelegenheit für Auslas­
sungsfehler.
Diese Duplizierung wurde durch die i n c l ude-Methode in Listing 3·7 behoben.
Lesen Sie diesen Code noch einmal und achten Sie darauf, wie die Lesbarkeit des
gesamten Moduls durch die Verringerung dieser Duplizierung verbessert wird.
Möglicherweise ist die Duplizierung die Wurzel allen Übels bei der Software-Ent­
wicklung. Viele Prinzipien und Techniken wurden zu dem Zweck entwickelt, sie zu
kontrollieren oder zu eliminieren. Beispielsweise dienen alle Datenbank-Normal­
formen von Codd dazu, die Duplizierung von Daten zu eliminieren. Bei der objekt­
orientierten Programmierung bemüht man sich darum, andernfalls redundanten
Code in Basisklassen zu konzentrieren. Bei der Strukturierten Programmierung,
der Aspektorientierten Programmierung, der Komponentenorientierten Program­
mierung geht es immer auch um Strategien, Duplizierung zu eliminieren. Man
könnte sagen, dass alle Innovationen in Software-Entwicklung seit der Erfindung
der Subroutine ein fortlaufender Versuch sind, Duplizierung in unserem Source­
code zu eliminieren.

3.1 1 Stru ktu rierte Progra m m ieru n g

Einige Programmierer befolgen die Regeln der Strukturierten Programmierung


von Edsger Dijkstra [ S P72] . Dijkstra sagte, dass jede Funktion und i eder Block inner­
halb einer Funktion einen Eingang und einen Ausgang haben solle. Diesen Regeln
entsprechend sollte eine Funktion nur eine r e t u r n-Anweisung. keine b reak- oder
c o n t i n u e-Anweisungen in einer Schleife und niemals. wirklich niemals, goto­
Anweisungen enthalten.
Obwohl wir den Zielen und Techniken der Strukturierten Programmierung wohl­
wollend gegenüberstehen, bieten diese Regeln wenig Vorteile . wenn Funktionen
sehr klein sind. Nur bei größeren Funktionen können Sie durch solche Regeln
beträchtliche Vorteile erzielen.

8o
3. 1 2
W i e sch reibt m a n s o l c h e F u n kt i o n e n ?

Wenn Sie also Ihre Funktionen klein halten, dann richtet eine gelegentliche Anwen­
dung von mehreren r e t u rn-, b reak- oder c o n t i n u e-Anweisungen keinen Schaden
an und kann den Code manchmal ausdrucksstärker machen als die Ein-Eingang­
ein-Ausgang-Regel. Andererseits lässt sich goto nur bei großen Funktionen sinn­
voll einsetzen und sollte deshalb vermieden werden.

3.1 2 Wie sch re i bt m a n solche Fu n ktio n e n ?

Software zu schreiben, ist wie jede andere Art des Schreibens. Wenn Sie einen Auf­
satz oder einen Artikel schreiben, notieren Sie zunächst Ihre Gedanken, dann ord­
nen Sie sie, bis sie sich gut lesen lassen. Der erste Entwurfi mag unbeholfen und
unstrukturiert wirken, weshalb Sie ihn umformulieren und umstrukturieren wer­
den, bis er Ihren Vorstellungen entspricht.
Wenn ich Funktionen schreibe, sind sie zunächst lang und kompliziert. Sie haben
viele Einrückungen und verschachtelte Schleifen. Sie haben lange Argumentenlis­
ten. Die Namen sind willkürlich, und es gibt duplizierten Code. Aber ich verfüge
ebenfalls über eine Suite von Unit-Tests, die alle diese umständlichen Code-Zeilen
testen.
Dann massiere und verfeinere ich den Code, lagere Funktionen aus, ändere Namen
und eliminiere Duplizierungen. Ich verkleinere die Methoden und stelle sie um.
Manchmal breche ich ganze Klassen heraus, während ich gleichzeitig dafür sorge,
dass die Tests bestanden werden.
Schließlich folgen meine Funktionen den Regeln, die ich in diesem Kapitel
beschrieben habe. Ich schreibe sie nicht in dieser Form, wenn ich anfange. Ich
glaube nicht, dass dies irgendj emand könnte.

3.1 3 Z u sa m m e nfass u n g

Jedes System wird mit einer domänenspezifischen Sprache konzipiert, die von dem
Programmierer konzipiert wird, um das System zu beschreiben. Funktionen sind
die Verben dieser Sprache, und Klassen sind die Substantive. Dies ist kein Rück­
schritt zu der scheußlichen alten Auffassung, die Substantive und die Verben in
einem Anforderungsdokument lieferten die ersten Anhaltspunkte für die in einem
System benötigten Klassen und Funktionen. Stattdes sen kommt hier eine viel ältere
Wahrheit zum Ausdruck. Die Kunst der Programmierung ist und war immer die
Kunst des Sprachen-Designs.
Meister-Programmierer betrachten Systeme nicht als Programme, die geschrieben
werden müssen, sondern als Geschichten, die erzählt werden wollen. Sie verwen­
den die Fähigkeiten der von ihnen gewählten Programmiersprache, um eine viel
reichhaltigere und ausdrucksstärkere Sprache zu konstruieren, mit der diese
Geschichte erzählt werden kann. Ein Teil dieser domänenspezifischen Sprache wird

81
Kapitel 3
F u n kt i o n e n

von einer Hierarchie von Funktionen gebildet, die alle Aktionen beschreiben, die
innerhalb des Systems ausgeführt werden. In einer kunstvollen Rekursion werden
diese Aktionen so geschrieben, dass sie in derselben domänenspezifischen Spra­
che, die sie definieren, ihren eigenen kleinen Teil der Geschichte erzählen.
Dieses Kapitel behandelt die handwerklichen Fähigkeiten, um gute Funktionen zu
schreiben. Wenn Sie die Regeln aus diesem Kapitel befolgen, werden Ihre Funkti­
onen kurz sein, geeignete Namen haben und sauber strukturiert sein. Sie dürfen
aber niemals vergessen, das s Ihr eigentliches Ziel darin besteht, die Geschichte des
Systems zu erzählen, und dass Ihre Funktionen sauber zusammenpassen und in
einer klaren und präzisen Sprache geschrieben sein müssen, um Ihre Erzählung zu
unterstützen.

3.14 Setu pTeardown l ncl uder

Listi ng 3.7: SetupTea rdownlncl ude r . j ava


p a c k a g e fi t n e s s e . h t m l ;

i mpo r t fi t n e s s e . r e s po n d e r s . r u n . Su i t e R e s po n d e r ;
i mpo r t fi t n e s s e . wi ki . * ;

p u b l i c c l a s s S e t u pTe a r down l n c l u d e r {
p r i vate PageData p a g e D at a ;
p r i vate bool e a n i s S u i t e ;
p r i vate Wi ki Page t e s t Page ;
p r i vate S t r i n g B u ffe r n ewPageCon t e n t ;
p r i vate PageC r awl e r pageC r awl e r ;

p u b l i c s t at i c S t r i n g r e n d e r ( Pag e D a t a page Data) t h rows E x c e p t i on {


re t u r n r e n d e r ( p a g e D at a , fal s e ) ;
}

p u b l i c s t a t i c S t r i n g r e n d e r ( PageData p a g e D at a , bool e a n i s S u i t e )
t h rows E x c e pt i on {
r e t u r n new S e t u pTe a rdown l n c l u d e r ( pageData) . r e n d e r ( i s S u i t e ) ;
}

p r i vate S e t u pTe a rd own l n c l u de r ( PageData pageData) {


t h i s . pageData pageDat a ;
=

t e s t Page =pageData . g e tWi k i Pag e ( ) ;


pageC r awl e r t e s t Page . g e t PageC r awl e r ( ) ;
=

n ewPageCo n t e n t n ew S t r i n g B u ffe r ( ) ;
=

p r i vate S t r i n g r e n d e r ( bool e a n i s S u i t e ) t h rows Exc e p t i on {


t h i s . i s S u i te i s Sui te ;
=

i f ( i sTe s t Page ( ) )
3-14
Setu pTeardow n l ncl u d e r

i n c l u d e S e t u pAndTe a r down Pag e s ( ) ;


r e t u r n pageData . g e t H t m l ( ) ;
}

p r i vate boo l e a n i sTe s t Page ( ) t h rows E x c e p t i on {


r e t u rn pageData . h asAtt r i b u t e ( "Te s t " ) ;
}

p r i vate voi d i n c l u d e S e t u pAndTe a rdown Pag e s ( ) t h rows E x c e p t i o n {


i nc l udeSetupPages () ;
i n c l u d e PageCo n te n t ( ) ;
i n c l udeTe a rdown Pag e s ( ) ;
u pd a te PageCo n te n t ( ) ;
}

p r i vate voi d i n c l u d e S e t u p Pag e s ( ) t h rows E x c e p t i on {


i f (i s S u i t e )
i n cl udeSui teSetu pPage () ;
i n c l u d e S e t u p Pa g e ( ) ;
}

p r i vate voi d i n c l u d e S u i t e S e t u p Page ( ) t h rows E x c e pt i on {


i n c l u d e ( S u i t e R e s p o n d e r . S U ITE_S ETU P_NAM E , " - s e t u p " ) ;
}

p r i vate voi d i n c l u d e S e t u p Pag e ( ) t h rows E x c e pt i on {


i n cl ude ( " SetUp" , " - s e t u p " ) ;
}

p r i vate voi d i n c l u d e PageCon te n t ( ) t h rows E x c e pt i on {


n ewPageCon t e n t . a p p e n d ( pag e D at a . g etConte n t () ) ;
}

p r i vate voi d i n c l u d eTe a rdown Pag e s ( ) t h rows E x c e p t i o n {


i n c l udeTe a rdown Page ( ) ;
i f (i sSui te)
i n cl u d e S u i teTe a r d own Page ( ) ;
}

p r i vate voi d i n c l u d eTe a r down Pag e ( ) t h rows E x c e p t i on {


i n c l u d e ( " Te a rDown " , " - t e a rdown " ) ;
}

p r i vate voi d i n c l u d e S u i teTe a rdown Page ( ) t h rows E x c e pt i on {


i n c l u d e ( S u i t e R e s p o n d e r . S U I TE_TEARDOWN_NAM E , " - te a rdown " ) ;
}

p r i vate voi d u pd a t e PageCon t e n t ( ) t h rows Exce p t i on {


pageData . s e t Co n te n t ( n ewPageCo n t e n t . toSt r i n g () ) ;
Kapitel 3
F u n kt i o n e n

p r i vate voi d i n c l u d e ( S t r i n g p a g e N am e , S t r i n g a rg ) t h rows E x c e pt i o n {


Wi k i Page i n h e r i t e d Page = fi n d l n h e r i t e d Page ( p a g e N a m e ) ;
i f ( i n h e r i t e d Page ! = n u l l ) {
S t r i n g pag e P a t h Name = g e t P a t h N am e Fo r P a g e ( i n h e r i t e d P a g e ) ;
b u i l d l n c l u d e D i r e c t i ve ( p a g e P a t h N ame , a rg ) ;
}
}

p r i vate Wi k i Page f i n d l n h e r i t e d Page ( St r i n g pageName) t h rows E x c e p t i on {


r e t u r n PageC rawl e rl m p l . g e t l n h e r i t e d P ag e ( p a g e N ame , t e s t P a g e ) ;
}

p r i v a t e S t r i n g g e t P a t h N ame Fo r Pa g e (Wi k i Page pag e ) t h rows E x c e pt i on {


Wi k i P a g e P a t h pag e P a t h = pageC r awl e r . g e t F u l l P at h ( pa g e ) ;
r e t u r n Pat h Pa r s e r . r e n d e r ( p a g e Pat h ) ;
}

p r i vate voi d b u i l d l n c l u d e D i r e c t i ve ( S t r i n g p ag e P a t h N ame , S t r i n g a rg ) {


n ewPageCo n t e n t
. ap p e n d ( " \ n ! i n c l u d e " )
. ap p e n d ( a r g )
. ap p e n d ( " . " )
. ap p e n d (page P a t h N am e )
. ap p e n d ( " \n " ) ;
}
}
Kapitel 4

Kom mentare

»Kommentieren Sie schlechten Code nicht - schreiben Sie ihn um.«


- Brian W Kernighan und P. ]. Plaugher

Nichts kann so hilfreich sein wie ein wohlplatzierter Kommentar. Nichts kann ein
Modul mehr zumüllen als leichtfertige dogmatische Kommentare. Nichts kann so
viel Schaden anrichten wie ein alter überholter Kommentar, der Lügen und Fehlin·
formationen verbreitet.
Kommentare sind nicht wie Schindlers Liste. Sie sind nicht »das reine Gute«. Tat­
sächlich sind Kommentare bestenfalls ein erforderliches Übel. Wären unsere Pro­
grammiersprachen ausdrucksstark genug oder hätten wir genügend Talent, unsere
Absichten in den vorhandenen Sprachen immer klar genug auszudrücken, wir wür­
den wohl kaum Kommentare brauchen.
Der angemessene Einsatz von Kommentaren soll unsere Unfähigkeit ausgleichen,
uns in unserem Code klar auszudrücken. Beachten Sie das Wort Unfähigkeit. Genau
das meine ich. Kommentare sind immer ein Zeichen der Unfähigkeit. Wir brau­
chen sie, da es uns nicht immer gelingt herauszufinden, wie wir uns ohne sie aus­
drücken können. Doch ein Kommentar ist kein Grund zum Feiern.
Wenn Sie also einen Kommentar schreiben müssen, sollten Sie vorher überlegen,
ob Sie sich nicht doch noch in Ihrem Code besser ausdrücken könnten. Jedes Mal,
wenn Sie sich in Ihrem Code ausdrücken können, können Sie stolz auf sich sein.
Jedes Mal, wenn Sie einen Kommentar schreiben, sollten Sie sich mangelnder Aus­
drucksfähigkeit im Code bewusst sein.

Bs
Kapitel 4
Ko m m e ntare

Warum schätze ich Kommentare so gering? Weil sie lügen. Nicht immer und nicht
absichtlich, aber zu oft. Je älter ein Kommentar ist und je weiter er von dem Code
entfernt ist, den er beschreibt, desto wahrscheinlicher ist er einfach falsch. Der
Grund ist simpel. Realistisch betrachtet, können Programmierer Kommentare
nicht warten.
Code ändert und entwickelt sich. Teile des Codes werden von hier nach da verscho­
ben. Die Teile verzweigen, reproduzieren und vereinigen sich wieder und werden
zu Schimären. Leider folgen die Kommentare ihnen nicht immer - sie können ihnen
nicht immer folgen. Und allzu oft werden die Kommentare von dem Code getrennt,
den sie beschreiben, und verwaisen als immer ungenauer werdende »Waschzettel«.
Betrachten Sie beispielsweise das Schicksal des folgenden Kommentars und der
Zeile, die er beschreiben sollte:

Mec kR e q u e s t req u e s t ;
p r i vate fi n a l S t r i n g HTT P_DATE_REGEXP =

" [ SMTWF] [ a - z ] { 2 } \\ , \\ s [ 0 - 9 ] { 2 } \\ s [ J FMA S OND] [ a- z ] { 2 } \\s " +


" [ 0 - 9 ] { 4 } \\ s [ 0 - 9 ] { 2 } \\ : [ 0 - 9 ] { 2 } \\ : [ 0 - 9 ] { 2 }\\s G"!T " :
p r i vate R e s p o n s e r e s pon s e ;
p r i vate F i t N e s s eCon t e x t c o n t e x t ;
p r i vate F i l e Re s po n d e r r e s po n d e r ;
p r i vate L o c a l e s a v e l o c a l e ;
II Exampl e : "Tue , 02 Apr 2003 2 2 : 1 8 : 4 9 GMT '

Wahrscheinlich wurden später andere Instanznf.ablen zv.ischen der Konstanten


HTT P DAT E REGEXP und ihrem erklärenden Kommenta: emgefügt.
_ _

Natürlich könnte man fordern, dass Programmierer d1szipliniert genug sein soll­
ten, Kommentare immer zu aktualisieren, zu korrigieren usw. Ich stimme zu; sie
sollten. Aber mir wäre es lieber, sie würden diese Energ:e aufu-enden, um den Code
so klar und ausdrucksstark zu formulieren, dass er -u be:-�au.pt keine Kommentare
benötigt.
Ungenaue Kommentare sind viel schlimmer als gar i. e : :1 e r\.o!!lmentare. Sie führen
in die Irre. Sie wecken Erwartungen, die niemals erft.L: weden. Sie schreiben alte
Regeln fest, die nicht mehr befolgt werden müssen oce:- ;o-�a:- nicht mehr befolgt
werden sollten.
Die Wahrheit kann nur an einer Stelle gefunden wercie:::.� ::n Code. Nur der Code
kann wirklich sagen, was er tut. Er ist die einzige QueiJe ::.�:- ""'1rklich genaue Infor­
mationen. Deshalb sollten wir, auch wenn Kommen�:-e :-:-1anchmal erforderlich
sind, uns anstrengen, um sie zu minimieren.

4.1 Ko m me nta re s i n d kei n E rsatz fü r s c h l ec h te n Cod e

Einer der häufigeren Gründe, Kommentare zu schreibe: _ :s: s chlechter Code. Wir
schreiben ein Modul und wir wissen, dass es verwirre::c -_;:._� schlecht strukturiert

86
4- 2
Er k l ä re n S i e i m u n d d u rch d e n Cod e

ist. Wir wissen, dass es ein Chaos ist. Deshalb sagen wir uns: »Oh, das muss ich aber
kommentieren!« Nein! Sie müssen Ihren Code säubern!
Klarer und ausdrucksstarker Code mit wenigen Kommentaren ist viel besser als
unordentlicher und komplexer Code mit zahlreichen Kommentaren. Anstatt Ihre
Zeit mit dem Schreiben von Kommentaren zu verbringen, die Ihr Chaos erklären,
sollten Sie sie darauf verwenden, das Chaos zu beseitigen.

4.2 Erkläre n Sie i m u n d d u rc h d e n Code

Manchmal ist Code sicher kein gutes Medium für Erklärungen. Leider deuten viele
Programmierer dies so um, dass Code selten, falls überhaupt, ein gutes Medium für
Erklärungen ist. Dies ist grundfalsch. Was würden Sie lieber lesen? Dies:

II C h e c k to s e e i f t h e e m p l oyee i s e l i g i b l e fo r f u l l b e n efi t s
i f ( ( em pl oyee . fl a g s & HOURLY_F LAG) &&
( e m p l oyee . ag e > 6 5 ) )

Oder dies?

i f ( e m p l oyee . i s E l i g i b l e Fo r Fu l l B e n e f i t s ( ) )

I n Deutsch etwa:

II P r ü f e n , ob d e r Mi t a r b e i t e r al l e B e n e f i t s be kommen s o l l
i f ( ( e m p l oyee . fl ag s & HOURLY_F LAG) &&
( e m p l oyee . ag e > 65) )

Oder dies?

i f ( e m p l oyee . so l l Al l e B e n efi t s B e komm e n ( ) )

Meistens muss man nur wenige Sekunden nachdenken, um den Zweck durch den
Code auszudrücken. In vielen Fällen reicht es einfach, eine Funktion zu erstellen,
die dasselbe aussagt wie der Kommentar, den Sie schreiben wollen.

4·3 G ute Kom m e nta re

Einige Kommentare sind notwendig oder vorteilhaft. Es folgen einige, die meiner
Meinung die Bits wert sind, die sie verbrauchen. Denken Sie jedoch daran, dass der
einzig wirklich gute Kommentar der ist, den Sie nicht schreiben müssen.

J u risti sche Ko m m e ntare

Manchmal zwingen uns die Codierstandards unseres Unternehmens, bestimmte


Kommentare aus juristischen Gründen zu schreiben. Beispielsweise sind CopY-
Kapitel 4
Ko m m entare

right- und Autoren-Vermerke am Anfang aller Quelldateien oft notwendige und ver­
nünftige Angaben.
Hier ist beispielsweise der standardmäßige Kommentar-Header, den wir am
Anfang jeder Quelldatei in FitNesse einfügen. Glücklicherweise verbirgt unsere
I D E diesen Kommentar, so dass er nicht den Bildschirm verunstaltet.

II Copy r i g h t (C) 2003 , 2004 , 200 5 by Obj ect Mento r , I n c . Al l ri g h t s rese rved .
II Rel eased u n d e r t h e te rms of t h e GNU Gene ral Publ i c Li c e n s e ve r s i on 2 or l at e r .

Derartige Kommentare sollten keine langen Verträge oder Ähnliches enthalten.


Wenn möglich, sollten Sie auf eine Standardlizenz oder ein anderes externes Doku­
ment verweisen, anstatt alle Bedingungen in den Kommentar einzufügen.

I nform ierende Ko m mentare

Manchmal ist es nützlich, grundlegende Informationen in einem Kommentar mit­


zuteilen. So erklärt etwa der folgende Kommentar den Rückgabewert einer abstrak­
ten Methode:

II Gi bt ei ne Ins tanz des getesteten Res ponde r s zu rück


p ro t e c t e d a b s t r a c t R e s p an d e r r e s po n d e r l n s t a n c e ( ) ;

Ein derartiger Kommentar kann manchmal nützlich sein; aber es ist besser, die
Information möglichst mit dem Namen der Funktion zu Yermitteln. So könnte etwa
der Kommentar in diesem Fall redundant gemacht werden. indem man die Funk­
tion umbenennt: r e s po n d e r B e i ngTe s t e d .
Hier ist ein etwas besserer Fall:

II Ve r g l e i c h s fo rm a t k k : mm : s s E E E , MMM dd ,
P a t t e r n t i meMat e h e r P a t t e r n . compi l e (
=

" \ \d * : \\ d * : \\d * \\w* , \\w* \\d * , \\d * " ) ;

In diesem Fall teilt uns der Kommentar mit. das s de:- :-eguläre Ausdruck zum
Abgleich eines Ausdrucks mit Datum und Zeit Ye!"l\ e::1cie: werden soll, der mit der
Funktion S i m p l eDate Fo rmat . fo rmat und dem spez:!:z'.e:-ten Format- String for­
matiert worden ist. Dennoch könnte es besser und kla:-er gewesen sein, wenn dieser
Code in eine spezielle Klasse verschoben worden wäre. d:e :".;.:- die Umwandlung der
Formate von Datums- und Zeitangaben zuständig ge'i\ e s e:: wäre. Dann wäre der
Kommentar wahrscheinlich überflüssig gewesen.

E rkläru n g der Absicht

Manchmal liefert ein Kommentar nicht nur nützliche - ::::-: :>r:nationen über die Im­
plementierung, sondern auch über die Gründe hinte:- e::: e :- Entscheidung. Im fol­
genden Fall wird eine interessante Entscheidung c�:-2: einen Kommentar
dokumentiert. Um zwei Objekte zu vergleichen, wollte de: _-\utor sie so sortieren,

88
4·3
G ute K o m m e ntare

dass Objekte seiner Klasse in der Reihenfolge vor den Objekten aller anderen Klas­
sen stehen.

p u b l i c i n t com p a r eTo (Obj e c t o)


{
i f ( o i n s t a n c e o f Wi k i P a g e P at h )
{
Wi ki Pag e Path p =(Wi k i Pag e Pa t h ) o ;
S t r i n g com p r e s s e d N ame =S t r i n g U t i l . j o i n ( n ames , " " ) ;
S t r i n g com p r e s s e d A r g u m e n t N am e= S t r i n g U t i l . j o i n ( p . n ames , " " ) ;
r e t u r n com p r e s s e d N am e . com p a r eTo ( c om p r e s s ed A r g u m e n tName) ;
}
r e t u r n 1 ; II Wi r s i nd größe r , we i l wi r den r i c h t i gen Typ haben .
}

Hier ist ein noch besseres Beispiel. Vielleicht stimmen Sie nicht mit der Problem­
lösung des Programmierers überein, aber wenigstens wissen Sie, was er versuchte.

p u b l i c voi d t e s tCon c u r r e n tAddWi d g e t s ( ) t h rows E x c e p t i on {


Wi d g e t B u i l d e r wi d g e t ß u i l d e r =

n ew Wi d g e t B u i l d e r ( n ew Cl a s s [ ] { Bo l dWi d g e t . c l as s } ) ;
Stri n g text =" ' ' bo l d t e x t ' ' "' ;
'

P a r e n tWi d g e t p a r e n t =

n ew Bol dWi d g e t ( n ew Moc kWi d g e t Root ( ) , " ' ' ' bo 1 d t e x t ' ' ' " ) ;
Atom i cßool e a n fai l Fl ag = n ew Atom i cßool e a n ( ) ;
fai l Fl ag . s e t (fal s e ) ;

II Di es i s t u n s e r bester Versuch , e i ne Race-Cond i t i on


II (Gl e i chze i t i gkei t s bed i ngung) zu e rzeugen ,
II i ndem e i ne große Anzahl von Th reads e rstel l t wi rd .
fo r ( i n t i = 0 ; i < 2 5 000 ; i ++) {
Wi d g e t B u i l d e rTh r e ad wi d g e t B u i l d e rTh r e ad =

n ew Wi d g e t B u i l d e rTh r e ad (wi d g e t B u i l d e r , text , p a r e n t , fai l Fl ag ) ;


Th read t h read =n ew Th read (wi d g e t B u i l d e rTh r e a d ) ;
t h read . s t a r t ( ) ;
}
a s s e r t E q u a l s (fal s e , fai l Fl ag . g e t ( ) ) ;
}

K l a rste l l u n gen

Manchmal ist es einfach hilfreich, die Bedeutung eines obskuren Arguments oder
Rückgabewerts in etwas Lesbares zu übersetzen. Im Allgemeinen ist es besser, eine
Methode zu finden, die das Argument oder den Rückgabewert von sich aus klar macht;
aber wenn sie zu einer Standard-Library gehört oder in Code steht, den Sie nicht
ändern können, dann kann ein hilfreicher klärender Kommentar nützlicher sein.
Natürlich besteht ein beträchtliches Risiko, dass ein klärender Kommentar falsch
ist. So zeigt ein Blick auf das vorhergehende Beispiel, wie schwierig seine Korrekt-
Kapitel 4
Kom m e ntare

p u b l i c voi d t e s tCom p a r eTo ( ) t h rows E x c e p t i on


{
Wi ki Page Path a = P at h P a r s e r . p a r s e ( " PageA " ) ;
Wi ki PagePath ab = Pat h P a r s e r . p a r s e ( " PageA . Pag e B " ) ;
Wi ki Page Path b = Pat h P a r s e r . p a r s e ( " Pag e B " ) ;
Wi ki Page Path aa =Pat h P a r s e r . p a r s e ( " PageA . Pag e A " ) ;
Wi k i Page Path bb = P at h P a r s e r . p a r s e ( " P a g e B . Pag e B " ) ;
Wi ki Page Path ba Pat h P a r s e r . p a r s e ( " P a g e B . PageA " ) ;
=

a s s e r tT r u e ( a . comp a r eTo (a) == 0) ; II a == a


a s s e rtTr u e ( a . comp a r eTo ( b ) ! = 0 ) ; II a ! = b
a s s e r tT r u e (ab . comp a r eTo (ab) == 0) ; II ab == ab
a s s e r tT r u e ( a . comp a r eTo ( b ) == - 1) ; II a < b
a s s e r tT r u e (aa . compa r eTo (ab) == - 1) ; II aa < a b
a s s e r tT r u e ( b a . com p a r eTo ( b b ) == - 1) ; II b a < b b
a s s e rtTr u e ( b . comp a r eTo (a) = = 1) ; II b > a
a s s e r tT r u e (ab . comp a r eTo ( aa) 1) ;
== II ab > aa
a s s e r tT r u e ( b b . comp a r eTo (ba) 1) ;
== II bb > b a
}

heit zu verifizieren ist. Dies erklärt, warum die Klarstellung erforderlich und warum
sie riskant ist. Bevor Sie derartige Kommentare schreiben, sollten Sie deshalb sorg­
faltig prüfen, ob es keine bessere Alternative gibt, und dann noch sorgfaltiger darauf
achten, dass sie korrekt sind.

War n u ngen vor Ko nsequenzen

Manchmal ist es nützlicher, andere Programmierer vor bestimmten Konsequenzen


zu warnen. Beispielsweise erklärt der folgende Kommentar. \Yarum ein spezieller
Testfall abgeschaltet wurde:

II Nu r a u s führen , wenn Si e Zei t tot schl agen wol l e n .


p u b l i c voi d _t e s tWi t h R e a l l yB i g F i l e ( )
{
w r i t e l i n e sTo F i l e ( 10000000) ;
r e s pon s e . s e t Body ( t e s t F i l e) ;
r e s pon s e . r e ad yTo S e n d ( t h i s ) ;
S t r i n g r e s po n s e S t r i n g = o u t p u t . t o St r i n g ( ) ;
as s e r t S u b St r i n g ( " Con t e n t - L e n g t h : 1000000000 " , r e s pon s e S t r i n g ) ;
a s s e r tT r u e (by t e s S e n t > 1000000000 ) ;
}

Heutzutage schalten wir den Testfall natürlich mit einem �I g n o r e Attribut und -

einem entsprechenden aussagekräftigen String ab. @I g n o r e ( " D i e Au s fü h r u n g


d au e r t z u l an g e . " ) . Doch bevor e s J Unit 4 gab, war e s eine \·erbreitete Konven­
tion, ein Unterstreichungszeichen vor den Methodennamen zu setzen. Der Kom­
mentar ist zwar etwas flapsig, drückt aber den Punkt ziemheb gut aus.

90
4·3
G ute Ko m m e nt are

Hier ist ein anderes, treffenderes Beispiel:

p u b l i c s t at i c S i m p l eDate Fo rmat m a ke S t a n d a r d H t t pDate Format ( )


{
II S i mpl eDateFormat i s t n i cht t h read - s i c h e r ;
II deshal b müssen wi r j ede Ins tanz unabhäng i g e r s tel l en .
S i m p l eDate Fo rmat df n ew S i m p l e D a t e F o rmat ( " E E E , d d MMM yyyy H H : mm : s s z " ) ;
=

d f . s etTi meZo n e (Ti meZon e . g e tTi meZo n e ( " GMT " ) ) ;


r e t u rn d f ;
}

Sie könnten einwenden, dass es bessere Methoden zur Lösung dieses Problems
gibt. Ich würde Ihnen vielleicht sogar zustimmen. Aber der hier gezeigte Kommen·
tar ist vernünftig. Er warnt übereifrige Programmierer davor, aus Gründen der Effi·
zienz einen statischen Initialisierer zu verwenden.

TO DO- Ko m m entare

Manchmal ist es vernünftig, »To do«·Yermerke in Form von I /TODO-Kommentaren


in den Code einzufügen. Im folgenden Fall erklärt der TODO· Kommentar, warum die
Funktion eine veraltete Implementierung hat und wie die Funktion in Zukunft aus·
sehen sollte.

II TODO- MdM di es wi rd n i cht benöt i g t


I I Wi r e rwarte n , dass s i e m i t u n s e rem Checkou t - Model l übe r fl ü s s i g wi rd .
p ro t e c t e d Ve r s i o n i n fo makeVe r s i o n ( ) t h rows E x c e pt i o n
{
r e t u rn n u l l ;
}

TODOs sind Aufgaben, die nach Meinung des Programmierers erledigt werden soll·
ten, aber im Moment, aus welchem Grund auch immer, nicht gelöst werden kön·
nen. Es könnte sich um eine Erinnerung handeln, eine veraltete Funktion zu
ändern, oder eine Bitte an einen anderen Entwickler, sich des Problems anzuneh·
men. Es könnte eine Bitte sein, einen besseren Namen zu erfinden, oder eine Erin·
nerung, eine Änderung vorzunehmen, die von einem geplanten Ereignis abhängig
ist. Doch eines ist ein TODO keinesfalls : Es ist keine Entschuldigung dafür, schlechten
Code im System zu lassen.
Heutzutage stellen die meisten guten I D E s spezielle Funktionen zur Verfügung,
um alle TODO-Kommentare zu finden. Deshalb ist es unwahrscheinlich, dass sie ver·
loren gehen. Dennoch sollten Sie Ihren Code nicht mit TODOs verunstalten. Deshalb
sollten Sie Ihren Code regelmäßig durchsuchen und nicht mehr aktuelle TODOs
löschen.

Verstä rku n g

Mit einem Kommentar kann auch die Bedeutung eines Teil des Codes unterstrichen
werden, der andernfalls als unbedeutend angesehen werden könnte.
Kapitel 4
Ko m m e ntare

S t r i n g l i s t i t emCo n t e n t = mat c h . g rou p ( 3 ) . t r i m () ;


II De r t r i m - Be fehl i s t wi rkl i ch w i c h t i g . Er entfernt d i e füh renden
II Lee rze i chen , di e dazu füh ren könnten , dass das El ement al s
II e i ne wei tere L i ste i nterp ret i e rt wi rd .
n ew L i s t i t e mWi d g e t ( t h i s , l i s t i t emCo n t e n t , t h i s . l ev e l + 1) ;
r e t u r n b u i l d l i s t ( t e x t . s u b s t r i n g (mat c h . e n d ( ) ) ) ;

J avadocs i n öffentl i c h e n A P i s

Kaum etwas anderes ist so hilfreich und befriedigend wie ein wohlgeschriebenes
öffentliches API. Die Javadocs für die Standard-Java-Library sind ein Beispiel dafür.
Es wäre bestenfalls schwierig, Java-Programme ohne sie zu schreiben.
Wenn Sie ein öffentliches API schreiben, sollten Sie sicher gute Javadocs dafür
schreiben. Aber Sie sollten dabei an die anderen Empfehlungen in diesem Kapitel
denken. Javadocs können genauso irreführend, nicht-lokal und unehrlich sein wie
andere Kommentare.

4·4 Sc h l echte Ko m m e ntare

Die meisten Kommentare gehören zu dieser Kategorie. Normalerweise handelt es


sich um Krücken oder Entschuldigungen für schlechten Code oder Rechtfertigun­
gen für unzureichende Entscheidungen, die kaum über ein Selbstgespräch des Pro­
grammierers hinausgehen.

Gera u n e

Einen Kommentar nur deshalb einzufügen, weil Sie das Gefühl haben, Sie sollten
dies tun, oder weil der Prozess es erfordert, ist ein Hack. Wenn Sie sich dafür ent­
scheiden, einen Kommentar zu schreiben, sollten Sie die erforderliche Zeit aufwen­
den, um den Ihren Fähigkeiten entsprechend bestmöglichen Kommentar zu
schreiben.
Hier ist beispielsweise ein Fall aus FitNesse, bei dem ein Kommentar möglicher­
weise nützlicher gewesen wäre. Aber der Autor war in Eile oder einfach nur nach­
lässig. Sein »Geraune« hinterließ ein Geheimnis :

p u b l i c voi d l o ad P rope rt i e s ( )
{
t ry
{
S t r i n g p rope r t i e s Pa t h = p ro p e r t i e s lo c at i on + / + P RO P E RT I E S_FI L E ;
" "

F i l e i n p u t S t ream p ro p e r t i e s S t ream = n ew F i l e i n p u t S t r e am ( p ro p e rt i e s Pa t h ) ;
l o aded P rope r t i e s . l oad ( p rop e rt i e s S t r e am) ;
}
c a t c h ( I O E x c e pt i o n e )
{
II No p rope r t i e s fi l es means al l d e fau l t s are l oaded
}
}

92
4-4
Sch l echte Ko m m e ntare

(Deutsche Übersetzung des Kommentars: »Keine Properties-Dateien bedeutet, dass


alle Defaults oder Standardwerte geladen sind oder werden«; nicht eindeutig!) Was
bedeutet der Kommentar in dem c a t c h - Block? Man muss annehmen, dass es für den
Autor etwas bedeutete, doch was, geht kaum klar daraus hervor. Was können wir aus
dem Code schließen? Wenn eine I O E x c e p t i on ausgelöst wird, gab es offensichtlich
keine Properties-Datei; und in diesem Fall werden alle Standardwerte geladen. Aber
wer lädt die Standardwerte? Waren sie bereits vor dem Aufruf von l oad P ro p e r ­
t i e s . l o a d geladen? Oder fangt l oad P ro p e rti e s . l o a d c a t c h die Ausnahme ab,
lädt die Standardwerte und übergeht dann die Ausnahme, so dass wir uns nicht
darum kümmern müssen? Oder hat l oad P ro p e r t i e s . l oad alle Standardwerte
geladen, bevor sie versuchte, die Datei zu laden? Versuchte der Autor nur, sich über
die Tatsache hinwegzumogeln, dass er den cat c h - Elock leer ließ? Oder - und dies
ist die beängstigende Möglichkeit - wollte der Autor sich ermahnen, später an diese
Stelle zurückzukommen und den Code zu schreiben, der die Standardwerte lädt?
Unsere einzige Option besteht darin, den Code in den Teilen des Systems zu stu­
dieren, um herauszufinden, was passiert. Jeder Kommentar, der Sie zwingt, in ande­
ren Modulen nach seiner Bedeutung zu suchen, ist ein gescheiterter
Kommunikationsversuch und die Bits nicht wert, die er konsumiert.

Red u nda nte Kom m entare

Listing 4 - 1 zeigt eine einfache Funktion mit einem Header-Kommentar, der voll­
kommen redundant ist. Den Kommentar zu lesen, dauert wahrscheinlich länger, als
den Code selbst zu lesen.

Listing 4.1 : wai t Fo rC l o s e


I I U t i l i ty met hod t h a t ret u r n s when t h i s . cl osed i s t rue . Th rows a n
I I except i on i f t h e t i meout i s reached .
p u b l i c s y n c h r o n i zed voi d wai t Fo rC l o s e (fi n a l l a n g t i m e o u t M i l l i s )
t h rows E x c e pt i on
{
i f ( ! cl osed)
{
wai t (t i m e o u t M i l l i s ) ;
i f ( ! cl osed)
t h row n ew E x c e pt i on ( " M o c k R e s pon s e Se n d e r co u l d n o t b e c l o s ed " ) ;
}
}

(Übersetzung des Kommentars: »Utility-Methode, die zurückkehrt, wenn


this.closed wahr ist. Löst eine Ausnahme aus , wenn der Timeout erreicht ist.«) Wel­
chen Zweck erfüllt dieser Kommentar? Es ist sicher nicht informativer als der Code.
Weder rechtfertigt er den Code noch nennt er seinen Zweck oder Existenzgrund. Er
ist nicht leichter zu lesen als der Code. Tatsächlich ist er weniger präzise als der Code
und verführt den Leser, diesen Mangel an Präzision zu akzeptieren, anstatt sich zu

93
Kapitel 4
Ko m m entare

bemühen, den Code zu verstehen. Der Kommentar ähnelt einem Gebrauchtwagen­


händler, der Sie mit schönen Worten davon abhalten will, unter die Haube zu
schauen.
Betrachten Sie jetzt die zahlreichen nutzlosen und redundanten Javadocs in Listing
4-2aus Tomcat. Diese Kommentare bewirken nur, dass der Code unübersichtlicher
und unklarer wird. Sie erfüllen gar keinen dokumentarischen Zweck. Um die Sache
schlimmer zu machen: Ich zeige nur die ersten Kommentare. Dieses Modul enthält
zahlreiche weitere.

Listi n g 4.2: Con tai nerBase . j ava (Tomcat)


p u b l i c a b s t ract c l a s s Con t a i n e r B a s e
i m p l e m e n t s Con t a i n e r , L i fe c yc l e , P i p e l i n e ,
M B e a n Reg i s t r ati on , S e r i a l i za b l e {

I**
* T h e p ro c e s s o r d e l ay fo r t h i s compon e n t .
*I
p ro t e c t e d i n t b a c k g rou n d P ro c e s s o r D e l ay = - 1 ;

I* *
* T h e l i fecyc l e e v e n t s u p p o r t fo r t h i s compone n t .
*I
p ro t e c t e d L i fecyc l e S u p p o r t l i fe c y c l e =
n ew L i f e c y c l e S u p po rt ( t h i s ) ;

I**
* T h e c o n t a i n e r e v e n t l i s t e n e r s fo r t h i s C o n t a i n e r .
*I
p ro t e c t e d A r r ay L i s t l i s t e n e rs n ew A r r a y L i s t () ;

I**
* T h e Load e r i m p l e m e n t at i o n wi t h wh i c h t h i s Co n t a i n e r i s
* a s s o c i ated .
*I
p ro t e c t e d Load e r l oad e r = n u l l ;

I**
* T h e L og g e r i m p l eme n t at i o n wi t h w h i c h t h i s Co n t a i n e r i s
* a s s o c i ated .
*I
p ro t e c t e d Log l og g e r = n u l l ;

I* *
* A s s o c i at e d l og g e r n ame .
*I
p ro t e c t e d S t r i n g l ogName = n u l l ;

I**
* T h e M a n ag e r i mp l eme n t at i o n wi t h wh i c h t h i s C o n t a i n e r i s

94
4-4
Sch l echte Ko m m entare

* a s s o c i a ted .
*/
p ro t e c t e d M a n ag e r m a n a g e r = n u l l ;

/* *
* T h e c l u s t e r wi t h wh i ch t h i s C o n t a i n e r i s a s s o c i a t e d .
*/
p ro t e c t e d C l u s t e r c l u s t e r = n u l l ;

!* *
* T h e h u man - r e a d a b l e n am e o f t h i s C o n t a i n e r .
*/
p ro t e c t e d S t r i n g n am e = n u l l ;

/ '' *
* T h e p a r e n t C o n t a i n e r to wh i c h t h i s C o n t a i n e r i s a c h i l d .
*/
p ro t e c t e d C o n t a i n e r p a r e n t = n u l l ;

!* *
* T h e p a r e n t c l a s s l o ade r t o b e c o n f i g u r e d w h e n w e i n s tal l a
* Load e r .
*/
p ro t e c t e d C l a s s loade r p a r e n tC l a s s load e r = n u l l ;

!**
* T h e P i p e l i n e o b j e c t wi t h w h i c h t h i s C o n t a i n e r i s
* a s s o c i a ted .
*/
p ro t e c t e d P i p e l i n e p i p e l i n e = n ew S t a n d a r d P i p e l i n e ( t h i s ) ;

!* *
* T h e Real m wi t h w h i c h t h i s C o n t a i n e r i s a s s o c i a t e d .
*/
p ro t e c t e d Rea l m r e a l m = n u l l ;

/**
* T h e r e s o u r c e s D i r C o n t e x t o b j e c t wi t h wh i c h t h i s Contai n e r
* i s associ ated .
*/
p ro t e c t e d D i rCon t e x t r e s o u r c e s = n u l l ;

I rrefü h rende Ko m m entare

Selbst bei den besten Absichten fügt ein Programmierer manchmal Aussagen in
seine Kommentare ein, die nicht präzise genug sind, um korrekt zu sein. Betrachten
Sie noch einmal den redundanten, doch auch subtil irreführenden Kommentar aus
Listing 4 - r .

95
Kapitel 4
Ko m m e ntare

Haben Sie bemerkt, wo der Kommentar Sie in die Irre führt? Die Methode kehrt
nicht zurück, wenn t h i s . c l o s e d den Wert t r u e annimmt. Sie kehrt zurück, falls
t h i s . c 1 o s e d den Wert t r u e hat; andernfalls wartet sie auf einen blinden Timeout
und löst dann eine Ausnahme aus , falls t h i s . c l o s e d immer noch nicht den Wert
t r u e hat.
Diese subtile Fehlinformation, die in einem Kommentar eingebettet ist, der schwe·
rer zu lesen ist als der Body des Codes selbst, könnte einen anderen Programmierer
veranlassen, die Funktion unbekümmert aufzurufen und zu erwarten, dass sie
zurückkehrt, sobald t h i s . c l o s e d den Wert t r u e annimmt. Dieser arme Program­
mierer würde dann seine Zeit mit Debugging- Sitzungen vergeuden müssen, um
herauszufinden, warum sein Code so langsam ausgeführt wird.

Vorgesch rieben e Ko m m entare

Es ist einfach albern, per Regel vorzuschreiben, dass jede Funktion eine Javadoc
oder jede Variable einen Kommentar haben müsse. Derartige Kommentare machen
den Code nur unübersichtlicher, verbreiten Lügen und führen zu einer allgemeinen
Verwirrung und Unordnung.
Beispielsweise führt die Forderung, jede Funktion müsse Javadocs haben, zu
Abscheulichkeiten wie etwa in Listing 4 · 3. Dieser Wust Yon Kommentar liefert keine
zusätzlichen Informationen, macht den Code nur unklarer und birgt das Potenzial
für Lügen und Irreführungen.

Listi ng 4·3
/* *
*
* @pa ram t i t l e T h e t i t l e of t h e CD
* @pa r am a u t h o r T h e au t h o r of t h e CD
* @pa r am t r a c k s The n u m b e r of t r a c k s o n the CD
* @pa r am d u rati o n i nM i n u t e s The d u r a t i on of the CD i n - i n u t e s
*/
p u b l i c voi d addCD ( S t r i n g t i t l e , S t r i n g a u t h o r ,
i n t t ra c k s , i n t d u r a t i o n i nM i n u t e s ) {
CD cd =n ew CD () ;
cd . ti tl e = ti tl e ;
cd . author = autho r ;
cd . t racks = t ra c k s ;
c d . d u r a t i on =d u rati o n ;
c d l i s t . add ( c d) ;
}

Tagebuch - Ko m menta re

Manche Entwickler fügen jedes Mal, wenn sie ein �1odul editieren, an seinem
Anfang einen Kommentar ein. Diese Kommentare bilden im Laufe der Zeit eine Art
von Tagebuch oder Protokoll aller jemals vorgenommenen Anderungen. Ich habe

g6
4-4
Schlechte Kom mentare

Module gesehen, die Dutzende von Seiten dieser fortlaufenden Tagebucheinträge


enthielten.

�changes (from 11-0ct-2001)


* --------------------------
*11-0ct-2001 Re-organi sed the cl ass and moved it to new package
* com . j refi nery. date (DG) ;
*05-Nov-2001 Added a getDescri pti on() method , and el i mi nated Notabl eDate
* cl ass (DG) ;
*12-Nov-2001 IBD requi res setDescri ption() method , now that Notabl eDate
* cl ass i s gone (DG) ; Changed getPrevi ousDayOfWeek() ,
* getFol l owi ngDayOfWeek() and getNearestDayOfWeek() to correct
* bugs (DG) ;
*05-Dec-2001 Fi xed bug i n SpreadsheetDate cl ass (DG) ;
*29-May-2002 Moved the month constants i nto a separate i nterface
*
(MonthConstants) (DG) ;
*27-Aug-2002 Fi xed bug i n addMonths () method , thanks to N???l evka Petr (DG) ;
*03-0ct-2002 Fi xed errors reported by Checkstyl e (DG) ;
*13-Mar-2003 Impl emented Seri al i zabl e (DG) ;
*29-May-2003 Fi xed bug i n addMonths method (DG) ;
*04-Sep-2003 Impl emented Comparabl e . Updated the i sinRange j avadocs (DG) ;
*05-Jan-2005 Fi xed bug i n addYears() method (1096282) (DG) ;

Vor langer Zeit gab es einen guten Grund für die Erstellung und Pflege solcher Pro­
tokolleinträge am Anfang j edes Moduls. Es gab keine Sourcecode-Control-Systeme,
die dies für uns erledigten. Heute sind diese langen Journale jedoch eine weitere
Form von Stördaten, die das Modul unübersichtlicher machen. Sie sollten vollkom­
men entfernt werden.

Geschwätz

Manchmal stoßen Sie auf Kommentare, die reines Geschwätz sind. Sie wiederholen
das Offensichtliche und liefern keine neuen Informationen.

!**
*Defaul t constructo r .
*/
p rotected Ann ual DateRu l e () {
}

Tatsächlich? Oder wie wäre es damit:

/** De r T