Refactoring Uschi Beck uschibeck@web.de
Gliederung Was ist Refactoring Definition, Einordnung in das Seminar Motivation Testen Code-Smells Katalog von Refactorings Aufbau, Beispiele Design Patterns als Ziel Refactoringwerkzeuge Eclipse Probleme, Grenzen Fazit 2
Definition entstand in Smalltalk-Kreisen Kent Beck, Ward Cunningham Systematische Änderung der internen Struktur einer Software, ohne ihr beobachtbares Verhalten zu ändern Was macht das Thema in einem Entwurfsseminar? Refactoring nur bei schlechtem Entwurf? Nein! Erst bei der Implementierung werden Schwachstellen erkannt neue Sichtweise auf den Entwurf Dynamisch, ständig weiterentwickeln ( Xtreme-Programming ) 3
Einordnung Refactoring 4
Warum Refactoring? neue Anforderungen schwer einzubauen redundanter Code Designverbesserung Qualitätsziel leichter lesbar und damit verständlicher für einen selbst, für andere Entwickler Fehler leichter zu finden Wartbarkeit wird erhöht erspart langfristig gesehen eine Menge Arbeit Refactoring erhöht die Programmiergeschwindigkeit 5
Aktivitäten ten in der Softwarewartung Änderungen testen 25% Verstehen des Source Codes 50% Änderungen Planen 10% Änderungen durchführen 10% Änderungen dokumentieren 5% 6
Metapher der zwei HüteH Refactoring als ständiger Teil des Entwicklungsprozesses Mini-Programmierzyklus Metapher der zwei Hüte ( Kent Beck ) Funktionalität hinzufügen Refactoring Man kann immer nur einen Hut tragen! 7
Die Bedeutung von Tests wichtige Voraussetzung für das Refactoring vor allem, wenn es ohne Werkzeugunterstützung durchgeführt wird stellen sicher, dass die Funktionalität nicht verändert wird damit man Tests auch anwendet sollten sie vollständig automatisiert ablaufen ihre Ergebnisse selbst überprüfen z.b. JUnit nach jedem Refactoring Tests einmal ausführen 8
Code-Smells Problem: woran erkennt man, das die Struktur des Codes verbessert werden kann? bereits kennen gelernt: Antipatterns Code-Smells ifitsmells, change it Strukturen im Code, die es nahe legen zu refaktorisieren nur Indizien, keine präzisen Kriterien!!! über 20 verschieden 9
Beispiele für f Code-Smells Duplizierter Duplizierter Code Code Es geht meistens ohne erschwert Änderungen Lange Lange Methoden Methoden schwer verständlich Kommentare, um Arbeitsweise zu erklären Große Große Klassen Klassen sehr vielen Instanzvariablen Brutstätte für duplizierten Code Neid Neid eine Klasse benutzt häufig Elemente einer anderen Klasse ACHTUNG: bei manchen Designpatterns ist das gewollt ( z.b. Visitor ) 10
Katalog von Refactorings über 70 Refactorings in Gruppen gegliedert Name Kurze Beschreibung in welcher Situation dieses Refactoring benötigt wird und was es leistet Motivation Vorteile wann sollte man besser darauf verzichten Vorgehensweise präzise, schrittweise Erklärung, wie das Refactoring von Hand auszuführen ist Beispiele Javacode, mit Erklärungen 11
Methoden zusammenstellen modifizieren Methoden erleichtern die Verständlichkeit Typische Code-Smells: lange Methoden duplizierter Code Methode extrahieren Beschreibung: Codefragment, das zusammengefasst werden kann erstelle Methode, deren Name die Aufgabe erklärt Motivation: Widerverwendbarkeit überschreiben ist einfacher verbessert die Verständlichkeit 12
Beispiel: Methode extrahieren public String rechnung() {...... double gesamtbetrag = 0; sehr lang Videothek Methode, die Rechnung schreibt While-Schleife berechnet Preis für jede Ausleihe } while (... ) { Ausleihe Preis hängt eineausleihe vom Filmtyp = ab ; double ausleihgebühr = 0; switch (eineausleihe.getmovie().getpricecode()){ case case Movie.REGULAR: ausleihgebühr = ; = ; case case Movie.CHILDRENS: ausleihgebühr = ; = ; } } gesamtbetrag += ausleihgebühr; } 13
Beispiel: Methode extrahieren double gesamtbetrag = 0; switch ( ){ case Movie.REGULAR: ausleihgebühr = ; case Movie.CHILDRENS: ausleihgebühr = ; } gesamtbetrag += ausleihgebühr; } 1. Neue Methode erstellen 2. Zu extrahierenden Code in die neue Methode kopieren 3. Nach Variablen suchen, nur gelesene als Parameter übergeben 4. ausleihgebühr muss zurückgegeben werden private double void void gebührfüreineausleihe () { () Ausleihe {( eineausleihe) ) { { double ausleihgebühr = 0; } switch (eineausleihe.getmovie().getpricecode()){{ switch (eineausleihe.getmovie().getpricecode()){ case case Movie.REGULAR: Movie.REGULAR: ausleihgebühr = ; case Movie.CHILDRENS: ausleihgebühr = ; } } return ausleihgebühr; } 14
Beispiel: Methode extrahieren public String rechnung() {... double gesamtbetrag = 0; while (... ) { Ausleihe eineausleihe = ; double ausleihgebühr = gebührfüreineausleihe( eineausleihe ); gesamtbetrag += ausleihgebühr; } private double gebührfüreineausleihe ( Ausleihe eineausleihe) { double ausleihgebühr = 0; switch (eineausleihe.getmovie().getpricecode()) { case Movie.REGULAR: ausleihgebühr = ; } } case Movie.CHILDRENS: ausleihgebühr = ; } return ausleihgebühr; 5. Extrahierten Code durch Methodenaufruf ersetzen 15
Eigenschaften zwischen Objekten verschieben behandeln die Delegation von Aufgaben zwischen Klassen Verteilung von Verantwortlichkeit verschieben Methoden und Felder Typische Code-Smells: Neid duplizierter Code große Klassen Klasse extrahieren Beschreibung: Klasse, die die Arbeit macht, die von zwei Klassen zu erledigen wäre erstelle neue Klasse und verschiebe relevante Felder und Methoden Motivation: glasklare Abstraktion in der Praxis wachsen Klassen ständig Beachte: Assoziationen Veröffentlichung 16
Daten organisieren wandeln Datentypen um modifizieren den Zugriff auf Daten Möglichkeit nutzen, neue Typen zu definieren Typische Code-Smells: Neigung zu elementaren Datentypen große Klassen Wert durch Objekt ersetzen Beschreibung: Datenelement, das zusätzliches Verhalten benötigt Datenelement in Klasse umwandeln Motivation: einfache Datenelemente werden komplexer 17
Wert durch Objekte ersetzen Kunde kundennummer: int Kundennummer k_nr: int Kunde 18
Methodenaufrufe vereinfachen vereinfachen Schnittstellen Schlüsselqualifikation für gute Software z.b. Namensänderung: einfach, aber wirkungsvoll Typische Code-Smells: Kommentare Konstruktor durch Factory-Methode ersetzen Beschreibung: mehr als nur eine einfache Konstruktion ausführen Konstruktor durch eine Fabrikmethode ersetzen Motivation: eine Methode um verschiedene Typen von Objekten zu erzeugen 19
Weitere Refactorings bedingte Ausdrücke vereinfachen ( if-then-else Konstrukte, switch Anweisungen ) Umgang mit der Generalisierung ( verschieben von Methoden in der Vererbungshierarchie, Interface extrahieren ) 20
Refactoring to Patterns Designpatterns erhöhen die Flexibilität verbessern die Wartbarkeit können Ziel von Refactorings sein Manchmal geht etwas aber auch ohne Designpatterns einfacher Refactoring To Patterns ( Joshua Kerievsky ) Beschreibt wie man durch Refactoring Design Patterns einbauen/entfernen kann Aufbau der einzelnen Refactorings wie bei Martin Fowler 21
Refactoring-Werkzeuge verringern Zeitaufwand Sichern den Erhalt der Funktionalität Programmieren und Refactoring gehen ineinander über Entwurfsfehler werden billiger Anforderungen an Refactoring-Werkzeuge ganze Programm nach bestimmten Elementen durchsuchen Ableitungsbäume Genauigkeit Geschwindigkeit Rückgängig machen 22
Eclipse: Refactoringmenü umbenennen extrahieren von Variablen, Methoden Verschieben Interface extrahieren Factory-Methode einfügen Undo-Funktion vorhanden 23
Eclipse: Methode extrahieren Dialogfenster für Methode extrahieren 24
Eclipse: Methode extrahieren Voransicht für Methode extrahieren 25
Probleme und Grenzen Datenbanken veröffentlichte Schnittstellen manchmal besser: Code neu schreiben kurz vorm Fertigstellungstermin Performance Verlust? NEIN! 10 20% des Codes für 80% Performance verantwortlich zugänglicher für Performance-Tuning Dokumentation muss aktualisiert werden 26
Häufig geäußerte erte Bedenken wir haben keine Zeit dafür erleichtert die weitere Implementierungsarbeit ( spart also Zeit ) kann das Programm kaputt machen gute Tests es werden immer nur kleine Teile geändert, d.h. die Änderungen können leicht rückgängig gemacht werden Entwicklungsumgebungen wie Eclipse sichern die Erhaltung Vorteile erst langfristig erkennbar, vielleicht haben wir da gar nichts mehr mit dem Projekt zu tun Und wenn doch?!! das Programm läuft doch Qualitätsaspekt Flexibilität in Bezug auf Änderungen Wartbarkeit 27
Fazit einzelne Refactorings erscheinen häufig banal man muss den Gesamtnutzen in einem großen Projekt sehen Ziele vor Augen führen nicht auf Teufel komm raus alles refaktorisieren wollen beim Refactoring von Hand in kleinen Schritten vorgehen, Testen nicht vergessen sich mit dem Refactoringwerkzeug seiner Entwicklungsumgebung vertraut machen Refactoring als eine ständige Weiterentwicklung des Entwurfs betrachten 28