Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

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

Ähnliche Präsentationen


Präsentation zum Thema: "Refactoring Java Code Arno.Haase@Haase-Consulting.com Arno.Haase@acm.org www.Haase-Consulting.com."—  Präsentation transkript:

1 Refactoring Java Code Arno.Haase@Haase-Consulting.com

2 Übersicht  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

4 Refactoring: Definition
„Refactoring ist die Verbesserung der Qualität von 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

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

7 Demonstration Ein Quelltext sagt mehr als tausend Folien...
Der Quelltext ist im Internet verfügbar:

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

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

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

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

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.

13 Übersicht 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...

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)

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

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

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.

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

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

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.

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“

23 Versionsverwaltung 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

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

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

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

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

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.

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

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

32 Grenzen des Refactoring
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!

34 Übersicht 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?

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

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

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

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

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

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

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

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

44 Monster-Klasse 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 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 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

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

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

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

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

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

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

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

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

56 Übersicht 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.

58 JUnit JUnit ist ein Framework zur Unterstützung von automatisierten Modultests. Tests sind Java-Klassen Test-Schreiben ist kein großer Overhead

59 Beispiel Ein dummes aber einfaches Beispiel...
Der Quelltext ist im Internet verfügbar:

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

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“ TestCase Briefmarke BriefmarkeTest

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

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

64 TestSuite Mehrere Tests können als TestSuite zusammengefasst werden.
Klasse junit.framework.TestSuite Eine TestSuite kann TestCases und TestSuites enthalten 1..* Test TestCase TestSuite

65 Beispiel (2) Eine zweite Klasse mit Tests kommt dazu.
Der Quelltext ist im Internet verfügbar:

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

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

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

69 Beispiel (3) Das Beispiel wird noch einmal erweitert.
Der Quelltext ist im Internet verfügbar:

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

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ß

72 Zusammenfassung 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

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

75 Change Inconsistent Layout
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

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

78 Rename Method (1) 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

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

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

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

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“

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

85 Remove Assignments to Parameters
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

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

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

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

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

91 Move Field (1) 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

93 Extract Class (1) 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)

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

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

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

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

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

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

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

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

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

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

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

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

107 Remove Control Flag 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

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

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

111 Parameterize Method 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

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

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

115 Introduce Parameter Object (1)
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

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

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

119 Pull Up Method 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

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

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

123 Form Template Method (2)
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

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!

126 Übersicht 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:

128 Übersicht 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

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

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

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

133 Literatur Folgende Quellen sind gute Startpunkte für eine Vertiefung:
„Refactoring“, Martin Fowler „Extreme Programming Explained“, Kent Beck

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


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

Ähnliche Präsentationen


Google-Anzeigen