Upload
lore-duenow
View
118
Download
4
Embed Size (px)
Citation preview
2
Übersicht
Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
3
„Refactoring“, Martin Fowler
• Dieses Tutorial beruht im Wesentlichen auf dem Buch „Refactoring – Improving the Design of Existing Code“ von Martin Fowler. Standardwerk Abweichungen im Detail
• Dieses Tutorial beruht im Wesentlichen auf dem Buch „Refactoring – Improving the Design of Existing Code“ von Martin Fowler. Standardwerk Abweichungen im Detail
4
Refactoring: Definition
„Refactoring ist die Verbesserung der Qualitätvon vorhandenem Quell-text ohne Veränderung der Funktionalität.“
5
Problem
• Das Design eines Systems neigt dazu, im Laufe der Zeit immer schlechter zu werden. Neue Funktionalität wird gefordert, alte entfällt Vorhandene Anforderungen werden geändert Das Verständnis des Systems ändert sich
• Das Design eines Systems neigt dazu, im Laufe der Zeit immer schlechter zu werden. Neue Funktionalität wird gefordert, alte entfällt Vorhandene Anforderungen werden geändert Das Verständnis des Systems ändert sich
6
Refactoring als Gegenmittel
• Um dem entgegenzuwirken, muss das Design mit dem System wachsen. Kleine Schritte reduzieren das Risiko Trennung zwischen Refactoring und
Erweiterung des Systems hilft zu fokussieren Arbeit am System stößt auf sich ändernde Teile
• Um dem entgegenzuwirken, muss das Design mit dem System wachsen. Kleine Schritte reduzieren das Risiko Trennung zwischen Refactoring und
Erweiterung des Systems hilft zu fokussieren Arbeit am System stößt auf sich ändernde Teile
7
Demonstration
• Ein Quelltext sagt mehr als tausend Folien... Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
• Ein Quelltext sagt mehr als tausend Folien... Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
8
Was ist geschehen?
• Ein Stück Software wurde überarbeitet, ohne dass sich sein Verhalten geändert hat. Auslöser: eine anstehende Änderung Code war unnötig kompliziert Änderungen in kleinen Schritten
• Ein Stück Software wurde überarbeitet, ohne dass sich sein Verhalten geändert hat. Auslöser: eine anstehende Änderung Code war unnötig kompliziert Änderungen in kleinen Schritten
9
Wann Refactoring
• Der richtige Zeitpunkt für Refactoring ist, wenn man sich ohnehin mit dem Quelltext beschäftigt. Beim Debugging Beim Erweitern/Ändern Wenn ein Kollege mit einer Frage kommt
• Der richtige Zeitpunkt für Refactoring ist, wenn man sich ohnehin mit dem Quelltext beschäftigt. Beim Debugging Beim Erweitern/Ändern Wenn ein Kollege mit einer Frage kommt
10
Kleine Schritte
• Refactoring funktioniert am besten, wenn man es in kleinen Schritten tut. Schutz vor Flüchtigkeitsfehlern Man behält den Überblick Bei Problem: einfach einen Schritt zurück
• Refactoring funktioniert am besten, wenn man es in kleinen Schritten tut. Schutz vor Flüchtigkeitsfehlern Man behält den Überblick Bei Problem: einfach einen Schritt zurück
11
Die beiden Hüte
• Refactoring und Erweiterung des Systems wechseln sich ab. Saubere Trennung für besseren Überblick Zettel und Stift als Gedächtnisstütze Man hat entweder den „Refactoring-Hut“ oder
den „Erweiterungs-Hut“ auf
• Refactoring und Erweiterung des Systems wechseln sich ab. Saubere Trennung für besseren Überblick Zettel und Stift als Gedächtnisstütze Man hat entweder den „Refactoring-Hut“ oder
den „Erweiterungs-Hut“ auf
12
Zusammenfassung
• Refactoring erlaubt es, nachträglich Designentscheidungen zu ändern. Zeitpunkt: wenn man ohnehin mit dem Code zu
tun hat Kleine Schritte: Entspannt bleiben, bei Problem
einen Schritt zurück.
• Refactoring erlaubt es, nachträglich Designentscheidungen zu ändern. Zeitpunkt: wenn man ohnehin mit dem Code zu
tun hat Kleine Schritte: Entspannt bleiben, bei Problem
einen Schritt zurück.
13
Übersicht
• Einführung
Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
• Einführung
Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
14
Altersschwäche
• Software kann an Altersschwäche sterben. Design wächst nicht mit den Anforderungen Wartung als Albtraum Manchmal schon vor Inbetriebnahme...
• Software kann an Altersschwäche sterben. Design wächst nicht mit den Anforderungen Wartung als Albtraum Manchmal schon vor Inbetriebnahme...
15
Hellseherei
• Fixiertes Design vorab ist problematisch. Anforderungen ändern sich Das Verständnis wächst „Hellseherei“ funktioniert oft nicht Ausnahme: feste Anforderungen, erfahrenes
Team (z.B. reine Migration)
• Fixiertes Design vorab ist problematisch. Anforderungen ändern sich Das Verständnis wächst „Hellseherei“ funktioniert oft nicht Ausnahme: feste Anforderungen, erfahrenes
Team (z.B. reine Migration)
16
Traditionelles Vorgehen
• Das Wasserfall-Modell ist immer noch sehr verbreitet. Änderungen werden mit der Zeit teurer Risiko minimieren
• Das Wasserfall-Modell ist immer noch sehr verbreitet. Änderungen werden mit der Zeit teurer Risiko minimieren
Zeit
Änderungskosten
17
Änderungen billig machen
• Agile Vorgehensmodelle unterstützen späte Änderungen Z.B. eXtreme Programming Weniger Gewicht auf Planung am Anfang System profitiert von wachsender Erfahrung
• Agile Vorgehensmodelle unterstützen späte Änderungen Z.B. eXtreme Programming Weniger Gewicht auf Planung am Anfang System profitiert von wachsender Erfahrung
Zeit
Änderungskosten
18
Kriterien für das Vorgehensmodell
• Refactoring funktioniert am besten in einem Vorgehensmodell, bei dem Änderungen billig und sicher sind.
• Dann kann das System von der wachsenden Erfahrung profitieren.
• Refactoring funktioniert am besten in einem Vorgehensmodell, bei dem Änderungen billig und sicher sind.
• Dann kann das System von der wachsenden Erfahrung profitieren.
19
Source-Code enthält das Design
• Refactoring ändert das Design schrittweise im Quelltext. Sonstige Design-Dokumentation bremst dabei. Keine Hackerei: Anforderung an den Code Je feiner die übrige Designdokumentation ist,
desto problematischer „Design Freeze“ schließt Refactoring aus
• Refactoring ändert das Design schrittweise im Quelltext. Sonstige Design-Dokumentation bremst dabei. Keine Hackerei: Anforderung an den Code Je feiner die übrige Designdokumentation ist,
desto problematischer „Design Freeze“ schließt Refactoring aus
20
Einfachheit als Wert
• Softwareentwicklung ist eine der kompliziertesten Tätigkeiten der Welt. Quelltexte sind primär für menschliche Leser Möglichst viele Hilfestellungen Unnötige Komplexität entfernen
• Softwareentwicklung ist eine der kompliziertesten Tätigkeiten der Welt. Quelltexte sind primär für menschliche Leser Möglichst viele Hilfestellungen Unnötige Komplexität entfernen
21
Wenn du es siehst, tue es
• Ein Problem lieber gleich angehen als es auf die lange Bank schieben. Probleme verschwinden nicht von alleine Vorgehensmodell muss das zulassen Mut als Wert
• Ausnahme: kurz vor einer Deadline.
• Ein Problem lieber gleich angehen als es auf die lange Bank schieben. Probleme verschwinden nicht von alleine Vorgehensmodell muss das zulassen Mut als Wert
• Ausnahme: kurz vor einer Deadline.
22
Qualität als Wert?
• Qualität als Wert entwickelt leicht eine Eigendynamik. Qualität ist relativ zu Maßstäben; damit lässt
sich Vieles begründen Stattdessen klarer „Einfachheit“ und
„Kommunikation“
• Qualität als Wert entwickelt leicht eine Eigendynamik. Qualität ist relativ zu Maßstäben; damit lässt
sich Vieles begründen Stattdessen klarer „Einfachheit“ und
„Kommunikation“
23
Versionsverwaltung
• Eine Versionsverwaltung ist eine wichtige Voraussetzung für Refactoring, besonders im Team. Reversibilität von Refactorings Kurze Check-In-Zyklen
• Eine Versionsverwaltung ist eine wichtige Voraussetzung für Refactoring, besonders im Team. Reversibilität von Refactorings Kurze Check-In-Zyklen
24
Buildprozess
• Nur ein wohldefinierter Buildprozess erlaubt die Überprüfung von Änderungen. An jedem Arbeitsplatz verfügbar Muss gelebt werden Integration in IDE Früh aufsetzen und mit dem Projekt wachsen
lassen
• Nur ein wohldefinierter Buildprozess erlaubt die Überprüfung von Änderungen. An jedem Arbeitsplatz verfügbar Muss gelebt werden Integration in IDE Früh aufsetzen und mit dem Projekt wachsen
lassen
25
Häufige Integration
• Es muss immer ein funktionstüchtiger Stand des Systems verfügbar sein. Systemteile früh aneinanderschrauben, damit
sie nicht auseinanderlaufen z.B. nächtlicher Build
• Es muss immer ein funktionstüchtiger Stand des Systems verfügbar sein. Systemteile früh aneinanderschrauben, damit
sie nicht auseinanderlaufen z.B. nächtlicher Build
26
Einwände gegen Refactoring
• Es gibt – teilweise tatsächliche – Hindernisse: „Design ist nicht mehr dokumentiert.“ „Refactoring lohnt sich nicht.“ „Wo sind die kurzfristigen Vorteile?“ „Es könnte etwas kaputtgehen.“
• Es gibt – teilweise tatsächliche – Hindernisse: „Design ist nicht mehr dokumentiert.“ „Refactoring lohnt sich nicht.“ „Wo sind die kurzfristigen Vorteile?“ „Es könnte etwas kaputtgehen.“
27
„Design ist nicht dokumentiert“
• Einwand: Durch Refactoring laufen Implementierung und Designdokumentation auseinander Im sehr großen Maßstab berechtigter Einwand Ansonsten:
• Gesonderte Designdokumentation veraltet ohnehin
• Quelltext gewinnt an Klarheit: Design wird im Quelltext expliziter
• Einwand: Durch Refactoring laufen Implementierung und Designdokumentation auseinander Im sehr großen Maßstab berechtigter Einwand Ansonsten:
• Gesonderte Designdokumentation veraltet ohnehin
• Quelltext gewinnt an Klarheit: Design wird im Quelltext expliziter
28
„Refactoring lohnt sich nicht“
• Einwand: Während des Refactorings implementiert man keine Funktionalität. Durch Refactoring gleichbleibend gutes Design System bleibt änderbar Nicht ästhetische Selbstbefriedigung
• Einwand: Während des Refactorings implementiert man keine Funktionalität. Durch Refactoring gleichbleibend gutes Design System bleibt änderbar Nicht ästhetische Selbstbefriedigung
29
„Keine kurzfristigen Vorteile“
• Einwand: Refactoring bringt langfristig Vorteile, aber nicht kurzfristig. Refactoring als Teil des jeweiligen
Arbeitspakets Kein Hauruck-Redesign, sondern hier ein
wenig und dort ein wenig. Vereinfacht die tägliche Arbeit und spart dabei
Zeit.
• Einwand: Refactoring bringt langfristig Vorteile, aber nicht kurzfristig. Refactoring als Teil des jeweiligen
Arbeitspakets Kein Hauruck-Redesign, sondern hier ein
wenig und dort ein wenig. Vereinfacht die tägliche Arbeit und spart dabei
Zeit.
30
„Es könnte etwas kaputt gehen“
• Einwand: Refactoring könnte bestehende Funktionalität kaputt machen. JUnit-Tests In kleinen Schritten vorgehen Bei Unsicherheit lieber vorsichtig sein Andererseits: bei jeder Änderung kann etwas
kaputtgehen...
• Einwand: Refactoring könnte bestehende Funktionalität kaputt machen. JUnit-Tests In kleinen Schritten vorgehen Bei Unsicherheit lieber vorsichtig sein Andererseits: bei jeder Änderung kann etwas
kaputtgehen...
31
Alternative: Einfach tun
• Wenn das Management nicht von Refactoring überzeugt ist, gibt es die Möglichkeit, es einfach zu tun Der „offizielle“ Weg ist besser Professionelle Verantwortung Es spart Zeit, wird sich also bewähren
• Wenn das Management nicht von Refactoring überzeugt ist, gibt es die Möglichkeit, es einfach zu tun Der „offizielle“ Weg ist besser Professionelle Verantwortung Es spart Zeit, wird sich also bewähren
32
Grenzen des Refactoring
• Es gibt Situationen, wo Refactoring nicht gut funktioniert. Relationale Datenbanken Fixierte Schnittstellen Hoffnungslos kaputtes System
• Es gibt Situationen, wo Refactoring nicht gut funktioniert. Relationale Datenbanken Fixierte Schnittstellen Hoffnungslos kaputtes System
33
Zusammenfassung
• Das Umfeld des Refactoring: Agile Prozesse erlauben es, spät Änderungen
am System durchzuführen Versionsverwaltung, Build Management Es gibt Einwände, mit denen man sich
auseinander setzen muss
• Refactoring ist lernbar: Keine Scheu!
• Das Umfeld des Refactoring: Agile Prozesse erlauben es, spät Änderungen
am System durchzuführen Versionsverwaltung, Build Management Es gibt Einwände, mit denen man sich
auseinander setzen muss
• Refactoring ist lernbar: Keine Scheu!
34
Übersicht
• Einführung
• Das Umfeld für Refactoring
„Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
• Einführung
• Das Umfeld für Refactoring
„Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
35
Wann Refactoring?
• Das „wie“ ist relativ einfach, aber wann und wo soll man refaktorieren? Lohnt sich ein bestimmtes Refactoring? In welche Richtung soll man gehen? Wo fängt man an? Wann soll man aufhören?
• Das „wie“ ist relativ einfach, aber wann und wo soll man refaktorieren? Lohnt sich ein bestimmtes Refactoring? In welche Richtung soll man gehen? Wo fängt man an? Wann soll man aufhören?
36
„Code Smells“
• „Geruch“ von Quelltexten ist eine Metapher, um über ihre Qualität zu reden. Katalog von Gerüchen Keine präzisen Kriterien Hilfestellung für die Intuition
• „Geruch“ von Quelltexten ist eine Metapher, um über ihre Qualität zu reden. Katalog von Gerüchen Keine präzisen Kriterien Hilfestellung für die Intuition
37
Duplizierter Code
• Wenn das Gleiche an zwei Stellen im Quelltext steht, „stinkt“ das zum Himmel. Der Quelltext ist unübersichtlich Das System ist schwer zu ändern Inkonsistenzen und damit Fehler schleichen
sich ein
• Wenn das Gleiche an zwei Stellen im Quelltext steht, „stinkt“ das zum Himmel. Der Quelltext ist unübersichtlich Das System ist schwer zu ändern Inkonsistenzen und damit Fehler schleichen
sich ein
38
Datenklasse
• Eine Klasse, die nur Daten und keine Logik enthält, ist ein Indiz für Verbesserungs-potential Oft gibt es Funktionalität, die im Wesentlichen
auf diesen Daten operiert Andernfalls ist vielleicht die Klasse schlecht
geschnitten
• Eine Klasse, die nur Daten und keine Logik enthält, ist ein Indiz für Verbesserungs-potential Oft gibt es Funktionalität, die im Wesentlichen
auf diesen Daten operiert Andernfalls ist vielleicht die Klasse schlecht
geschnitten
39
Kommentare
• Kommentare an sich „riechen“ gut, sie werden aber oft als „Deodorant“ verwendet. Kommentare sind Zeichen, dass der Quelltext
selbst nicht klar verständlich ist Kommentare können veralten oder in die Irre
führen
• Kommentare an sich „riechen“ gut, sie werden aber oft als „Deodorant“ verwendet. Kommentare sind Zeichen, dass der Quelltext
selbst nicht klar verständlich ist Kommentare können veralten oder in die Irre
führen
40
Unangebrachte Intimität
• Zwei Klassen, die ausgiebig gegenseitig Methoden aufrufen, sind oft nicht gut geschnitten. Sie sind eng gekoppelt und schwierig
unabhängig voneinander zu ändern Sie sind schwierig zu benutzen, weil sie keine
klare Aufgabenteilung haben
• Zwei Klassen, die ausgiebig gegenseitig Methoden aufrufen, sind oft nicht gut geschnitten. Sie sind eng gekoppelt und schwierig
unabhängig voneinander zu ändern Sie sind schwierig zu benutzen, weil sie keine
klare Aufgabenteilung haben
41
Neid
• Eine Methode, die im Wesentlichen auf Attributen einer anderen Klasse operiert, ist dort wahrscheinlich besser aufgehoben. Die Signatur der Methode wird dann einfacher
und die Aufgabenteilung der Klassen natürlicher
• Eine Methode, die im Wesentlichen auf Attributen einer anderen Klasse operiert, ist dort wahrscheinlich besser aufgehoben. Die Signatur der Methode wird dann einfacher
und die Aufgabenteilung der Klassen natürlicher
42
Switch
• Fallunterscheidungen mit „switch“ führen oft zu doppeltem Code, weil die gleichen Fälle mehrmals unterschieden werden. Switch ist nicht typsicher Man vergisst leicht Fälle Zusätzliche Fälle müssen an vielen Stellen
bedacht werden
• Fallunterscheidungen mit „switch“ führen oft zu doppeltem Code, weil die gleichen Fälle mehrmals unterschieden werden. Switch ist nicht typsicher Man vergisst leicht Fälle Zusätzliche Fälle müssen an vielen Stellen
bedacht werden
43
Lange Methode
• Lange Methoden sind aufwendiger zu verstehen als kurze. Kurze Methoden können durch ihre Namen den
Quelltext dokumentieren Durch Extrahieren kurzer Methoden
kann man Code-Duplizierung vermeiden und Aufgaben zwischen Klassen verschieben
• Lange Methoden sind aufwendiger zu verstehen als kurze. Kurze Methoden können durch ihre Namen den
Quelltext dokumentieren Durch Extrahieren kurzer Methoden
kann man Code-Duplizierung vermeiden und Aufgaben zwischen Klassen verschieben
44
Monster-Klasse
• Eine zu große Klasse wird unübersichtlich. Zu viele Attribute führen leicht zu Code-
Duplizierung
• Eine zu große Klasse wird unübersichtlich. Zu viele Attribute führen leicht zu Code-
Duplizierung
45
Datenklumpen
• Eine Gruppe von Daten, die oft zusammen vorkommt, kann man oft als Klasse zusammenfassen. Dieser Typ kann Funktionalität bekommen und
dadurch doppelten Code vermeiden Die Verwendung der Daten wird einfacher
• Eine Gruppe von Daten, die oft zusammen vorkommt, kann man oft als Klasse zusammenfassen. Dieser Typ kann Funktionalität bekommen und
dadurch doppelten Code vermeiden Die Verwendung der Daten wird einfacher
+ 5$
46
Unechte Primitive Datentypen
• Primitive Datentypen können oft besser durch Klassen ersetzt werden. Eigene Werttypen sind typsicher und
dokumentieren den Code Manchmal gibt es falsche Scheu vor „kleinen“
Klassen
• Primitive Datentypen können oft besser durch Klassen ersetzt werden. Eigene Werttypen sind typsicher und
dokumentieren den Code Manchmal gibt es falsche Scheu vor „kleinen“
Klassen
5$
47
Schrotkugeln herausoperieren
• Wenn man viele Klassen ändern muss, um einen Aspekt zu ändern, ließe er sich vielleicht an einer Stelle lokalisieren. Man übersieht sonst leicht eine Stelle Es entsteht leicht doppelter Code
• Wenn man viele Klassen ändern muss, um einen Aspekt zu ändern, ließe er sich vielleicht an einer Stelle lokalisieren. Man übersieht sonst leicht eine Stelle Es entsteht leicht doppelter Code
48
Kombinierte Abstraktionen
• Wenn eine Klasse von vielen verschiedenen Änderungen betroffen wird, ist es vielleicht besser, sie zu spalten. Sonst betreffen Änderungen potentiell mehr
Quelltext als nötig Aufteilung macht den Code übersichtlicher
• Wenn eine Klasse von vielen verschiedenen Änderungen betroffen wird, ist es vielleicht besser, sie zu spalten. Sonst betreffen Änderungen potentiell mehr
Quelltext als nötig Aufteilung macht den Code übersichtlicher
49
Lange Parameterliste
• Eine lange Parameterliste deutet auf Verbesserungspotential hin. Lange Parameterlisten sind unübersichtlich Sie neigen dazu, sich zu ändern Attribute oder Parameterobjekte sind besser
• Eine lange Parameterliste deutet auf Verbesserungspotential hin. Lange Parameterlisten sind unübersichtlich Sie neigen dazu, sich zu ändern Attribute oder Parameterobjekte sind besser
50
Faule Klasse
• Eine Klasse, die fast nichts mehr tut, kann mehr im Weg sein als nützen. Jede Klasse bedeutet Komplexität Der Nutzen kann kleiner werden als der Preis
• Eine Klasse, die fast nichts mehr tut, kann mehr im Weg sein als nützen. Jede Klasse bedeutet Komplexität Der Nutzen kann kleiner werden als der Preis
51
Hellseherei
• Oft berücksichtigen Leute sicherheitshalber Erweiterungen, die eventuell später benötigt werden. Das Design wird komplizierter, schwieriger zu
verstehen und ändern Indiz: Eine Methode oder
Klasse wird nur von Tests verwendet
• Oft berücksichtigen Leute sicherheitshalber Erweiterungen, die eventuell später benötigt werden. Das Design wird komplizierter, schwieriger zu
verstehen und ändern Indiz: Eine Methode oder
Klasse wird nur von Tests verwendet
52
Methodenketten
• Wenn man erst eine Reihe von get-Methoden aufrufen muss, um das eigentlich interessante Objekt zu bekommen, durchbricht das die Kapselung. Änderungen der dazwischenliegenden Klassen
betreffen den Client
• Wenn man erst eine Reihe von get-Methoden aufrufen muss, um das eigentlich interessante Objekt zu bekommen, durchbricht das die Kapselung. Änderungen der dazwischenliegenden Klassen
betreffen den Client
53
Vermittler
• Wenn viele Methoden einer Klasse den Aufruf einfach nur durchreichen, macht das das Interface unnötig kompliziert. Der Client sollte stattdessen direkt mit dem
inneren Objekt reden
• Wenn viele Methoden einer Klasse den Aufruf einfach nur durchreichen, macht das das Interface unnötig kompliziert. Der Client sollte stattdessen direkt mit dem
inneren Objekt reden
54
Alternative Klassen mit verschiedenen Schnittstellen
• Wenn mehrere Klassen das Gleiche tun, bedeutet das Code-Duplizierung mit allen ihren Problemen. Das gilt insbesondere bei unterschiedlichen
Interfaces
• Wenn mehrere Klassen das Gleiche tun, bedeutet das Code-Duplizierung mit allen ihren Problemen. Das gilt insbesondere bei unterschiedlichen
Interfaces
55
Ausgeschlagenes Erbe
• Wenn eine Unterklasse wesentliche Teile der Basisklasse ignoriert, irritiert das menschliche Leser. Wenn Implementierung ignoriert wird, ist das
nicht so schlimm Wenn Teile der Schnittstelle nicht unterstützt
werden, ist die Vererbung falsch
• Wenn eine Unterklasse wesentliche Teile der Basisklasse ignoriert, irritiert das menschliche Leser. Wenn Implementierung ignoriert wird, ist das
nicht so schlimm Wenn Teile der Schnittstelle nicht unterstützt
werden, ist die Vererbung falsch
56
Übersicht
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
• Toolunterstützung
57
Automatisierte Modultests
• Automatisierte Modultests reduzieren das Risiko beim Refactoring. automatisiert: Die Tests laufen auf Knopfdruck
ab und brauchen keine Nutzeraktion. Modultests: Getestet werden die einzelnen
Klassen.
• Automatisierte Modultests reduzieren das Risiko beim Refactoring. automatisiert: Die Tests laufen auf Knopfdruck
ab und brauchen keine Nutzeraktion. Modultests: Getestet werden die einzelnen
Klassen.
58
JUnit
• JUnit ist ein Framework zur Unterstützung von automatisierten Modultests. Tests sind Java-Klassen Test-Schreiben ist kein großer Overhead www.junit.org
• JUnit ist ein Framework zur Unterstützung von automatisierten Modultests. Tests sind Java-Klassen Test-Schreiben ist kein großer Overhead www.junit.org
59
Beispiel
• Ein dummes aber einfaches Beispiel... Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
• Ein dummes aber einfaches Beispiel... Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
60
Integration in IDE
• Der Aufruf von JUnit ist einfach. junit.jar in den ClassPath junit.swingui.TestRunner als Main-Klasse Den Namen des Testfalls als
Kommandozeilenparameter
• Der Aufruf von JUnit ist einfach. junit.jar in den ClassPath junit.swingui.TestRunner als Main-Klasse Den Namen des Testfalls als
Kommandozeilenparameter
61
Eine Testklasse je Klasse
• Typischerweise schreibt man zu jeder Klasse eine Testklasse. Testklasse erbt von junit.framework.TestCase Per Namenskonvention endet der Name der
Testklasse mit „Test“
• Typischerweise schreibt man zu jeder Klasse eine Testklasse. Testklasse erbt von junit.framework.TestCase Per Namenskonvention endet der Name der
Testklasse mit „Test“
TestCase
BriefmarkeTestBriefmarke
62
Tests
• Zu einer Test-Klasse gehören mehrere Test-Methoden. Namenskonvention: public void test... () Die Reihenfolge der Ausführung steht nicht fest Die Testmethoden müssen unabhängig
voneinander sein
• Zu einer Test-Klasse gehören mehrere Test-Methoden. Namenskonvention: public void test... () Die Reihenfolge der Ausführung steht nicht fest Die Testmethoden müssen unabhängig
voneinander sein
63
Assertions
• Die eigentlichen Tests erfolgen als Aufrufe der assert...-Methoden von TestCase. Wenn die Bedingung erfüllt ist, passiert nichts Wenn die Bedingung nicht
erfüllt ist, wird dieser Test abgebrochen und als fehl-geschlagen vorgemerkt
• Die eigentlichen Tests erfolgen als Aufrufe der assert...-Methoden von TestCase. Wenn die Bedingung erfüllt ist, passiert nichts Wenn die Bedingung nicht
erfüllt ist, wird dieser Test abgebrochen und als fehl-geschlagen vorgemerkt
64
TestSuite
• Mehrere Tests können als TestSuite zusammengefasst werden. Klasse junit.framework.TestSuite Eine TestSuite kann TestCases und TestSuites
enthalten
• Mehrere Tests können als TestSuite zusammengefasst werden. Klasse junit.framework.TestSuite Eine TestSuite kann TestCases und TestSuites
enthalten
Test
TestCase TestSuite
1..*
65
Beispiel (2)
• Eine zweite Klasse mit Tests kommt dazu. Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
• Eine zweite Klasse mit Tests kommt dazu. Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
66
Test vor Implementierung
• Man kann den Test schon beim Nachdenken über die geplante Funktionalität schreiben. Kleine Schritte: Ein wenig Testen, ein wenig
Implementieren usw. Wenn der Test erfolgreich durchläuft,
ist man fertig
• Man kann den Test schon beim Nachdenken über die geplante Funktionalität schreiben. Kleine Schritte: Ein wenig Testen, ein wenig
Implementieren usw. Wenn der Test erfolgreich durchläuft,
ist man fertig
67
Erst fehlschlagen lassen
• Das Ausprobieren des Tests vor der Implementierung gibt Sicherheit. Vielleicht klappt er ja schon... Man stellt sicher, dass er tatsächlich ausgeführt
wird
• Das Ausprobieren des Tests vor der Implementierung gibt Sicherheit. Vielleicht klappt er ja schon... Man stellt sicher, dass er tatsächlich ausgeführt
wird
68
Tests als Dokumentation
• Die Tests dokumentieren die getesteten Klassen genau. Sie zeigen die nötige Initialisierung Sie enthalten ein Beispiel für jede Methode Die Dokumentation ist nie veraltet
• Die Tests dokumentieren die getesteten Klassen genau. Sie zeigen die nötige Initialisierung Sie enthalten ein Beispiel für jede Methode Die Dokumentation ist nie veraltet
69
Beispiel (3)
• Das Beispiel wird noch einmal erweitert. Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
• Das Beispiel wird noch einmal erweitert. Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
70
Tests als Sicherheitsnetz
• Gute Tests schützen davor, unbeabsichtigt Funktionalität zu ändern, auf die sich andere Klassen verlassen. Das ist eine Voraussetzung für zuversichtliches
Refactoring Es hilft auch bei Erweiterungen und
Änderungen
• Gute Tests schützen davor, unbeabsichtigt Funktionalität zu ändern, auf die sich andere Klassen verlassen. Das ist eine Voraussetzung für zuversichtliches
Refactoring Es hilft auch bei Erweiterungen und
Änderungen
71
Wie fängt man an?
• Tests Schreiben braucht Übung, aber… der Einstieg ist leicht eine unvollständige Test-Suite ist hilfreich und
kann organisch wachsen durch Refactoring kann man später die Tests
verbessern Testen macht Spaß
• Tests Schreiben braucht Übung, aber… der Einstieg ist leicht eine unvollständige Test-Suite ist hilfreich und
kann organisch wachsen durch Refactoring kann man später die Tests
verbessern Testen macht Spaß
72
Zusammenfassung
• Refactoring
• Das Umfeld von Refactoring
• „Code Smells“
• JUnit
• Refactoring
• Das Umfeld von Refactoring
• „Code Smells“
• JUnit
73
Übersicht
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
Konkrete Refactorings
• Beispiel
• Toolunterstützung
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
Konkrete Refactorings
• Beispiel
• Toolunterstützung
74
Katalog
• Der Katalog ist Hilfestellung. Ziel ist „besserer Geruch“: Eigenes Urteil! Probieren und Fehler sind ungefährlich:
• JUnit-Tests• Man kann alles rückgängig machen
Einstieg: Problem Konkrete Schritte: damit man nichts
vergisst Am Ende: Immer compilieren und testen
• Der Katalog ist Hilfestellung. Ziel ist „besserer Geruch“: Eigenes Urteil! Probieren und Fehler sind ungefährlich:
• JUnit-Tests• Man kann alles rückgängig machen
Einstieg: Problem Konkrete Schritte: damit man nichts
vergisst Am Ende: Immer compilieren und testen
75
Change Inconsistent Layout
• Quelltext ist inkonsistent formatiert, insbesondere eingerückt. Layout an Quelltextrichtlinien anpassen Möglichst toolgestützt NICHT den eigenen Geschmack aufzwingen!
• Quelltext ist inkonsistent formatiert, insbesondere eingerückt. Layout an Quelltextrichtlinien anpassen Möglichst toolgestützt NICHT den eigenen Geschmack aufzwingen!
76
Replace Magic Number with Symbolic Constant
• In einer Methode steht eine Zahl (außer 0 und 1). Besser eine benannte Konstante einführen Name ist Dokumentation Wert ist besser änderbar Typcode, Arraylänge o.ä.? Dann Alternative
wählen
• In einer Methode steht eine Zahl (außer 0 und 1). Besser eine benannte Konstante einführen Name ist Dokumentation Wert ist besser änderbar Typcode, Arraylänge o.ä.? Dann Alternative
wählen
77
Replace Temp with Query
• Eine temporäre Variable enthält ein Zwischenergebnis. Den entsprechenden Ausdruck in eine Methode
auslagern Ursprüngliche Methode wird übersichtlicher Verfügbar im ganzen Objekt
• Eine temporäre Variable enthält ein Zwischenergebnis. Den entsprechenden Ausdruck in eine Methode
auslagern Ursprüngliche Methode wird übersichtlicher Verfügbar im ganzen Objekt
78
Rename Method (1)
• Der Name einer Methode spiegelt nicht (mehr) ihren Inhalt wieder. Den Namen ändern Analog Parameter hinzufügen oder entfernen
• Der Name einer Methode spiegelt nicht (mehr) ihren Inhalt wieder. Den Namen ändern Analog Parameter hinzufügen oder entfernen
79
Rename Method (2)
• Konkrete Schritte: Basis- und Unterklassen prüfen Methode mit neuem Namen anlegen,
Implementierung hineinkopieren, compilieren Clients schrittweise umstellen, jeweils testen Ursprüngliche Methode löschen, Testen
• Konkrete Schritte: Basis- und Unterklassen prüfen Methode mit neuem Namen anlegen,
Implementierung hineinkopieren, compilieren Clients schrittweise umstellen, jeweils testen Ursprüngliche Methode löschen, Testen
80
Replace Constructor with Factory Method
• Konstruktor ist nicht flexibel genug. Besser statische create-Methode verwenden Kontrolle über Instanzierung (Unterklassen,
Caching, Referenz-Semantik) Expliziter Name dokumentiert
• Konstruktor ist nicht flexibel genug. Besser statische create-Methode verwenden Kontrolle über Instanzierung (Unterklassen,
Caching, Referenz-Semantik) Expliziter Name dokumentiert
81
Extract Method (1)
• Mehrere Statements einer Methode gehören logisch zusammen. Auslagern in eigene Methode Sprechender Name für die neue Methode Ursprüngliche Methode wird übersichtlicher
• Mehrere Statements einer Methode gehören logisch zusammen. Auslagern in eigene Methode Sprechender Name für die neue Methode Ursprüngliche Methode wird übersichtlicher
82
Extract Method (2)
• Konkrete Schritte: Neue Methode anlegen und gut benennen Implementierung hineinkopieren Notwendige Parameter anlegen und benennen Ggf. Rückgabewert einführen Compilieren Code in ursprünglicher Methode durch Aufruf
ersetzen
• Konkrete Schritte: Neue Methode anlegen und gut benennen Implementierung hineinkopieren Notwendige Parameter anlegen und benennen Ggf. Rückgabewert einführen Compilieren Code in ursprünglicher Methode durch Aufruf
ersetzen
83
Inline Method (1)
• Der Code einer Methode ist genauso klar wie ihr Name. Methode inlinen Unnötige Methode ist nur Ballast Gegenstück zu „Extract Method“
• Der Code einer Methode ist genauso klar wie ihr Name. Methode inlinen Unnötige Methode ist nur Ballast Gegenstück zu „Extract Method“
84
Inline Method (2)
• Konkrete Schritte: Prüfen, dass die Methode nicht polymorph ist Jeden Aufruf durch den Inhalt ersetzen Compilieren und testen Methode löschen Bei Komplikationen nicht inlinen
• Konkrete Schritte: Prüfen, dass die Methode nicht polymorph ist Jeden Aufruf durch den Inhalt ersetzen Compilieren und testen Methode löschen Bei Komplikationen nicht inlinen
85
Remove Assignments to Parameters
• Eine Methode enthält eine Zuweisung an einen Parameter. Stattdessen temporäre Variable verwenden Erhöht Übersichtlichkeit
• Eine Methode enthält eine Zuweisung an einen Parameter. Stattdessen temporäre Variable verwenden Erhöht Übersichtlichkeit
86
Replace Method with Method Object (1)
• Eine Methode verwendet lokale Variablen so, dass Extract Method schwierig ist. Neue Klasse anlegen, die der Methode
entspricht Lokale Variablen werden zu Attributen Danach ist Refactoring leicht
• Eine Methode verwendet lokale Variablen so, dass Extract Method schwierig ist. Neue Klasse anlegen, die der Methode
entspricht Lokale Variablen werden zu Attributen Danach ist Refactoring leicht
87
Replace Method with Method Object (2)
• Konkrete Schritte: Neue Klasse anlegen Referenz auf ursprüngliche Klasse sowie
Attribute für die lokalen Variablen einführen Konstruktor zur Initialisierung Methode „compute“ einführen und die
ursprüngliche Implementierung hineinkopieren In der alten Methode an die neue delegieren
• Konkrete Schritte: Neue Klasse anlegen Referenz auf ursprüngliche Klasse sowie
Attribute für die lokalen Variablen einführen Konstruktor zur Initialisierung Methode „compute“ einführen und die
ursprüngliche Implementierung hineinkopieren In der alten Methode an die neue delegieren
88
Substitute Algorithm
• Ein Algorithmus ist komplizierter als nötig. Durch einen einfacheren Algorithmus ersetzen Insbesondere, wenn zwei verschiedene
Algorithmen für das Gleiche verwendet werden Optimierung allenfalls am Ende
• Ein Algorithmus ist komplizierter als nötig. Durch einen einfacheren Algorithmus ersetzen Insbesondere, wenn zwei verschiedene
Algorithmen für das Gleiche verwendet werden Optimierung allenfalls am Ende
89
Move Method (1)
• Eine Methode benutzt mehr Features oder wird von mehr Features einer anderen Klasse benutzt als der, wo sie definiert ist. Methode zu den Features verschieben Stärkere Kohäsion, schlankere Schnittstellen Das Original delegiert oder wird gelöscht
• Eine Methode benutzt mehr Features oder wird von mehr Features einer anderen Klasse benutzt als der, wo sie definiert ist. Methode zu den Features verschieben Stärkere Kohäsion, schlankere Schnittstellen Das Original delegiert oder wird gelöscht
90
Move Method (2)
• Konkrete Schritte: Benutzte Felder und Methoden ggf.
mitverschieben Vererbungshierarchie prüfen Methode in der neuen Klasse deklarieren Implementierung hineinkopieren und anpassen Compilieren Aufrufe ändern oder alte Methode umbiegen
• Konkrete Schritte: Benutzte Felder und Methoden ggf.
mitverschieben Vererbungshierarchie prüfen Methode in der neuen Klasse deklarieren Implementierung hineinkopieren und anpassen Compilieren Aufrufe ändern oder alte Methode umbiegen
91
Move Field (1)
• Ein Feld wird in einer anderen Klasse mehr benutzt Dorthin verschieben Bessere Kohäsion und schlankere Schnittstelle Eventuell Methoden mitverschieben
• Ein Feld wird in einer anderen Klasse mehr benutzt Dorthin verschieben Bessere Kohäsion und schlankere Schnittstelle Eventuell Methoden mitverschieben
92
Move Field (2)
• Konkrete Schritte: In Zielklasse ein Feld mit get- und set-Methode
anlegen Navigation von alter zu neuer Klasse
sicherstellen Ursprüngliches Feld entfernen Zugriffe umbiegen (inkl. Unterklassen) Compilieren und testen
• Konkrete Schritte: In Zielklasse ein Feld mit get- und set-Methode
anlegen Navigation von alter zu neuer Klasse
sicherstellen Ursprüngliches Feld entfernen Zugriffe umbiegen (inkl. Unterklassen) Compilieren und testen
93
Extract Class (1)
• Eine Klasse macht die Arbeit von zweien. Neue Klasse anlegen und Felder und Methoden
hineinverschieben Übersichtlichkeit durch klare Aufgabenteilung
• Eine Klasse macht die Arbeit von zweien. Neue Klasse anlegen und Felder und Methoden
hineinverschieben Übersichtlichkeit durch klare Aufgabenteilung
94
Extract Class (2)
• Konkrete Schritte: Aufteilung planen Neue Klasse anlegen, Referenz von alter zu
neuer Einzelne Felder und Methoden verschieben Schnittstellen überarbeiten Ggf. neue Klasse veröffentlichen
(Referenz/Wert)
• Konkrete Schritte: Aufteilung planen Neue Klasse anlegen, Referenz von alter zu
neuer Einzelne Felder und Methoden verschieben Schnittstellen überarbeiten Ggf. neue Klasse veröffentlichen
(Referenz/Wert)
95
Hide Delegate
• Ein Client holt sich von einem Objekt ein anderes Objekt und ruft darauf eine Methode auf. Im ersten Objekt eine Methode erzeugen, die
dann delegiert Dadurch bessere Kapselung
• Ein Client holt sich von einem Objekt ein anderes Objekt und ruft darauf eine Methode auf. Im ersten Objekt eine Methode erzeugen, die
dann delegiert Dadurch bessere Kapselung
96
Remove Middle Man
• Eine Klasse delegiert eine Reihe von Aufrufen einfach an ein anderes Objekt. Stattdessen inneres Objekt herausreichen get-Methode einführen Dadurch Übersichtlichkeit erhöhen
• Eine Klasse delegiert eine Reihe von Aufrufen einfach an ein anderes Objekt. Stattdessen inneres Objekt herausreichen get-Methode einführen Dadurch Übersichtlichkeit erhöhen
97
Replace Data Value with Object
• Ein primitives Attribut hat eigentlich dazugehörige Funktionalität. Spezielle Klasse schaffen und deren Instanz
verwenden Clients nach und nach umstellen Wert-Semantik: Identität spielt keine Rolle
• Ein primitives Attribut hat eigentlich dazugehörige Funktionalität. Spezielle Klasse schaffen und deren Instanz
verwenden Clients nach und nach umstellen Wert-Semantik: Identität spielt keine Rolle
98
Replace Type Code with Subclass (1)
• Eine Klasse hat einen Typcode, der über das Verhalten entscheidet. Für jeden Wert des Typcodes eine Unterklasse Grundlage für weitere Refactorings
• Eine Klasse hat einen Typcode, der über das Verhalten entscheidet. Für jeden Wert des Typcodes eine Unterklasse Grundlage für weitere Refactorings
99
Replace Type Code with Subclass (2)
• Konkrete Schritte: Auf Typcode nur durch get-Methode zugreifen statische create-Methode einführen Für jeden Wert eine Unterklasse einführen, die
die get-Methode überschreibt Typcode-Attribut aus der Basisklasse entfernen
• Konkrete Schritte: Auf Typcode nur durch get-Methode zugreifen statische create-Methode einführen Für jeden Wert eine Unterklasse einführen, die
die get-Methode überschreibt Typcode-Attribut aus der Basisklasse entfernen
100
Replace Type Code with State/Strategy (1)
• Ein Typ-Code entscheidet über Verhalten, aber es gibt schon Unterklassen. Zweite Vererbungshierarchie für Typ-Code Als State/Strategy anbinden
• Ein Typ-Code entscheidet über Verhalten, aber es gibt schon Unterklassen. Zweite Vererbungshierarchie für Typ-Code Als State/Strategy anbinden
101
Replace Type Code with State/Strategy (2)
• Konkrete Schritte: Den Typ-Code hinter get-Methode kapseln Neue Klasse mit Unterklassen für jeden Wert
schaffen (State-Klasse) Typ-Code in die neue Klassenhierarchie
verschieben Beim Setzen des Typ-Codes stattdessen State
ändern Typ-Feld entfernen
• Konkrete Schritte: Den Typ-Code hinter get-Methode kapseln Neue Klasse mit Unterklassen für jeden Wert
schaffen (State-Klasse) Typ-Code in die neue Klassenhierarchie
verschieben Beim Setzen des Typ-Codes stattdessen State
ändern Typ-Feld entfernen
102
Replace Conditional with Polymorphism (1)
• Verhalten wird über einen Typ-Code ausgewählt. Für jeden Typcode eine Unterklasse Spezifisches Verhalten jeweils in einer
überschriebenen Methode Man vergisst keine Fälle und gruppiert Logik
• Verhalten wird über einen Typ-Code ausgewählt. Für jeden Typcode eine Unterklasse Spezifisches Verhalten jeweils in einer
überschriebenen Methode Man vergisst keine Fälle und gruppiert Logik
103
Replace Conditional with Polymorphism (2)
• Konkrete Schritte: Replace Type Code with ... Ggf. Fallunterscheidung in eigene Methode Der Reihe nach:
• Für Unterklassen die Methode überschreiben und testen
• Den Fall aus der ursprünglichen Methode entfernen und testen
Methode in der Basisklasse abstrakt machen
• Konkrete Schritte: Replace Type Code with ... Ggf. Fallunterscheidung in eigene Methode Der Reihe nach:
• Für Unterklassen die Methode überschreiben und testen
• Den Fall aus der ursprünglichen Methode entfernen und testen
Methode in der Basisklasse abstrakt machen
104
Replace Subclass with Fields (1)
• Unterklassen unterscheiden sich nur in Methoden, die konstante Werte liefern. Die Unterklassen entfernen und die Werte aus
Attributen holen Die Unterklassen sind unnötiger Ballast
geworden
• Unterklassen unterscheiden sich nur in Methoden, die konstante Werte liefern. Die Unterklassen entfernen und die Werte aus
Attributen holen Die Unterklassen sind unnötiger Ballast
geworden
105
Replace Subclass with Fields (2)
• Konkrete Schritte: Statische create-Methode einführen final Felder in der Basisklasse einführen mit
protected Konstruktor, der sie initialisiert Unterklassen so ändern, dass sie diesen
aufrufen Die Methoden in der Basisklasse ändern, so
dass sie die Werte der Felder liefern Unterklassen entfernen
• Konkrete Schritte: Statische create-Methode einführen final Felder in der Basisklasse einführen mit
protected Konstruktor, der sie initialisiert Unterklassen so ändern, dass sie diesen
aufrufen Die Methoden in der Basisklasse ändern, so
dass sie die Werte der Felder liefern Unterklassen entfernen
106
Consolidate Duplicate Conditional Fragments
• Ein gemeinsames Stück Code ist in allen Zweigen einer Fallunterscheidung. Gemeinsamen Code herausziehen Entweder davor oder dahinter Sonst eventuell in eigene Methode
• Ein gemeinsames Stück Code ist in allen Zweigen einer Fallunterscheidung. Gemeinsamen Code herausziehen Entweder davor oder dahinter Sonst eventuell in eigene Methode
107
Remove Control Flag
• Ein Flag kontrolliert den Ablauf einer Schleife. Besser break, continue und return verwenden Kürzer und übersichtlicher
• Ein Flag kontrolliert den Ablauf einer Schleife. Besser break, continue und return verwenden Kürzer und übersichtlicher
108
Replace Nested Conditional with Guard Clause
• Eine Methode hat verschachtelte if-Statements, um ohne zweites return auszukommen. Sonderfälle am Anfang behandeln und dort
direkt zurückkehren Prüflogik in eigene Methoden auslagern Normalfall wird explizit
• Eine Methode hat verschachtelte if-Statements, um ohne zweites return auszukommen. Sonderfälle am Anfang behandeln und dort
direkt zurückkehren Prüflogik in eigene Methoden auslagern Normalfall wird explizit
109
Separate Query from Modifier (1)
• Eine Methode führt eine Abfrage durch und ändert gleichzeitig den Zustand des Objekts. Aufspalten in reine Abfrage und Modifikation Reine Abfrage ist vielseitig einsetzbar und
leicht zu verstehen Optimieren allenfalls später Multithreading / Remote: Sonderfälle
• Eine Methode führt eine Abfrage durch und ändert gleichzeitig den Zustand des Objekts. Aufspalten in reine Abfrage und Modifikation Reine Abfrage ist vielseitig einsetzbar und
leicht zu verstehen Optimieren allenfalls später Multithreading / Remote: Sonderfälle
110
Separate Query from Modifier (2)
• Konkrete Schritte: Die reine Abfrage als eigene Methode bauen In der ursprünglichen Methode das Ergebnis
der Abfrage zurückgeben Compilieren und testen In Aufrufen die Abfrage in eigenen Aufruf vor
die alte Methode setzen Rückgabe der alten Methode entfernen
• Konkrete Schritte: Die reine Abfrage als eigene Methode bauen In der ursprünglichen Methode das Ergebnis
der Abfrage zurückgeben Compilieren und testen In Aufrufen die Abfrage in eigenen Aufruf vor
die alte Methode setzen Rückgabe der alten Methode entfernen
111
Parameterize Method
• Mehrere Methoden tun das Gleiche mit unterschiedlichen fest verdrahteten Werten. Zusammenführen in eine einzige Methode mit
Parameter Vermeidet Code-Duplizierung
• Mehrere Methoden tun das Gleiche mit unterschiedlichen fest verdrahteten Werten. Zusammenführen in eine einzige Methode mit
Parameter Vermeidet Code-Duplizierung
112
Replace Parameter with Explicit Methods
• Ein Methode macht völlig verschiedene Dinge abhängig vom Wert eines Parameters. In mehrere Methoden mit sprechenden Namen
zerlegen
• Ein Methode macht völlig verschiedene Dinge abhängig vom Wert eines Parameters. In mehrere Methoden mit sprechenden Namen
zerlegen
113
Preserve Whole Object
• Eine Methode bekommt mehrere Attribute des gleichen Objekts als Parameter. Besser das ganze Objekt als Parameter
hineinreichen Außer man will bewusst entkoppeln
• Eine Methode bekommt mehrere Attribute des gleichen Objekts als Parameter. Besser das ganze Objekt als Parameter
hineinreichen Außer man will bewusst entkoppeln
114
Replace Parameter with Method
• Eine Methode bekommt einen Parameter, den sie auch selbst ermitteln könnte. Parameter ermitteln und aus der Signatur
entfernen Durch Methode von this oder von einem
anderen Parameter
• Eine Methode bekommt einen Parameter, den sie auch selbst ermitteln könnte. Parameter ermitteln und aus der Signatur
entfernen Durch Methode von this oder von einem
anderen Parameter
115
Introduce Parameter Object (1)
• Mehrere Parameter bilden eine natürliche Einheit. Zu einem neuen Typ zusammenfassen Wertsemantik Typsicher, besser lesbar
• Mehrere Parameter bilden eine natürliche Einheit. Zu einem neuen Typ zusammenfassen Wertsemantik Typsicher, besser lesbar
116
Introduce Parameter Object (2)
• Konkrete Schritte: Neue Klasse leer anlegen Die Parameter als Attribute hinzufügen. Dabei
die Werte immutable machen Den jeweiligen Parameter aus dem Aufruf
entfernen. Compilieren und Testen Funktionalität in die neue Klasse extrahieren
• Konkrete Schritte: Neue Klasse leer anlegen Die Parameter als Attribute hinzufügen. Dabei
die Werte immutable machen Den jeweiligen Parameter aus dem Aufruf
entfernen. Compilieren und Testen Funktionalität in die neue Klasse extrahieren
117
Remove Setting Method
• Ein Feld wird nur bei der Erzeugung gesetzt und anschließend nicht mehr geändert. Ggf. Konstruktor einführen Set-Methode entfernen Feld final machen
• Ein Feld wird nur bei der Erzeugung gesetzt und anschließend nicht mehr geändert. Ggf. Konstruktor einführen Set-Methode entfernen Feld final machen
118
Encapsulate Downcast
• Eine Methode liefert eine Referenz, die erst nach Downcast verwendbar ist (z.B. ein Element einer Collection). Downcast in der Methode durchführen und den
richtigen Typ zurückliefern Erhöht die Übersichtlichkeit und Typsicherheit
• Eine Methode liefert eine Referenz, die erst nach Downcast verwendbar ist (z.B. ein Element einer Collection). Downcast in der Methode durchführen und den
richtigen Typ zurückliefern Erhöht die Übersichtlichkeit und Typsicherheit
119
Pull Up Method
• Unterklassen haben Methoden mit dem gleichen Ergebnis. Methoden in die Basisklasse verschieben Code-Duplizierung vermeiden Eventuell unterschiedliche Algorithmen
• Unterklassen haben Methoden mit dem gleichen Ergebnis. Methoden in die Basisklasse verschieben Code-Duplizierung vermeiden Eventuell unterschiedliche Algorithmen
120
Push Down Method
• Eine Methode der Basisklasse wird nur von einer Unterklasse verwendet. Die Methode in diese Unterklasse verschieben Macht die Basisklasse einfacher Dokumentiert die Abhängigkeiten
• Eine Methode der Basisklasse wird nur von einer Unterklasse verwendet. Die Methode in diese Unterklasse verschieben Macht die Basisklasse einfacher Dokumentiert die Abhängigkeiten
121
Extract Superclass
• Mehrere Klassen haben teilweise die gleichen Methoden. Gemeinsamkeiten in eine Basisklasse ziehen Dokumentiert Beziehung zwischen den Klassen Öffnet den Blick für Verwendung dieser neuen
Abstraktion
• Mehrere Klassen haben teilweise die gleichen Methoden. Gemeinsamkeiten in eine Basisklasse ziehen Dokumentiert Beziehung zwischen den Klassen Öffnet den Blick für Verwendung dieser neuen
Abstraktion
122
Form Template Method (1)
• Unterklassen haben Methoden, die ähnliche Schritte in der gleichen Reihenfolge durchführen. Methoden extrahieren für Schritte, die von
einer neuen Methode der Basisklasse aufgerufen werden
Vermeidet Code-Duplizierung, dokumentiert Beziehungen
• Unterklassen haben Methoden, die ähnliche Schritte in der gleichen Reihenfolge durchführen. Methoden extrahieren für Schritte, die von
einer neuen Methode der Basisklasse aufgerufen werden
Vermeidet Code-Duplizierung, dokumentiert Beziehungen
123
Form Template Method (2)
• Konkrete Schritte: Methoden zerlegen Methodensignaturen vereinheitlichen Jeweils compilieren und testen Ursprüngliche Methode in Basisklasse ziehen
• Konkrete Schritte: Methoden zerlegen Methodensignaturen vereinheitlichen Jeweils compilieren und testen Ursprüngliche Methode in Basisklasse ziehen
124
Replace Inheritance with Delegation
• Eine Unterklasse will nur einen Teil der Schnittstelle der Basisklasse haben. Besser Aufrufe an eine Instanz der Basisklasse
durchreichen Klarere Beziehungen: Vererbung legt
Polymorphie nahe
• Eine Unterklasse will nur einen Teil der Schnittstelle der Basisklasse haben. Besser Aufrufe an eine Instanz der Basisklasse
durchreichen Klarere Beziehungen: Vererbung legt
Polymorphie nahe
125
Der Code ist das Design
• Alle hier präsentierten Refactorings wollen das Design im Quelltext klarer ausdrücken. Namen sind sehr wichtig Klarheit und Einfachheit Compilerunterstützung
• Diese Ziele sind wichtiger als das Verwenden konkreter Refactorings!
• Alle hier präsentierten Refactorings wollen das Design im Quelltext klarer ausdrücken. Namen sind sehr wichtig Klarheit und Einfachheit Compilerunterstützung
• Diese Ziele sind wichtiger als das Verwenden konkreter Refactorings!
126
Übersicht
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
Beispiel
• Toolunterstützung
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
Beispiel
• Toolunterstützung
127
Beispiel
• Ein praktisches Beispiel der Refactorings Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
• Ein praktisches Beispiel der Refactorings Der Quelltext ist im Internet verfügbar:
www.haase-consulting.com/download/oop2002
128
Übersicht
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
Toolunterstützung
• Einführung
• Das Umfeld für Refactoring
• „Code Smells“ als Wegweiser
• Automatisierte Tests mit JUnit
• Konkrete Refactorings
• Beispiel
Toolunterstützung
129
Toolunterstütztes Refactoring
• Die Durchführung des Refactoring lässt sich weitgehend automatisieren. Schutz vor Flüchtigkeitsfehlern Mehr als „Suchen und Ersetzen“ Plausibilitätsprüfungen
• Die Durchführung des Refactoring lässt sich weitgehend automatisieren. Schutz vor Flüchtigkeitsfehlern Mehr als „Suchen und Ersetzen“ Plausibilitätsprüfungen
130
Kriterien für Toolauswahl
• Folgende Punkte stellen Kriterien für die Auswahl eines Refactoring-Tools dar: Zuverlässigkeit Integration mit IDE Auf dem Parse-Baum operieren („Extract
Method“ als Indiz) Geschwindigkeit
• Folgende Punkte stellen Kriterien für die Auswahl eines Refactoring-Tools dar: Zuverlässigkeit Integration mit IDE Auf dem Parse-Baum operieren („Extract
Method“ als Indiz) Geschwindigkeit
131
Refactoring-Tools
• Hier eine Auswahl von aktuellen Refactoring-Tools für Java: Idea (www.intellij.com) Xrefactory (xref-tech.com/speller) Eclipse (www.eclipse.org) ...
• Hier eine Auswahl von aktuellen Refactoring-Tools für Java: Idea (www.intellij.com) Xrefactory (xref-tech.com/speller) Eclipse (www.eclipse.org) ...
132
Toolunterstützung praktisch
• Demonstration für toolgestütztes Refactoring So einfach kann Refactoring in der Praxis sein.
• Demonstration für toolgestütztes Refactoring So einfach kann Refactoring in der Praxis sein.
133
Literatur
• Folgende Quellen sind gute Startpunktefür eine Vertiefung: „Refactoring“, Martin Fowler www.refactoring.org www.junit.org „Extreme Programming Explained“,
Kent Beck
• Folgende Quellen sind gute Startpunktefür eine Vertiefung: „Refactoring“, Martin Fowler www.refactoring.org www.junit.org „Extreme Programming Explained“,
Kent Beck
134
Zusammenfassung
• Refactoring
• Das Umfeld von Refactoring
• „Code Smells“
• JUnit
• Refactoring-Katalog
• Toolunterstützung
• Refactoring
• Das Umfeld von Refactoring
• „Code Smells“
• JUnit
• Refactoring-Katalog
• Toolunterstützung