Refactoring Java Code Arno HaaseHaaseConsulting com Arno Haaseacm

  • Slides: 134
Download presentation
Refactoring Java Code Arno. Haase@Haase-Consulting. com Arno. Haase@acm. org www. Haase-Consulting. com

Refactoring Java Code Arno. Haase@Haase-Consulting. com Arno. Haase@acm. org www. Haase-Consulting. com

Übersicht Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte

Übersicht Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte Tests mit JUnit • Konkrete Refactorings • Beispiel • Toolunterstützung 2

„Refactoring“, Martin Fowler • Dieses Tutorial beruht im Wesentlichen auf dem Buch „Refactoring –

„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 3

Refactoring: Definition „Refactoring ist die Verbesserung der Qualität von vorhandenem Quelltext ohne Veränderung der

Refactoring: Definition „Refactoring ist die Verbesserung der Qualität von vorhandenem Quelltext ohne Veränderung der Funktionalität. “ 4

Problem • Das Design eines Systems neigt dazu, im Laufe der Zeit immer schlechter

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 5

Refactoring als Gegenmittel • Um dem entgegenzuwirken, muss das Design mit dem System wachsen.

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 6

Demonstration • Ein Quelltext sagt mehr als tausend Folien. . . § Der Quelltext

Demonstration • Ein Quelltext sagt mehr als tausend Folien. . . § Der Quelltext ist im Internet verfügbar: www. haase-consulting. com/download/oop 2002 7

Was ist geschehen? • Ein Stück Software wurde überarbeitet, ohne dass sich sein Verhalten

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 8

Wann Refactoring • Der richtige Zeitpunkt für Refactoring ist, wenn man sich ohnehin mit

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 9

Kleine Schritte • Refactoring funktioniert am besten, wenn man es in kleinen Schritten tut.

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 10

Die beiden Hüte • Refactoring und Erweiterung des Systems wechseln sich ab. § Saubere

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 11

Zusammenfassung • Refactoring erlaubt es, nachträglich Designentscheidungen zu ändern. § Zeitpunkt: wenn man ohnehin

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. 12

Übersicht • Einführung Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte

Übersicht • Einführung Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte Tests mit JUnit • Konkrete Refactorings • Beispiel • Toolunterstützung 13

Altersschwäche • Software kann an Altersschwäche sterben. § Design wächst nicht mit den Anforderungen

Altersschwäche • Software kann an Altersschwäche sterben. § Design wächst nicht mit den Anforderungen § Wartung als Albtraum § Manchmal schon vor Inbetriebnahme. . . 14

Hellseherei • Fixiertes Design vorab ist problematisch. § § Anforderungen ändern sich Das Verständnis

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) 15

Traditionelles Vorgehen • Das Wasserfall-Modell ist immer noch sehr verbreitet. § Änderungen werden mit

Traditionelles Vorgehen • Das Wasserfall-Modell ist immer noch sehr verbreitet. § Änderungen werden mit der Zeit teurer § Risiko minimieren 16

Änderungen billig machen • Agile Vorgehensmodelle unterstützen späte Änderungen § Z. B. e. Xtreme

Änderungen billig machen • Agile Vorgehensmodelle unterstützen späte Änderungen § Z. B. e. Xtreme Programming § Weniger Gewicht auf Planung am Anfang § System profitiert von wachsender Erfahrung 17

Kriterien für das Vorgehensmodell • Refactoring funktioniert am besten in einem Vorgehensmodell, bei dem

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. 18

Source-Code enthält das Design • Refactoring ändert das Design schrittweise im Quelltext. Sonstige Design.

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 19

Einfachheit als Wert • Softwareentwicklung ist eine der kompliziertesten Tätigkeiten der Welt. § Quelltexte

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 20

Wenn du es siehst, tue es • Ein Problem lieber gleich angehen als es

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. 21

Qualität als Wert? • Qualität als Wert entwickelt leicht eine Eigendynamik. § Qualität ist

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“ 22

Versionsverwaltung • Eine Versionsverwaltung ist eine wichtige Voraussetzung für Refactoring, besonders im Team. §

Versionsverwaltung • Eine Versionsverwaltung ist eine wichtige Voraussetzung für Refactoring, besonders im Team. § Reversibilität von Refactorings § Kurze Check-In-Zyklen 23

Buildprozess • Nur ein wohldefinierter Buildprozess erlaubt die Überprüfung von Änderungen. § An jedem

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 24

Häufige Integration • Es muss immer ein funktionstüchtiger Stand des Systems verfügbar sein. §

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 25

Einwände gegen Refactoring • Es gibt – teilweise tatsächliche – Hindernisse: § § „Design

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. “ 26

