Refactoring
Transcription
Refactoring
Seminar: CASE-Tools WS 06/07 31.01.2007 Refactoring Thomas Löffler Überblick 1. Einführung: 2. Vorgehen Wo wird refactorisiert? Beispiele 3. Refactoringtools Refactoring – Was ist das? Warum Refactoring? Ziele Eclipse RefactorIT 4. Kritik am Refactoring 5. Übung in Eclipse 2 Refactoring - Was ist das? Definition: „ A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behaviour.“ (Martin Fowler) Also: Umstrukturieren einer Software, ohne ihr beobachtbares Verhalten zu ändern Verbessert das Design der Software 1. Einführung 3 Warum Refactoring? Verbesserung und Pflege des Designs Software wird verständlicher Designfehler werden gefunden Unbekannte Codefehler werden gefunden Hilfe, um schneller zu programmieren 1. Einführung 4 Ziele Verbesserung der Lesbarkeit Übersichtlichkeit Verständlichkeit Erweiterbarkeit Vermeidung von Redundanz Testbarkeit 1. Einführung 5 Wo wird refactorisiert? Bad smells in Code „If code stinks, change it.“ Dort wo der Code den größten „Gestank“ ausbreitet Eher intuitiv als wissenschaftlich Aber: Es gibt einen ganzen Katalog von „code smells bad“ 2. Vorgehen 6 Beispiele für Code smells bad (1) Redundanter Code Gleiche Codestruktur an mehr als einer Stelle im Code Besser: Methode extrahieren (wenn exakt derselbe Ausdruck vorkommt) Abstrakte Methode in einer Oberklasse (wenn nur ähnlich) 2. Vorgehen 7 Beispiele für Code smells bad (2) Lange Methode erledigen in der Regel viele verschiedene Aufgaben Gesamte Funktionalität schwer überschaubar Besser: Funktion in mehrere kleinere Funktionen unterteilen Æ Methode wird leichter verständlich und Wiederverwendbarkeit steigt. 2. Vorgehen 8 Beispiele für Code smells bad (3) Große Klasse Klasse mit vielen Funktionen und Instanzvariablen Sind in der Regel sehr unübersichtlich Neigen dazu, redundanten Code zu haben Besser: Klasse in mehrer Klassen sinnvoll aufteilen Instanzvariablen in extra Datenklassen kapseln 2. Vorgehen 9 Beispiele für Code smells bad (4) Schrotschuss Operation (Shotgun Surgery): Bei Änderungen einer Klasse müssen viele kleine Änderungen in anderen Klassen gemacht werden Bei Änderungen müssen alle Programmteile gefunden werden, die eine Änderung benötigen. Besser: Programmteile in einer Klasse bündeln 2. Vorgehen 10 Beispiele für Code smells bad (5) Neid um Leistungsmerkmale (Feature Envy): Eine Methode einer Klasse interessiert sich mehr für Daten einer anderen Klasse Besser: Verschiebe die Methode (oder einen Teil davon) in die andere Klasse. 2. Vorgehen 11 Vorgehen „It is essential for refactoring that you have good tests. [...] Before you start refactoring, check that you have a solid suite of tests. These tests should be self checking.” (Martin Fowler) Test sollte vor dem Refactoring geschrieben sein Iteratives Vorgehen: Kleiner Refactoring-Schritt Testen 2. Vorgehen 12 Beispiel: Entwurfsmuster vor Refactoring 2. Vorgehen 13 Beispiel: Entwurfsmuster nach Refactoring 2. Vorgehen 14 Refactoringtools Es gibt ca. 70 Refactoring - Standardprozeduren. Rename, Move, Pull up, Push down ... Einige davon können leicht von Tools bearbeitet werden. Tools gibt es sehr viele, z.B. Eclipse (Java) RefactorIT (Java) IntelliJ (Java) SlickEdit (C++) Smalltalk Refactoring Browser (Smalltalk) Bicycle Repair Man (Python) HaRe (Haskell) Modell Maker (Delphi) 3. Refactoringtools 15 Refactoring in Eclipse Es können drei Blöcke zusammengefasst werden: Äußerliche Struktur Klassenstruktur Struktur in einer Klasse Eigene Undo/Redo Funktion für Refactorings. Preview-Funktion 3. Refactoringtools Bevor Refactoring auf den Code angewandt wird, können alle Änderungen betrachtet werden Auch Probleme werden vorher berichtet 16 Refactoring in Eclipse: Äußerliche Struktur(1) Eclipse bietet hier folgende Hilfen an: Rename: Ändert alle Variablen oder Methodennamen im Projekt. Move: verschiebt Pakete, Klassen/Interfaces, Felder oder Methoden in eine andere Klasse. 3. Refactoringtools 17 Refactoring in Eclipse: Äußerliche Struktur(2) Change Method Signature: Änderungen an der Signatur der Methode. z.B. Parameter hinzufügen oder entfernen. Convert anonymous class to nested: konvertiert eine anonyme in eine innere Klasse. public static void main(String[] args ) { System.out.println( new Object() { public String toString(){ return "Hello World!"; } }.toString() ); } Æ private static final class HelloWorld { public String toString(){ return "Hello World!"; } } public static void main(String[] args ) { System.out.println(new HelloWorld().toString()); } 3. Refactoringtools 18 Refactoring in Eclipse: Äußerliche Struktur(3) Convert Nested Type to Top Level (Eclipse 2) / Move Member Type to New File (Eclipse 3): erzeugt aus einer inneren Klasse eine eigene TopLevel-Klasse. class MyClass { class MyClass { public class Hello { private static final class HelloWorld { public String toString(){ return "Hello World!"; } } Æ public static void main(String[] args ) { System.out.println( new HelloWorld().toString() ); } } }; final class HelloWorld { public String toString(){ return "Hello World!"; } } public class Hello { public static void main(String[] args ) { System.out.println( new HelloWorld().toString() ); } } }; 3. Refactoringtools 19 Refactoring in Eclipse : Klassenstruktur(1) Pull Up: Verschiebt Methoden oder Variablen einer Klasse ihre Superklassen Push Down: Gegenteil von Pull Up. Verschiebt Methoden oder Variablen einer Klasse bzw. in alle ihre direkten Unterklassen. 3. Refactoringtools 20 Refactoring in Eclipse : Klassenstruktur(2) Extract Interface: erzeugt zu einer Klasse ein Interface. Die Methoden, die im Interface deklariert werden sollen, können vom Benutzer ausgewählt werden. 3. Refactoringtools 21 Refactoring in Eclipse : Klassenstruktur(3) Generalize Type (Eclipse 3): Ändert den Typ eines Objekts bei der Deklaration einer Variablen durch den Typ einer seiner Superklassen. Engeneer myEmployee = new Engeneer(); Æ Employee myEmployee = new Engeneer(); Use Supertype where possible: Ersetzt, falls möglich, Instanzen einer Klasse durch Instanzen einer ihrer Superklassen oder eines ihrer Interfaces. 3. Refactoringtools 22 Refactoring in Eclipse : Struktur in einer Klasse(1) Inline Auf lokale Variablen angewandt: Jedes Vorkommen einer ausgewählten lokalen Variablen wird durch ihren initialen Wert ersetzt. int x; int refactore = 12 + x; int y = 345 + refactore; Æ int x; int y = 345 + (12 + x); Auf Methoden angewandt: Ersetzt jeden Methodenaufruf durch ihren Code. Die Methode wird gelöscht. public int aMethod(int x) { return x + 12; } Æ public void anotherMethod() { int aMethod = 10 + 12; } public void anotherMethod() { aMethod(10); } 3. Refactoringtools 23 Refactoring in Eclipse : Struktur in einer Klasse(2) Extract Method: Setzt ein Codefragment in eine neue Methode. void print() { System.out.println(“Name: “ + name); System.out.println(“Vorname“ + vorname); printData(); } Æ void printName() { System.out.println(“Name: “ + name); System.out.println(“Vorname“ + vorname); } void print() ( printName(); printData(); } Extract Local Variable: Ersetzt einen Ausdruck durch eine lokale Variable. int x = 26 + 84 + 985; int y = 26 + 85 + 985; Æ int z = 26 + 84 + 985; int x = z; int y = z; 3. Refactoringtools 24 Refactoring in Eclipse : Struktur in einer Klasse(3) Extract Constant: Ersetzt einen Ausdruck durch eine statische Variable (Schlüsselwörter: static und final) void aMethod { int x = 26 + 84 + 985; int y = 26 + 85 + 985; } private static final int z = 26 + 84 + 985; Æ void aMethod { int x = z; int y = z; } Introduce Paramenter: erzeugt aus einem Ausdruck einen neue Methodenparameter. public void aMethod() { int z = 12 + 48 + 59; } public void anotherMethod() { aMethod(); } Æ public void aMethod(int x) { int z = x; } public void anotherMethod() { aMethod(12 + 48 + 59); } 3. Refactroingtools 25 Refactoring in Eclipse : Struktur in einer Klasse(4) Introduce Factory: Ersetzt alle Aufrufe eines Konstruktors mit einer entsprechenden statischen Factory - Methode. class MyClass { class MyClass { public MyClass() { // ... } private MyClass() { // ... } Æ public static MyClass createMyClass() { return new MyClass(); } public static void main(String[] args) { MyClass myClass = new MyClass(); // ... } public static void main(String[] args) { MyClass myClass = createMyClass(); // ... } }; }; 3. Refactoringtools 26 Refactoring in Eclipse : Struktur in einer Klasse(5) Convert Local Variable to Field: Ersetzt die lokale Variable durch eine statische Variable auf Klassenebene. void myMethod() { int x =24; // ... } private static int x; Æ void myMethod() { x = 24; // ... } Encapsulate Fields: Erzeugt Setter- und/oder Getter - Methoden für ein Attribut und ersetzt alle Referenzen auf dieses Feld durch die entsprechenden Methodenaufrufe. Die Sichtbarkeit des Attributes wird private. 3. Refactoringtools 27 RefactoringIT Als alleinstehendes Programm oder als Plugin Verschiedene Lizenzarten (je noch Projektgröße) Eclipse NetBeans Oracle JDeveloper Borland JBuilder Borland JBuilder Frei für OpenSource-Community Zusätzliche Funktionen: Hilfe zur Codeanalyse Metriken dienen zur „Bewertung“ des Codes. 3. Refactoringtools 28 RefactorIT: Hilfe zur Codeanalyse(1) Where Used Not Used Typ-bezogene Suche: Findet alle Felder, Parameter oder Returnwerte vom angegebenen Typ. Subtypes Findet und listet alle nicht verwendeten Klassen, Interfaces, Methoden, Konstruktoren und Felder in einer Klasse, eimem Package oder einem ganzen Projekt. Structure Search Findet und listet alle Referenzen einer ausgewählten Klasse, Interface, Methode, Konstruktor, Feld, lokale Variable. Listet alle Subklassen einer angegebenen Klasse bzw. alle Implementationsklassen eines angegebenen Interfaces. Type Explorer Zeigt den Vererbungsbaum für eine ausgewählte Klasse in einem Explorer View. 3. Refactoringtools 29 RefactorIT: Hilfe zur Codeanalyse(2) Draw Dependencies Zeigt alle Typen, Methoden, Konstruktoren von denen die ausgewählte Einheit (Package, Klasse, Methode) abhängt. Die entsprechenden 3. Refactoringtools 30 RefactorIT: Metriken(1) Helfen bei der Analyse von unbekanntem Source-Code Masszahlen wie Anzahl der Codezeilen oder Anzahl der Klassen Hinweise auf die Komplexität des Codes und seine innere Struktur Helfen bei der Abschätzung von Wiederverwendbarkeit von Aufwand von Funktiontests sowie Wartungsarbeiten. 3. Refactoringtools 31 RefactorIT: Metriken(2) Einige Metriken, die von RefactoringIT berechnet werden: Einfache Metriken: OO-Metriken: Gesamtzahl der Codezeilen (LOC) Gesamtzahl der echten Codezeilen ohne Kommentare (NCLOC) Gesamtzahl der Kommentarzeilen im Code (CLOC) Kommentardichte (DC = CLOC / LOC) Anzahl der Parameter in der Signatur der jeweiligen Methode (NP) Verhältnis von abstrakten Klassen oder Interfaces zur Gesamtzahl der Klassen (A) Position der Klasse in der Vererbungshirarchie gemessen als Abstand von der Wurzel (DIT) Anzahl der Klassendefinitionen in der Klasse (NOT) Qualitätsmetriken: „Cyclomatic Complexity’“: Komplexität auf Basis aller möglichen verschiedenen Ausführungspfade, die in einer Methode durchlaufen werden können ( v(C) ) Komplexität der Klasse: Summe der ‘Cyclomatic Complexities’ V(G) aller Methoden der jeweiligen Klasse (WMC) Anzahl der Methoden und Konstruktoren, die innerhalb der jeweiligen Klasse aufgerufen werden(RFC). 3. Refactoringtools 32 RefactorIT: Audit(1) Meldet verdächtigen und nutzlosen Code. Über 200 sog. „Audits“ Ergebnissen haben unterschiedliche Prioritäten Einige Meldungen können automatisch korrigiert werden 3. Refactoringtools 33 Kritik am Refactoring Kein Allheilmittel Kann teilweise nur schwer eingesetzt werden Im Zusammenhang mit Datenbanken, da unter Umständen Änderungen am Datenmodell vorgenommen werden müssen. Bei Echtzeitsystemen, da Refactoring unter Umständen zu Performanceverlust führt Auf Refactoring sollte verzichtet werden, wenn schlecht entworfene Software kann nicht immer durch Refactoring verbessert werden. Die Software ganz, oder in Teilen nicht funktioniert Zwang zur kurzfristigen Einhaltung einer Deadline Auswahl von vielen verschiedenen Refactorisierungen Es ist viel Erfahrung notwendig, um richtig zu refactorisieren 4. Kritik am Refactoring 34 Habt ihr noch Fragen? 35 Vielen Dank für eure Aufmerksamkeit. 36