E-Book, Deutsch, 472 Seiten
Reihe: mitp Professional
Fowler Refactoring
2020
ISBN: 978-3-95845-942-7
Verlag: MITP
Format: PDF
Kopierschutz: 1 - PDF Watermark
Wie Sie das Design bestehender Software verbessern
E-Book, Deutsch, 472 Seiten
Reihe: mitp Professional
ISBN: 978-3-95845-942-7
Verlag: MITP
Format: PDF
Kopierschutz: 1 - PDF Watermark
- Umfassend überarbeitete und aktualisierte Neuauflage des Standardwerks in vollständig neuer Übersetzung
- Verbesserungsmöglichkeiten von bestehender Software anhand von Code-Smells erkennen und Code effizient überarbeiten
- Umfassender Katalog von Refactoring-Methoden mit Code-Beispielen in JavaScript
Seit mehr als zwanzig Jahren greifen erfahrene Programmierer rund um den Globus auf dieses Buch zurück, um bestehenden Code zu verbessern und leichter lesbar zu machen sowie Software besser warten und erweitern zu können.
In diesem umfassenden Standardwerk zeigt Ihnen Martin Fowler, was die Vorteile von Refactoring sind, wie Sie verbesserungsbedürftigen Code erkennen und wie Sie ein Refactoring - unabhängig von der verwendeten Programmiersprache - erfolgreich durchführen. In einem umfangreichen Katalog gibt Fowler Ihnen verschiedene Refactoring-Methoden mit ausführlicher Erläuterung, Motivation, Vorgehensweise und einfachen Beispielen in JavaScript an die Hand.
Darüber hinaus behandelt er insbesondere folgende Schwerpunkte:
- Allgemeine Prinzipien und Durchführung des Refactorings
- Refactoring anwenden, um die Lesbarkeit, Wartbarkeit und Erweiterbarkeit von Programmen zu verbessern
- Code-Smells erkennen, die auf Verbesserungsmöglichkeiten durch Refactoring hinweisen
- Entwicklung zuverlässiger Tests für das Refactoring
- Erkennen von Fallstricken und notwendigen Kompromissen bei der Durchführung eines Refactorings
Diese vollständig neu übersetzte Ausgabe wurde von Grund auf überarbeitet, um den maßgeblichen Veränderungen der modernen Programmierung Rechnung zu tragen. Sie enthält einen aktualisierten Katalog von Refactoring-Methoden sowie neue Beispiele für einen funktionalen Programmieransatz.
Aus dem Inhalt:- Definition und Grund-lagen von Refactoring
- Der richtige Zeitpunkt für ein Refactoring
- Verbesserungsbedürftigen Code erkennen (Code-Smells)
- Tests und selbsttestender Code
- Umfangreicher Refactoring-Katalog:
- Kapselung
- Verschiebungen
- Daten organisieren
- Bedingungen vereinfachen
- Refactoring von APIs
- Umgang mit Vererbung
»Dieses Buch gibt einen sehr guten Einstieg in das Refactoring und hält auch eine übersichtliche, gut erklärte Sammlung von Refactoring-Patterns parat. Ein Buch, das sich jeder Programmierer unters Kopfkissen legen sollte.«
Martin Fowler ist Chief Scientist bei ThoughtWorks sowie Autor, Speaker und Consultant auf dem Gebiet der Softwareentwicklung. Er konzentriert sich auf die Entwicklung von Unternehmenssoftware und beschäftigt sich damit, was ein gutes Design auszeichnet und mit welchen Verfahren es umgesetzt werden kann.
Autoren/Hrsg.
Weitere Infos & Material
1;Cover;1
2;Titel;5
3;Impressum;6
4;Inhaltsverzeichnis;7
5;Vorwort zur ersten Auflage;17
6;Über den Fachkorrektor der deutschen Ausgabe;19
7;Einleitung;21
7.1;Was ist Refactoring?;22
7.2;Worum geht es in diesem Buch?;23
7.3;Wer sollte dieses Buch lesen?;25
7.4;Von anderen geschaffene Grundlagen;26
7.5;Danksagungen;27
8;Kapitel 1: Refactoring: Ein erstes Beispiel;29
8.1;1.1 Der Ausgangspunkt;29
8.2;1.2 Anmerkungen zum ersten Programm;32
8.3;1.3 Der erste Schritt des Refactorings;33
8.4;1.4 Aufteilung der statement-Funktion;34
8.4.1;1.4.1 Entfernen der Variable play;40
8.4.2;1.4.2 Extrahieren der Berechnung von Treuepunkten;45
8.4.3;1.4.3 Entfernen der Variable format;46
8.4.4;1.4.4 Entfernen der Gesamtzahl der Treuepunkte;49
8.5;1.5 Status: Eine Menge verschachtelter Funktionen;54
8.6;1.6 Die Phasen Berechnung und Formatierung voneinander trennen;56
8.7;1.7 Status: Aufgeteilt in zwei Dateien (und Phasen);65
8.8;1.8 Neuorganisation der Berechnungen nach Art;68
8.8.1;1.8.1 Berechnen der Kosten einer Vorstellung;70
8.8.2;1.8.2 Funktionen in die Klasse verschieben;71
8.8.3;1.8.3 Polymorphes Verhalten der Klasse PerformanceCalculator;73
8.9;1.9 Status: Erzeugen der Daten mit der polymorphen Klasse PerformanceCalculator;76
8.10;1.10 Abschließende Überlegungen;79
9;Kapitel 2: Prinzipien des Refactorings;81
9.1;2.1 Refactoring: Definition;81
9.2;2.2 Die beiden Hüte;82
9.3;2.3 Gründe für ein Refactoring;83
9.3.1;2.3.1 Refactoring verbessert das Design der Software;83
9.3.2;2.3.2 Refactoring macht Software besser verständlich;83
9.3.3;2.3.3 Refactoring hilft mir, Bugs aufzuspüren;84
9.3.4;2.3.4 Refactoring hilft mir, schneller zu programmieren;84
9.4;2.4 Der richtige Zeitpunkt für ein Refactoring;86
9.4.1;2.4.1 Vorbereitendes Refactoring: Hinzufügen eines Features vereinfachen;86
9.4.2;2.4.2 Refactoring zwecks Verbesserung der Verständlichkeit des Codes;87
9.4.3;2.4.3 Refactoring als Abfallentsorgung;88
9.4.4;2.4.4 Geplantes Refactoring und spontanes Refactoring;88
9.4.5;2.4.5 Langfristiges Refactoring;89
9.4.6;2.4.6 Refactoring beim Code-Review;90
9.4.7;2.4.7 Wie sag ich’s meinem Chef?;91
9.4.8;2.4.8 Wann sollte man kein Refactoring durchführen?;91
9.5;2.5 Probleme beim Refactoring;92
9.5.1;2.5.1 Verlangsamung der Entwicklung neuer Features;92
9.5.2;2.5.2 Code-Eigentümerschaft;93
9.5.3;2.5.3 Entwicklungszweige;94
9.5.4;2.5.4 Testen;96
9.5.5;2.5.5 Legacy Code;97
9.5.6;2.5.6 Datenbanken;98
9.6;2.6 Refactoring, Architektur und Yagni;99
9.7;2.7 Refactoring und der Softwareentwicklungsprozess;100
9.8;2.8 Refactoring und Performance;101
9.9;2.9 Ursprünge des Refactorings;104
9.10;2.10 Automatisiertes Refactoring;105
9.11;2.11 Weiterführende Literatur;107
10;Kapitel 3: Code-Smells: Schlechte Gerüche im Code;109
10.1;3.1 Rätselhafte Bezeichnung;110
10.2;3.2 Redundanter Code;110
10.3;3.3 Lange Funktion;111
10.4;3.4 Lange Parameterliste;112
10.5;3.5 Globale Daten;112
10.6;3.6 Veränderliche Daten;113
10.7;3.7 Divergierende Änderungen;114
10.8;3.8 Chirurgie mit der Schrotflinte;115
10.9;3.9 Feature-Neid;115
10.10;3.10 Datenklumpen;116
10.11;3.11 Obsession für elementare Datentypen;117
10.12;3.12 Wiederholte switch-Anweisungen;117
10.13;3.13 Schleifen;118
10.14;3.14 Träges Element;118
10.15;3.15 Spekulative Generalisierung;118
10.16;3.16 Temporäres Feld;119
10.17;3.17 Mitteilungsketten;119
10.18;3.18 Vermittler;120
10.19;3.19 Insiderhandel;120
10.20;3.20 Umfangreiche Klasse;120
10.21;3.21 Alternative Klassen mit unterschiedlichen Schnittstellen;121
10.22;3.22 Datenklasse;121
10.23;3.23 Ausgeschlagenes Erbe;122
10.24;3.24 Kommentare;122
11;Kapitel 4: Tests erstellen;125
11.1;4.1 Der Nutzen selbsttestenden Codes;125
11.2;4.2 Beispielcode zum Testen;127
11.3;4.3 Ein erster Test;131
11.4;4.4 Hinzufügen eines weiteren Tests;134
11.5;4.5 Ändern des Test-Fixtures;136
11.6;4.6 Austesten der Grenzen;137
11.7;4.7 Und noch viel mehr;141
12;Kapitel 5: Der Katalog;143
12.1;5.1 Format der Refactorings;143
12.2;5.2 Die Auswahl der Refactorings;144
13;Kapitel 6: Eine erste Zusammenstellung von Refactorings;147
13.1;6.1 Funktion extrahieren (Extract Function);147
13.1.1;6.1.1 Motivation;148
13.1.2;6.1.2 Vorgehen;149
13.1.3;6.1.3 Beispiel: Keine Variablen außerhalb des Gültigkeitsbereichs;150
13.1.4;6.1.4 Beispiel: Verwendung lokaler Variablen;153
13.1.5;6.1.5 Beispiel: Zuweisung zu einer lokalen Variable;154
13.2;6.2 Funktion inline platzieren (Inline Function);157
13.2.1;6.2.1 Motivation;158
13.2.2;6.2.2 Vorgehen;158
13.2.3;6.2.3 Beispiel;159
13.3;6.3 Variable extrahieren (Extract Variable);161
13.3.1;6.3.1 Motivation;161
13.3.2;6.3.2 Vorgehen;162
13.3.3;6.3.3 Beispiel;162
13.3.4;6.3.4 Beispiel mit einer Klasse;164
13.4;6.4 Variable inline platzieren (Inline Variable);165
13.4.1;6.4.1 Motivation;166
13.4.2;6.4.2 Vorgehen;166
13.5;6.5 Funktionsdeklaration ändern (Change Function Declaration);166
13.5.1;6.5.1 Motivation;167
13.5.2;6.5.2 Vorgehen;168
13.5.3;6.5.3 Beispiel: Umbenennen einer Funktion (einfaches Vorgehen);169
13.5.4;6.5.4 Beispiel: Umbenennen einer Funktion (Migrationsansatz);170
13.5.5;6.5.5 Beispiel: Hinzufügen eines Parameters;171
13.5.6;6.5.6 Beispiel: Einen Parameter durch eine seiner Eigenschaften ersetzen;172
13.6;6.6 Variable kapseln (Encapsulate Variable);174
13.6.1;6.6.1 Motivation;175
13.6.2;6.6.2 Vorgehen;176
13.6.3;6.6.3 Beispiel;176
13.7;6.7 Variable umbenennen (Rename Variable);179
13.7.1;6.7.1 Motivation;180
13.7.2;6.7.2 Vorgehen;180
13.7.3;6.7.3 Beispiel;180
13.8;6.8 Parameterobjekt einführen (Introduce Parameter Object);182
13.8.1;6.8.1 Motivation;182
13.8.2;6.8.2 Vorgehen;183
13.8.3;6.8.3 Beispiel;183
13.9;6.9 Funktionen zu einer Klasse vereinen (Combine Functions into Class);186
13.9.1;6.9.1 Motivation;187
13.9.2;6.9.2 Vorgehen;187
13.9.3;6.9.3 Beispiel;188
13.10;6.10 Funktionen zu einer Transformation vereinen (Combine Functions into Transform);191
13.10.1;6.10.1 Motivation;192
13.10.2;6.10.2 Vorgehen;192
13.10.3;6.10.3 Beispiel;193
13.11;6.11 Phase aufteilen (Split Phase);197
13.11.1;6.11.1 Motivation;198
13.11.2;6.11.2 Vorgehen;198
13.11.3;6.11.3 Beispiel;199
14;Kapitel 7: Kapselung;205
14.1;7.1 Datensatz kapseln (Encapsulate Record);205
14.1.1;7.1.1 Motivation;206
14.1.2;7.1.2 Vorgehen;207
14.1.3;7.1.3 Beispiel;207
14.1.4;7.1.4 Beispiel: Kapselung eines verschachtelten Datensatzes;209
14.2;7.2 Collection kapseln (Encapsulate Collection);214
14.2.1;7.2.1 Motivation;215
14.2.2;7.2.2 Vorgehen;216
14.2.3;7.2.3 Beispiel;216
14.3;7.3 Elementaren Wert durch Objekt ersetzen (Replace Primitive with Object);219
14.3.1;7.3.1 Motivation;219
14.3.2;7.3.2 Vorgehen;220
14.3.3;7.3.3 Beispiel;220
14.4;7.4 Temporäre Variable durch Abfrage ersetzen (Replace Temp with Query);223
14.4.1;7.4.1 Motivation;224
14.4.2;7.4.2 Vorgehen;225
14.4.3;7.4.3 Beispiel;225
14.5;7.5 Klasse extrahieren (Extract Class);227
14.5.1;7.5.1 Motivation;228
14.5.2;7.5.2 Vorgehen;228
14.5.3;7.5.3 Beispiel;229
14.6;7.6 Klasse inline platzieren (Inline Class);231
14.6.1;7.6.1 Motivation;232
14.6.2;7.6.2 Vorgehen;232
14.6.3;7.6.3 Beispiel;233
14.7;7.7 Delegation verbergen (Hide Delegate);234
14.7.1;7.7.1 Motivation;235
14.7.2;7.7.2 Vorgehen;236
14.7.3;7.7.3 Beispiel;236
14.8;7.8 Vermittler entfernen (Remove Middle Man);237
14.8.1;7.8.1 Motivation;237
14.8.2;7.8.2 Vorgehen;238
14.8.3;7.8.3 Beispiel;238
14.9;7.9 Algorithmus ersetzen (Substitute Algorithm);239
14.9.1;7.9.1 Motivation;240
14.9.2;7.9.2 Vorgehen;241
15;Kapitel 8: Verschiebungen;243
15.1;8.1 Funktion verschieben (Move Function);243
15.1.1;8.1.1 Motivation;244
15.1.2;8.1.2 Vorgehen;244
15.1.3;8.1.3 Beispiel: Verschieben einer verschachtelten Funktion in die oberste Ebene;245
15.1.4;8.1.4 Beispiel: Verschiebungen zwischen Klassen;250
15.2;8.2 Feld verschieben (Move Field);253
15.2.1;8.2.1 Motivation;253
15.2.2;8.2.2 Vorgehen;255
15.2.3;8.2.3 Beispiel;255
15.2.4;8.2.4 Beispiel: Verschiebung in ein gemeinsam genutztes Objekt;257
15.3;8.3 Anweisungen in Funktion verschieben (Move Statements into Function);259
15.3.1;8.3.1 Motivation;260
15.3.2;8.3.2 Vorgehen;260
15.3.3;8.3.3 Beispiel;261
15.4;8.4 Anweisungen in Aufrufer verschieben (Move Statements to Caller);263
15.4.1;8.4.1 Motivation;264
15.4.2;8.4.2 Vorgehen;264
15.4.3;8.4.3 Beispiel;265
15.5;8.5 Inline-Code durch Funktionsaufruf ersetzen (Replace Inline Code with Function Call);269
15.5.1;8.5.1 Motivation;269
15.5.2;8.5.2 Vorgehen;270
15.6;8.6 Anweisungen verschieben (Slide Statements);270
15.6.1;8.6.1 Motivation;271
15.6.2;8.6.2 Vorgehen;271
15.6.3;8.6.3 Beispiel;271
15.6.4;8.6.4 Beispiel: Verschiebungen und bedingte Anweisungen;273
15.6.5;8.6.5 Literaturhinweis;274
15.7;8.7 Schleife aufteilen (Split Loop);275
15.7.1;8.7.1 Motivation;275
15.7.2;8.7.2 Vorgehen;276
15.7.3;8.7.3 Beispiel;276
15.8;8.8 Schleife durch Pipeline ersetzen (Replace Loop with Pipeline);279
15.8.1;8.8.1 Motivation;279
15.8.2;8.8.2 Vorgehen;279
15.8.3;8.8.3 Beispiel;280
15.8.4;8.8.4 Literaturhinweis;285
15.9;8.9 Toten Code entfernen (Remove Dead Code);285
15.9.1;8.9.1 Motivation;285
15.9.2;8.9.2 Vorgehen;286
16;Kapitel 9: Daten organisieren;287
16.1;9.1 Variable aufteilen (Split Variable);287
16.1.1;9.1.1 Motivation;288
16.1.2;9.1.2 Vorgehen;288
16.1.3;9.1.3 Beispiel;288
16.1.4;9.1.4 Beispiel: Zuweisung zu einem Eingabeparameter;290
16.2;9.2 Feld umbenennen (Rename Field);291
16.2.1;9.2.1 Motivation;292
16.2.2;9.2.2 Vorgehen;292
16.2.3;9.2.3 Beispiel: Umbenennen eines Feldes;292
16.3;9.3 Abgeleitete Variable durch Abfrage ersetzen (Replace Derived Variable with Query);295
16.3.1;9.3.1 Motivation;296
16.3.2;9.3.2 Vorgehen;296
16.3.3;9.3.3 Beispiel;297
16.3.4;9.3.4 Beispiel: Mehr als eine Quelle;298
16.4;9.4 Referenz durch Wert ersetzen (Change Reference to Value);299
16.4.1;9.4.1 Motivation;300
16.4.2;9.4.2 Vorgehen;300
16.4.3;9.4.3 Beispiel;300
16.5;9.5 Wert durch Referenz ersetzen (Change Value to Reference);303
16.5.1;9.5.1 Motivation;303
16.5.2;9.5.2 Vorgehen;304
16.5.3;9.5.3 Beispiel;304
17;Kapitel 10: Bedingungen vereinfachen;307
17.1;10.1 Bedingung zerlegen (Decompose Conditional);307
17.1.1;10.1.1 Motivation;308
17.1.2;10.1.2 Vorgehen;308
17.1.3;10.1.3 Beispiel;308
17.2;10.2 Bedingten Ausdruck zusammenfassen (Consolidate Conditional Expression);310
17.2.1;10.2.1 Motivation;311
17.2.2;10.2.2 Vorgehen;311
17.2.3;10.2.3 Beispiel;312
17.2.4;10.2.4 Beispiel: Verwendung von »and«;312
17.3;10.3 Verschachtelte Bedingung durch Wächterbedingung ersetzen (Replace Nested Conditional with Guard Clauses);313
17.3.1;10.3.1 Motivation;314
17.3.2;10.3.2 Vorgehen;314
17.3.3;10.3.3 Beispiel;315
17.3.4;10.3.4 Beispiel: Umkehrung der Bedingungen;317
17.4;10.4 Bedingung durch Polymorphie ersetzen (Replace Conditional with Polymorphism);319
17.4.1;10.4.1 Motivation;320
17.4.2;10.4.2 Vorgehen;320
17.4.3;10.4.3 Beispiel;321
17.4.4;10.4.4 Beispiel: Polymorphie für Variationen verwenden;326
17.5;10.5 Sonderfall einführen (Introduce Special Case);338
17.5.1;10.5.1 Motivation;339
17.5.2;10.5.2 Vorgehen;339
17.5.3;10.5.3 Beispiel;340
17.5.4;10.5.4 Beispiel: Verwendung eines Objekts mit Literalen;345
17.5.5;10.5.5 Beispiel: Verwenden einer Transformation;348
17.6;10.6 Assertion einführen (Introduce Assertion);353
17.6.1;10.6.1 Motivation;353
17.6.2;10.6.2 Vorgehen;354
17.6.3;10.6.3 Beispiel;354
18;Kapitel 11: Refactoring von APIs;357
18.1;11.1 Abfrage von Veränderung trennen (Separate Query from Modifier);357
18.1.1;11.1.1 Motivation;358
18.1.2;11.1.2 Vorgehen;358
18.1.3;11.1.3 Beispiel;359
18.2;11.2 Funktion parametrisieren (Parameterize Function);361
18.2.1;11.2.1 Motivation;362
18.2.2;11.2.2 Vorgehen;362
18.2.3;11.2.3 Beispiel;362
18.3;11.3 Steuerungs-Flag entfernen (Remove Flag Argument);365
18.3.1;11.3.1 Motivation;365
18.3.2;11.3.2 Vorgehen;367
18.3.3;11.3.3 Beispiel;367
18.4;11.4 Vollständiges Objekt erhalten (Preserve Whole Object);370
18.4.1;11.4.1 Motivation;371
18.4.2;11.4.2 Vorgehen;371
18.4.3;11.4.3 Beispiel;372
18.4.4;11.4.4 Beispiel: Eine Variante zum Erstellen der neuen Funktion;373
18.5;11.5 Parameter durch Abfrage ersetzen (Replace Parameter with Query);375
18.5.1;11.5.1 Motivation;376
18.5.2;11.5.2 Vorgehen;377
18.5.3;11.5.3 Beispiel;377
18.6;11.6 Abfrage durch Parameter ersetzen (Replace Query with Parameter);378
18.6.1;11.6.1 Motivation;379
18.6.2;11.6.2 Vorgehen;380
18.6.3;11.6.3 Beispiel;380
18.7;11.7 Setter entfernen (Remove Setting Method);383
18.7.1;11.7.1 Motivation;383
18.7.2;11.7.2 Vorgehen;384
18.7.3;11.7.3 Beispiel;384
18.8;11.8 Konstruktor durch Fabrikfunktion ersetzen (Replace Constructor with Factory Function);385
18.8.1;11.8.1 Motivation;386
18.8.2;11.8.2 Vorgehen;386
18.8.3;11.8.3 Beispiel;386
18.9;11.9 Funktion durch Befehl ersetzen (Replace Function with Command);387
18.9.1;11.9.1 Motivation;388
18.9.2;11.9.2 Vorgehen;389
18.9.3;11.9.3 Beispiel;389
18.10;11.10 Befehl durch Funktion ersetzen (Replace Command with Function);395
18.10.1;11.10.1 Motivation;395
18.10.2;11.10.2 Vorgehen;396
18.10.3;11.10.3 Beispiel;396
19;Kapitel 12: Der Umgang mit Vererbung;401
19.1;12.1 Methode nach oben verschieben (Pull Up Method);401
19.1.1;12.1.1 Motivation;402
19.1.2;12.1.2 Vorgehen;403
19.1.3;12.1.3 Beispiel;403
19.2;12.2 Feld nach oben verschieben (Pull Up Field);404
19.2.1;12.2.1 Motivation;405
19.2.2;12.2.2 Vorgehen;405
19.3;12.3 Konstruktorrumpf nach oben verschieben (Pull Up Constructor Body);406
19.3.1;12.3.1 Motivation;407
19.3.2;12.3.2 Vorgehen;407
19.3.3;12.3.3 Beispiel;407
19.4;12.4 Methode nach unten verschieben (Push Down Method);410
19.4.1;12.4.1 Motivation;411
19.4.2;12.4.2 Vorgehen;411
19.5;12.5 Feld nach unten verschieben (Push Down Field);411
19.5.1;12.5.1 Motivation;412
19.5.2;12.5.2 Vorgehen;412
19.6;12.6 Typenschlüssel durch Unterklassen ersetzen (Replace Type Code with Subclasses);412
19.6.1;12.6.1 Motivation;413
19.6.2;12.6.2 Vorgehen;413
19.6.3;12.6.3 Beispiel;414
19.6.4;12.6.4 Beispiel: Indirekte Vererbung;417
19.7;12.7 Unterklasse entfernen (Remove Subclass);420
19.7.1;12.7.1 Motivation;421
19.7.2;12.7.2 Vorgehen;421
19.7.3;12.7.3 Beispiel;421
19.8;12.8 Basisklasse extrahieren (Extract Superclass);426
19.8.1;12.8.1 Motivation;427
19.8.2;12.8.2 Vorgehen;427
19.8.3;12.8.3 Beispiel;427
19.9;12.9 Hierarchie abbauen (Collapse Hierarchy);431
19.9.1;12.9.1 Motivation;431
19.9.2;12.9.2 Vorgehen;432
19.10;12.10 Unterklasse durch Delegation ersetzen (Replace Subclass with Delegate);432
19.10.1;12.10.1 Motivation;433
19.10.2;12.10.2 Vorgehen;434
19.10.3;12.10.3 Beispiel;435
19.10.4;12.10.4 Beispiel: Ersetzen einer Hierarchie;442
19.11;12.11 Basisklasse durch Delegation ersetzen (Replace Superclass with Delegate);452
19.11.1;12.11.1 Motivation;453
19.11.2;12.11.2 Vorgehen;454
19.11.3;12.11.3 Beispiel;454
20;Anhang A: Bibliografie;459
21;Anhang B: Liste der Refactorings;463
22;Anhang C: Code-Smells;465
23;Stichwortverzeichnis;469
Einleitung
Es war einmal ein Berater, der sich zu einem Softwareprojekt aufmachte, um sich den Code anzusehen, der im Laufe des Projekts entstanden war. Als er sich die Klassenhierarchie im Kern des Systems ansah, stellte er fest, dass es ein ziemliches Durcheinander war. Klassen auf höherem Abstraktionsniveau gingen von bestimmten Annahmen bezüglich der Funktionsweise anderer Klassen aus – Annahmen, die sie in Form von Code an ihre Unterklassen vererbten. Der Code war allerdings nicht für alle Unterklassen geeignet, daher wurde er ziemlich häufig überschrieben. Schon geringfügige Änderungen an der Basisklasse hätten die Notwendigkeit, den Code zu überschreiben, weitestgehend beseitig. An anderen Stellen hatte man die Intentionen der Basisklasse offenbar nicht richtig verstanden, denn Teile des in der Basisklasse bereits vorhandenen Verhaltens wurden in Unterklassen erneut implementiert. An wieder anderen Stellen erledigten mehrere Unterklassen die gleichen Aufgaben durch Code, der in der Klassenhierarchie eindeutig nach oben verschoben werden konnte.
Der Berater empfahl dem Projektmanagement, den Code zu untersuchen und zu bereinigen – was allerdings nicht gerade für Begeisterung sorgte. Der Code funktionierte offenbar, und es gab erheblichen Termindruck. Das Management meinte, man werde sich später darum kümmern.
Den Programmierern, die an der Klassenhierarchie arbeiteten, hatte der Berater ebenfalls gezeigt, was da tatsächlich vor sich ging. Sie waren eifrig und erkannten das Problem. Ihnen war klar, dass es nicht wirklich ihr Fehler war. Manchmal benötigt es eben ein weiteres Paar an Augen, um ein Problem zu erkennen. Die Programmierer befassten sich also ein paar Tage lang damit, die Hierarchie aufzuräumen. Als sie fertig waren, hatten sie die Hälfte des Codes aus der Hierarchie entfernt, ohne dadurch die Funktionalität einzuschränken. Sie waren mit dem Ergebnis sehr zufrieden und stellten fest, dass sowohl das Hinzufügen neuer Klassen als auch die Verwendung der Klassen des übrigen Systems schneller und einfacher von der Hand gingen.
Das Projektmanagement war nicht erfreut. Der Terminplan war eng, und es gab eine Menge Arbeit zu erledigen. Die beiden Programmierer hatten zwei Tage mit Arbeiten verbracht, die nichts zu den vielen Features beitrugen, die das System in wenigen Monaten besitzen musste. Der alte Code hatte doch tadellos funktioniert. Ja, zugegeben, das Design war jetzt etwas »reiner« und etwas »sauberer«, aber das Projekt musste Code liefern, der funktioniert, keinen Code, der Akademikern gefällt. Der Berater hingegen schlug vor, weitere zentrale Teile des Systems auf ähnliche Weise aufzuräumen, wodurch das Projekt womöglich ein bis zwei Wochen zum Stillstand käme. Und das Ganze, um den Code schöner zu machen, nicht, damit er etwas kann, was er nicht jetzt schon könnte.
Was halten Sie von dieser Geschichte? Glauben Sie, dass der Berater zu Recht vorschlug, weiter aufzuräumen? Oder neigen Sie eher zur alten Ingenieur-Weisheit »Was nicht kaputt ist, muss man auch nicht reparieren«?
Ich bin hier zugegebenermaßen etwas voreingenommen, denn der Berater war ich. Das Projekt scheiterte sechs Monate später, vor allem, weil der Code zu komplex war, um ihn zu debuggen oder ihn so anzupassen, dass er eine akzeptable Leistung lieferte.
Dann wurde Kent Beck als Berater engagiert, der das Projekt wieder auf die Beine stellen sollte – eine Aufgabe, die es erforderlich machte, fast das gesamte System von Grund auf neu zu schreiben. Er machte einiges anders, aber die wichtigste Änderung war, dass er darauf bestand, den Code durch Refactorings kontinuierlich aufzuräumen. Die erhöhte Effektivität des Teams und die Rolle, die das Refactoring dabei einnahm, inspirierten mich dazu, die erste Ausgabe dieses Buchs zu verfassen – um das von Kent und anderen erworbene Wissen weiterzugeben, das sie sich durch die Anwendung von Refactorings zur Verbesserung der Softwarequalität angeeignet hatten.
Seitdem gehört »Refactoring« in der Programmierung zum gängigen Wortschatz. Tatsächlich hat sich das ursprüngliche Buch auch ziemlich gut behaupten können. Allerdings sind achtzehn Jahre ein hohes Alter für ein Buch über Programmierung. Daher dachte ich mir, es sei an der Zeit, es zu überarbeiten. Dabei habe ich praktisch jede Seite des Buchs neu geschrieben. In gewisser Hinsicht hat sich jedoch nur sehr wenig geändert. Die Essenz des Buches ist unverändert; die meisten der wichtigsten Refactorings sind grundsätzlich die gleichen. Ich hoffe jedoch, dass die Neuformulierungen mehr Lesern dabei helfen, zu erlernen, wie das Refactoring effektiv durchgeführt wird.
Was ist Refactoring?
Refactoring ist der Prozess, ein Softwaresystem so zu modifizieren, dass sich das externe Verhalten des Codes nicht ändert, aber dennoch die interne Struktur des Codes zu verbessern. Es handelt sich um eine Vorgehensweise zum Aufräumen von Code, die Disziplin erfordert und die Wahrscheinlichkeit, Bugs zu verursachen, minimiert. Beim Refactoring verbessern Sie im Wesentlichen das Design des Codes, nachdem er geschrieben wurde.
»Verbessern des Designs des Codes, nachdem er geschrieben wurde.« Das ist schon eine seltsame Ausdrucksweise. Seit es Softwareentwicklung gibt, dachten die meisten Leute, dass zunächst das Design entwickelt wird, und dass die Programmierung erst dann erfolgt, wenn es abgeschlossen ist. Der Code wird im Laufe der Zeit modifiziert, und die Integrität des Systems – die dem ursprünglichen Design entsprechende Struktur – geht allmählich verloren. Der Code wird nicht mehr sorgfältig entwickelt, und die Programmierung wird allmählich zum »Hacken«.
Refactoring ist das Gegenteil dieser Vorgehensweise. Mit Refactoring können wir ein schlechtes oder sogar chaotisches Design in sinnvoll strukturierten Code umwandeln. Die einzelnen Schritte sind einfach – geradezu simpel. Ich verschiebe ein Attribut von einer Klasse in eine andere, entnehme einer Methode etwas Code, um daraus eine eigene Methode zu machen oder verschiebe Teile des Codes in der Hierarchie nach oben oder unten. Dennoch kann die Gesamtheit dieser kleinen Änderungen das Design drastisch verbessern. Hierbei handelt es sich um die genaue Umkehrung dessen, was man als Softwarezerfall bezeichnen könnte.
Beim Refactoring verschiebt sich die Gewichtung der Tätigkeiten. Das Design wird nicht nur ganz am Anfang festgelegt, sondern entsteht kontinuierlich während der Entwicklung. Während sich das System entwickelt, finde ich heraus, wie sich das Design verbessern lässt. Diese Interaktion führt zu einem Programm, dessen Design auch bei fortschreitender Entwicklung gut bleibt.
Worum geht es in diesem Buch?
Dieses Buch ist ein Leitfaden für das Refactoring und wendet sich an den fortgeschrittenen Entwickler. Ich möchte Ihnen zeigen, wie Sie Refactorings auf kontrollierte und effiziente Weise durchführen können. Sie erfahren, wie Sie ein Refactoring vornehmen, ohne Bugs im Code zu verursachen, und gleichzeitig die Struktur des Codes systematisch verbessern.
Traditionell beginnt ein Buch mit einer Einführung. Das halte ich im Prinzip für richtig, finde es jedoch schwierig, Refactoring anhand allgemeiner Erklärungen oder Definitionen einzuführen, deshalb folgt zunächst ein Beispiel. In Kapitel 1 wird ein kleines Programm mit einigen typischen Designfehlern durch Refactorings so umstrukturiert, dass es anschließend besser verständlich und leichter modifizierbar ist. Sie lernen dabei den generellen Refactoring-Prozess sowie eine Reihe nützlicher Refactorings kennen. Hierbei handelt es sich um das wichtigste Kapitel, das Sie lesen sollten, wenn Sie verstehen möchten, worum es beim Refactoring eigentlich geht.
In Kapitel 2 erläutere ich weitere allgemeine Prinzipien des Refactorings und stelle einige Definitionen sowie die Gründe für ein Refactoring vor. Anschließend umreiße ich einige der Herausforderungen, die das Refactoring mit sich bringt. In Kapitel 3 unterstützt mich Kent Beck dabei, zu beschreiben, wie man »Code-Smells« identifiziert und wie man sie durch Refactorings bereinigen kann. Auch das Testen spielt beim Refactoring eine sehr wichtige Rolle, deshalb beschreibt Kapitel 4, wie Sie Tests in Ihren Code integrieren können.
Der Hauptgegenstand dieses Buchs – der Refactoring-Katalog – nimmt die verbleibenden Seiten ein. Der Katalog ist zwar alles andere als vollständig, enthält jedoch die wichtigsten Refactorings, die wahrscheinlich von den meisten Entwicklern benötigt werden. Der Katalog ist aus den Notizen entstanden, die ich mir gemacht habe, als ich mich Ende der 1990er Jahre mit Refactoring befasste. Ich verwende diese Notizen auch heute noch, weil ich sie mir nicht alle merken kann. Wenn ich ein Refactoring durchführen möchte, wie etwa Phase aufteilen (Split Phase, Abschnitt 6.11), kann ich im Katalog nachsehen, wie ich das auf sichere Weise Schritt für Schritt tun kann. Ich kann mir nur wünschen, dass Sie diesen Teil des Buchs regelmäßig aufschlagen werden.
Schwerpunkt Internet
Das Internet hat enorme Auswirkungen auf unsere Gesellschaft, insbesondere auf die Art und Weise, wie wir uns Informationen beschaffen. Als ich die erste Ausgabe dieses Buchs verfasste, wurde das Wissen über Softwareentwicklung hauptsächlich durch Druckerzeugnisse vermittelt. Inzwischen beschaffe ich mir die meisten Informationen online. Das stellt für Autoren wie mich eine Herausforderung dar: Haben Bücher noch eine Daseinsberechtigung, und wie sollten sie gestaltet sein?
Ich glaube, Bücher wie dieses haben noch immer ihren Platz – sie müssen sich jedoch ändern. Der Wert...