„Design ist nicht dokumentiert“ • Einwand: Durch Refactoring laufen Implementierung und Designdokumentation auseinander §

„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 27

„Refactoring lohnt sich nicht“ • Einwand: Während des Refactorings implementiert man keine Funktionalität. §

„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 28

„Keine kurzfristigen Vorteile“ • Einwand: Refactoring bringt langfristig Vorteile, aber nicht kurzfristig. § Refactoring

„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. 29

„Es könnte etwas kaputt gehen“ • Einwand: Refactoring könnte bestehende Funktionalität kaputt machen. §

„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. . . 30

Alternative: Einfach tun • Wenn das Management nicht von Refactoring überzeugt ist, gibt es

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 31

Grenzen des Refactoring • Es gibt Situationen, wo Refactoring nicht gut funktioniert. § Relationale

Grenzen des Refactoring • Es gibt Situationen, wo Refactoring nicht gut funktioniert. § Relationale Datenbanken § Fixierte Schnittstellen § Hoffnungslos kaputtes System 32

Zusammenfassung • Das Umfeld des Refactoring: § Agile Prozesse erlauben es, spät Änderungen am

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! 33

Übersicht • Einführung • Das Umfeld für Refactoring „Code Smells“ als Wegweiser • Automatisierte

Übersicht • Einführung • Das Umfeld für Refactoring „Code Smells“ als Wegweiser • Automatisierte Tests mit JUnit • Konkrete Refactorings • Beispiel • Toolunterstützung 34

Wann Refactoring? • Das „wie“ ist relativ einfach, aber wann und wo soll man

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? 35

„Code Smells“ • „Geruch“ von Quelltexten ist eine Metapher, um über ihre Qualität zu

„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 36

Duplizierter Code • Wenn das Gleiche an zwei Stellen im Quelltext steht, „stinkt“ das

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 37

Datenklasse • Eine Klasse, die nur Daten und keine Logik enthält, ist ein Indiz

Datenklasse • Eine Klasse, die nur Daten und keine Logik enthält, ist ein Indiz für Verbesserungspotential § Oft gibt es Funktionalität, die im Wesentlichen auf diesen Daten operiert § Andernfalls ist vielleicht die Klasse schlecht geschnitten 38

Kommentare • Kommentare an sich „riechen“ gut, sie werden aber oft als „Deodorant“ verwendet.

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 39

Unangebrachte Intimität • Zwei Klassen, die ausgiebig gegenseitig Methoden aufrufen, sind oft nicht gut

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 40

Neid • Eine Methode, die im Wesentlichen auf Attributen einer anderen Klasse operiert, ist

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 41

Switch • Fallunterscheidungen mit „switch“ führen oft zu doppeltem Code, weil die gleichen Fälle

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 42

Lange Methode • Lange Methoden sind aufwendiger zu verstehen als kurze. § Kurze Methoden

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 43

Monster-Klasse • Eine zu große Klasse wird unübersichtlich. § Zu viele Attribute führen leicht

Monster-Klasse • Eine zu große Klasse wird unübersichtlich. § Zu viele Attribute führen leicht zu Code. Duplizierung 44

Datenklumpen • Eine Gruppe von Daten, die oft zusammen vorkommt, kann man oft als

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 + 5$ 45

Unechte Primitive Datentypen • Primitive Datentypen können oft besser durch Klassen ersetzt werden. §

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 5$ 46

Schrotkugeln herausoperieren • Wenn man viele Klassen ändern muss, um einen Aspekt zu ändern,

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 47

Kombinierte Abstraktionen • Wenn eine Klasse von vielen verschiedenen Änderungen betroffen wird, ist es

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 48

Lange Parameterliste • Eine lange Parameterliste deutet auf Verbesserungspotential hin. § Lange Parameterlisten sind

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 49

Faule Klasse • Eine Klasse, die fast nichts mehr tut, kann mehr im Weg

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 50

Hellseherei • Oft berücksichtigen Leute sicherheitshalber Erweiterungen, die eventuell später benötigt werden. § Das

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 51

Methodenketten • Wenn man erst eine Reihe von get. Methoden aufrufen muss, um das

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 52

Vermittler • Wenn viele Methoden einer Klasse den Aufruf einfach nur durchreichen, macht das

Vermittler • Wenn viele Methoden einer Klasse den Aufruf einfach nur durchreichen, macht das Interface unnötig kompliziert. § Der Client sollte stattdessen direkt mit dem inneren Objekt reden 53

Alternative Klassen mit verschiedenen Schnittstellen • Wenn mehrere Klassen das Gleiche tun, bedeutet das

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 54

