Entdecken Sie eBooks
Kategorien
Entdecken Sie Hörbücher
Kategorien
Entdecken Sie Zeitschriften
Kategorien
Entdecken Sie Dokumente
Kategorien
Robert c. Martin
Robert C. Martin
Clean Code
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.
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.
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
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
5
I n h a ltsverzeich n i s
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
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
I n h a ltsverzeich n i s
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
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
11
I n h a ltsverzeich n i s
12
I n h a ltsverzeich n i s
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
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
-
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
,I
-
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
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
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
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.
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
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.
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.
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
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
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
»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
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
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
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
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
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 ?
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 ?
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:
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:
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
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.
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?«
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.
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
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.
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,
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.
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
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.
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.
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.
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.
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.
} 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 (
=
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 ) .
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 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
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.
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
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.
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
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.
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.
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
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
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 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.
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.
68
H
Switch-Anwe i s u n ge n
• 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
oder
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.
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.
]0
3-6
F u n kt i o n s a r g u m ente
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
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
72
3·6
F u n kt i o n s a r g u m e n te
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.
Triaden
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.
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:
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
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.
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?
75
Kapitel 3
F u n kt i o n e n
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 ( ) ;
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:
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:
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.
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) {
==
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 ( ) ) ;
}
T ry/c at c h - Blöcke sind von Natur aus hässlich . S : e .::::- .::.::.keln die Struktur des
-•
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 ) ;
}
}
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.
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] .
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.
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.
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 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 ) ;
}
n ewPageCo n t e n t n ew S t r i n g B u ffe r ( ) ;
=
i f ( i sTe s t Page ( ) )
3-14
Setu pTeardow n l ncl u d e r
Kom mentare
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 =
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.
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.
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?
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.
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.
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 .
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 (
=
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.
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.
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.
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 ) ;
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
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.
Heutzutage schalten wir den Testfall natürlich mit einem �I g n o r e Attribut und -
90
4·3
G ute Ko m m e nt are
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
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
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.
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
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.
93
Kapitel 4
Ko m m entare
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 ;
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.
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
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 () {
}