Ausgeschlagenes Erbe • Wenn eine Unterklasse wesentliche Teile der Basisklasse ignoriert, irritiert das menschliche

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 55

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser Automatisierte

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser Automatisierte Tests mit JUnit • Konkrete Refactorings • Beispiel • Toolunterstützung 56

Automatisierte Modultests • Automatisierte Modultests reduzieren das Risiko beim Refactoring. § automatisiert: Die Tests

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. 57

JUnit • JUnit ist ein Framework zur Unterstützung von automatisierten Modultests. § Tests sind

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 58

Beispiel • Ein dummes aber einfaches Beispiel. . . § Der Quelltext ist im

Beispiel • Ein dummes aber einfaches Beispiel. . . § Der Quelltext ist im Internet verfügbar: www. haase-consulting. com/download/oop 2002 59

Integration in IDE • Der Aufruf von JUnit ist einfach. § junit. jar in

Integration in IDE • Der Aufruf von JUnit ist einfach. § junit. jar in den Class. Path § junit. swingui. Test. Runner als Main-Klasse § Den Namen des Testfalls als Kommandozeilenparameter 60

Eine Testklasse je Klasse • Typischerweise schreibt man zu jeder Klasse eine Testklasse. §

Eine Testklasse je Klasse • Typischerweise schreibt man zu jeder Klasse eine Testklasse. § Testklasse erbt von junit. framework. Test. Case § Per Namenskonvention endet der Name der Testklasse mit „Test“ Test. Case Briefmarke. Test 61

Tests • Zu einer Test-Klasse gehören mehrere Test. Methoden. § Namenskonvention: public void test.

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 62

Assertions • Die eigentlichen Tests erfolgen als Aufrufe der assert. . . -Methoden von

Assertions • Die eigentlichen Tests erfolgen als Aufrufe der assert. . . -Methoden von Test. Case. § Wenn die Bedingung erfüllt ist, passiert nichts § Wenn die Bedingung nicht erfüllt ist, wird dieser Test abgebrochen und als fehlgeschlagen vorgemerkt 63

Test. Suite • Mehrere Tests können als Test. Suite zusammengefasst werden. § Klasse junit.

Test. Suite • Mehrere Tests können als Test. Suite zusammengefasst werden. § Klasse junit. framework. Test. Suite § Eine Test. Suite kann Test. Cases und Test. Suites enthalten Test. Case 1. . * Test. Suite 64

Beispiel (2) • Eine zweite Klasse mit Tests kommt dazu. § Der Quelltext ist

Beispiel (2) • Eine zweite Klasse mit Tests kommt dazu. § Der Quelltext ist im Internet verfügbar: www. haase-consulting. com/download/oop 2002 65

Test vor Implementierung • Man kann den Test schon beim Nachdenken über die geplante

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 66

Erst fehlschlagen lassen • Das Ausprobieren des Tests vor der Implementierung gibt Sicherheit. §

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 67

Tests als Dokumentation • Die Tests dokumentieren die getesteten Klassen genau. § Sie zeigen

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 68

Beispiel (3) • Das Beispiel wird noch einmal erweitert. § Der Quelltext ist im

Beispiel (3) • Das Beispiel wird noch einmal erweitert. § Der Quelltext ist im Internet verfügbar: www. haase-consulting. com/download/oop 2002 69

Tests als Sicherheitsnetz • Gute Tests schützen davor, unbeabsichtigt Funktionalität zu ändern, auf die

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 70

Wie fängt man an? • Tests Schreiben braucht Übung, aber… § der Einstieg ist

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ß 71

Zusammenfassung • • Refactoring Das Umfeld von Refactoring „Code Smells“ JUnit 72

Zusammenfassung • • Refactoring Das Umfeld von Refactoring „Code Smells“ JUnit 72

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser •

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte Tests mit JUnit Konkrete Refactorings • Beispiel • Toolunterstützung 73

Katalog • Der Katalog ist Hilfestellung. § Ziel ist „besserer Geruch“: Eigenes Urteil! §

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 74

Change Inconsistent Layout • Quelltext ist inkonsistent formatiert, insbesondere eingerückt. § Layout an Quelltextrichtlinien

Change Inconsistent Layout • Quelltext ist inkonsistent formatiert, insbesondere eingerückt. § Layout an Quelltextrichtlinien anpassen § Möglichst toolgestützt § NICHT den eigenen Geschmack aufzwingen! 75

Replace Magic Number with Symbolic Constant • In einer Methode steht eine Zahl (außer

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 76

Replace Temp with Query • Eine temporäre Variable enthält ein Zwischenergebnis. § Den entsprechenden

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 77

Rename Method (1) • Der Name einer Methode spiegelt nicht (mehr) ihren Inhalt wieder.

Rename Method (1) • Der Name einer Methode spiegelt nicht (mehr) ihren Inhalt wieder. § Den Namen ändern § Analog Parameter hinzufügen oder entfernen 78

Rename Method (2) • Konkrete Schritte: § Basis- und Unterklassen prüfen § Methode mit

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 79

Replace Constructor with Factory Method • Konstruktor ist nicht flexibel genug. § Besser statische

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 80

Extract Method (1) • Mehrere Statements einer Methode gehören logisch zusammen. § Auslagern in

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 81

Extract Method (2) • Konkrete Schritte: § § § Neue Methode anlegen und gut

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 82

Inline Method (1) • Der Code einer Methode ist genauso klar wie ihr Name.

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“ 83

Inline Method (2) • Konkrete Schritte: § § § Prüfen, dass die Methode nicht

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 84

Remove Assignments to Parameters • Eine Methode enthält eine Zuweisung an einen Parameter. §

Remove Assignments to Parameters • Eine Methode enthält eine Zuweisung an einen Parameter. § Stattdessen temporäre Variable verwenden § Erhöht Übersichtlichkeit 85

Replace Method with Method Object (1) • Eine Methode verwendet lokale Variablen so, dass

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 86

Replace Method with Method Object (2) • Konkrete Schritte: § Neue Klasse anlegen §

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 87

Substitute Algorithm • Ein Algorithmus ist komplizierter als nötig. § Durch einen einfacheren Algorithmus

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 88

Move Method (1) • Eine Methode benutzt mehr Features oder wird von mehr Features

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 89

Move Method (2) • Konkrete Schritte: § Benutzte Felder und Methoden ggf. mitverschieben §

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 90

Move Field (1) • Ein Feld wird in einer anderen Klasse mehr benutzt §

Move Field (1) • Ein Feld wird in einer anderen Klasse mehr benutzt § Dorthin verschieben § Bessere Kohäsion und schlankere Schnittstelle § Eventuell Methoden mitverschieben 91

Move Field (2) • Konkrete Schritte: § In Zielklasse ein Feld mit get- und

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 92

Extract Class (1) • Eine Klasse macht die Arbeit von zweien. § Neue Klasse

Extract Class (1) • Eine Klasse macht die Arbeit von zweien. § Neue Klasse anlegen und Felder und Methoden hineinverschieben § Übersichtlichkeit durch klare Aufgabenteilung 93

Extract Class (2) • Konkrete Schritte: § Aufteilung planen § Neue Klasse anlegen, Referenz

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) 94

Hide Delegate • Ein Client holt sich von einem Objekt ein anderes Objekt und

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 95

Remove Middle Man • Eine Klasse delegiert eine Reihe von Aufrufen einfach an ein

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 96

Replace Data Value with Object • Ein primitives Attribut hat eigentlich dazugehörige Funktionalität. §

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 97

Replace Type Code with Subclass (1) • Eine Klasse hat einen Typcode, der über

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 98

Replace Type Code with Subclass (2) • Konkrete Schritte: § Auf Typcode nur durch

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 get-Methode überschreibt § Typcode-Attribut aus der Basisklasse entfernen 99

Replace Type Code with State/Strategy (1) • Ein Typ-Code entscheidet über Verhalten, aber es

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 100

Replace Type Code with State/Strategy (2) • Konkrete Schritte: § Den Typ-Code hinter get-Methode

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 101

Replace Conditional with Polymorphism (1) • Verhalten wird über einen Typ-Code ausgewählt. § Für

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 102

Replace Conditional with Polymorphism (2) • Konkrete Schritte: § Replace Type Code with. .

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 103

Replace Subclass with Fields (1) • Unterklassen unterscheiden sich nur in Methoden, die konstante

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 104

Replace Subclass with Fields (2) • Konkrete Schritte: § Statische create-Methode einführen § final

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 105

Consolidate Duplicate Conditional Fragments • Ein gemeinsames Stück Code ist in allen Zweigen einer

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 106

Remove Control Flag • Ein Flag kontrolliert den Ablauf einer Schleife. § Besser break,

Remove Control Flag • Ein Flag kontrolliert den Ablauf einer Schleife. § Besser break, continue und return verwenden § Kürzer und übersichtlicher 107

Replace Nested Conditional with Guard Clause • Eine Methode hat verschachtelte if. Statements, um

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 108

Separate Query from Modifier (1) • Eine Methode führt eine Abfrage durch und ändert

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 109

Separate Query from Modifier (2) • Konkrete Schritte: § Die reine Abfrage als eigene

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 110

Parameterize Method • Mehrere Methoden tun das Gleiche mit unterschiedlichen fest verdrahteten Werten. §

Parameterize Method • Mehrere Methoden tun das Gleiche mit unterschiedlichen fest verdrahteten Werten. § Zusammenführen in eine einzige Methode mit Parameter § Vermeidet Code-Duplizierung 111

Replace Parameter with Explicit Methods • Ein Methode macht völlig verschiedene Dinge abhängig vom

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 112

Preserve Whole Object • Eine Methode bekommt mehrere Attribute des gleichen Objekts als Parameter.

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 113

Replace Parameter with Method • Eine Methode bekommt einen Parameter, den sie auch selbst

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 114

Introduce Parameter Object (1) • Mehrere Parameter bilden eine natürliche Einheit. § Zu einem

Introduce Parameter Object (1) • Mehrere Parameter bilden eine natürliche Einheit. § Zu einem neuen Typ zusammenfassen § Wertsemantik § Typsicher, besser lesbar 115

Introduce Parameter Object (2) • Konkrete Schritte: § Neue Klasse leer anlegen § Die

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 116

Remove Setting Method • Ein Feld wird nur bei der Erzeugung gesetzt und anschließend

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 117

Encapsulate Downcast • Eine Methode liefert eine Referenz, die erst nach Downcast verwendbar ist

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 118

Pull Up Method • Unterklassen haben Methoden mit dem gleichen Ergebnis. § Methoden in

Pull Up Method • Unterklassen haben Methoden mit dem gleichen Ergebnis. § Methoden in die Basisklasse verschieben § Code-Duplizierung vermeiden § Eventuell unterschiedliche Algorithmen 119

Push Down Method • Eine Methode der Basisklasse wird nur von einer Unterklasse verwendet.

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 120

Extract Superclass • Mehrere Klassen haben teilweise die gleichen Methoden. § Gemeinsamkeiten in eine

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 121

Form Template Method (1) • Unterklassen haben Methoden, die ähnliche Schritte in der gleichen

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 122

Form Template Method (2) • Konkrete Schritte: § § Methoden zerlegen Methodensignaturen vereinheitlichen Jeweils

Form Template Method (2) • Konkrete Schritte: § § Methoden zerlegen Methodensignaturen vereinheitlichen Jeweils compilieren und testen Ursprüngliche Methode in Basisklasse ziehen 123

Replace Inheritance with Delegation • Eine Unterklasse will nur einen Teil der Schnittstelle der

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 124

Der Code ist das Design • Alle hier präsentierten Refactorings wollen das Design im

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! 125

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser •

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte Tests mit JUnit • Konkrete Refactorings Beispiel • Toolunterstützung 126

Beispiel • Ein praktisches Beispiel der Refactorings § Der Quelltext ist im Internet verfügbar:

Beispiel • Ein praktisches Beispiel der Refactorings § Der Quelltext ist im Internet verfügbar: www. haase-consulting. com/download/oop 2002 127

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser •

Übersicht • Einführung • Das Umfeld für Refactoring • „Code Smells“ als Wegweiser • Automatisierte Tests mit JUnit • Konkrete Refactorings • Beispiel Toolunterstützung 128

Toolunterstütztes Refactoring • Die Durchführung des Refactoring lässt sich weitgehend automatisieren. § Schutz vor

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 129

Kriterien für Toolauswahl • Folgende Punkte stellen Kriterien für die Auswahl eines Refactoring-Tools dar:

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 130

Refactoring-Tools • Hier eine Auswahl von aktuellen Refactoring-Tools für Java: § § Idea (www.

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). . . 131

Toolunterstützung praktisch • Demonstration für toolgestütztes Refactoring § So einfach kann Refactoring in der

Toolunterstützung praktisch • Demonstration für toolgestütztes Refactoring § So einfach kann Refactoring in der Praxis sein. 132

Literatur • Folgende Quellen sind gute Startpunkte für eine Vertiefung: § § „Refactoring“, Martin

Literatur • Folgende Quellen sind gute Startpunkte für eine Vertiefung: § § „Refactoring“, Martin Fowler www. refactoring. org www. junit. org „Extreme Programming Explained“, Kent Beck 133

Zusammenfassung • • • Refactoring Das Umfeld von Refactoring „Code Smells“ JUnit Refactoring-Katalog Toolunterstützung

Zusammenfassung • • • Refactoring Das Umfeld von Refactoring „Code Smells“ JUnit Refactoring-Katalog Toolunterstützung 134