What Is Refactoring? Definition: The process of changing software in a way that the external behavior is not altered but the internal structure is improved. Or, an instance of such a change. (E.g. I carried out a refactoring. ) Cleaning up code. Improving design. But after the code works. Fights against software entropy Refactoring - 1
Why Refactor? Continuous improvement of design Tidying up. Avoids decay. Needed if make it work is first priority Best design choices may not evident at first Makes software easier to understand Refactoring done to clean up hacks Done after reflection. May be done to remove ambiguity, misleading code, a hack, etc. If you can change it successfully, you understand it Refactoring - 2
Why Refactor? (2) Helps you find bugs A change to improve structure may reveal a flaw in old implementation Helps you developing working code more quickly Counter-intuitive! Short cycles of add-functionality then improve-design. (Kent Beck s two hats idea). Refactoring - 3
But Hold On Possible objections. Touching the design is asking for trouble! Once it s working, why bother? After I think it s working, don t I have to reverify the design changes again? What we need to make refactoring successful is Unit tests Refactoring - 4
Unit Testing in TDD Motto: Clean code that works. (Ron Jeffries) Unit testing has broader goals that just insuring quality Improve developers lives (coping, confidence) Support design flexibility and change Allow iterative development with working code early Refactoring - 5
Unit Testing Benefits Developers can work in a predictable way of developing code Programmers write their own unit tests Get rapid response for testing small changes Build many highly-cohesive looselycoupled modules to make unit testing easier Refactoring - 6
Red/Green/Refactor The TDD mantra of how to code: Red: write a little test that doesn t work, perhaps even doesn t compile Green: Write code to make the test work quickly (perhaps not the best code) Refactor: Eliminate duplication and other problems that you did to just make the test work Refactoring - 7
When Should Refactor? Remember: afterwards! (After what?) The Rule of Three First, just do it. Second time, do it badly but tolerate it. Third time, do it well: refactor. Some guidelines: When you need to add a function. Existing design makes this hard. Improve it. When you need to fix a bug. As part of a code review. Refactoring - 8
Refactoring and Design Smells Fowler, design smells, and catalog of refactorings The book http://www.refactoring.com/ List of smells on the web: http://wiki.java.net/bin/view/people/smellsto Refactorings Refactoring - 9
Tool Support for Refactoring Refactorings: standard re-structurings to solve common problems Can do them by hand Put might be tricky IDEs and separate tools support this IntelliJ, ReSharper, JRefactory, C# Refactory Eclipse, JBuilder, next release of Visual Studio Refactoring - 10
Why tools? Ponder these: In Java, you decide to change a class s name. What needs to changed? In Java, you want to change the name of a method. What needs to be changed? Refactoring - 11
Java Refactorings in Eclipse Renaming resources classes, methods, fields moving to another package inner and anonymous classes Class hierarchy modifications includes make an interface from a class Code level mods make a code segment a function Refactoring - 12
Refactoring JDT has actions for refactoring Java code Refactoring - 13
Refactoring Refactoring actions rewrite source code Within a single Java source file Across multiple interrelated Java source files Refactoring actions preserve program semantics Does not alter what program does Just affects the way it does it Refactoring - 14
Refactoring Full preview of all ensuing code changes Programmer can veto individual changes List of changes before vs. after Refactoring - 15
Refactoring JDT has actions for refactoring Java code Refactoring - 16
Refactoring Growing catalog of refactoring actions Organize imports Rename {field, method, class, package} Move {field, method, class} Extract method Extract local variable Inline local variable Reorder method parameters Refactoring - 17
Cechy języka utrudniające refaktoryzację Mechanizm refleksji określenie klasy danego obiektu, uzyskanie informacji nt. modyfikatorów klasy, pól, metod, konstruktorów i nadklasy, odkrycie, jakie stałe i deklaracje metod należą do danego interfejsu, stworzenie instancji klasy, której nazwa nie jest znana do chwili uruchomienia programu, pobranie i ustawienie wartości pola obiektu, nawet jeśli nazwa pola nie jest znana aż do uruchomienia programu, wywołanie metody obiektu, nawet bez uprzedniej znajomości jej nazwy, stworzenie tablicy, której rozmiar i typ przechowywanych obiektów nie jest znany aż do chwili wykonania programu, a następnie modyfikowanie przechowywanych w niej obiektów. Refactoring - 18
Wymagania stawiane narzędziom oraz algorytmom Zasada niezmienionego zachowania Samodzielne pozyskiwanie maksymalnej ilości potrzebnych danych Niemożność polegania na użytkowniku w sprawie bezpieczeństwa refaktoryzacji Udostępnianie użytkownikowi listy problemów Maksymalnie dobra jakość generowanego kodu Prostota i łatwość modyfikacji wygenerowanego kodu Brak kompilacji kodu w trakcie refaktoryzacji w celu sprawdzenia jego poprawności Refactoring - 19
Wpływ dodania klasy na zachowanie Przed import java.util.*; class A { HashMap m = new HashMap();} Po import java.util.*; class HashMap {} class A { HashMap m = new HashMap();} Refactoring - 20
Refaktoryzacje (1) Zmiana nazwy (Rename) Przemieszczenie klasy (Move class) Przemieszczenie pola statycznego (Move static field) Przemieszczenie pola (Move field) Przemieszczenie metody statycznej (Move static method) Przemieszczenie metody nie-statycznej (Move non-static method) Ekstrakcja metody (Extract Method) Rozwinięcie wywołań metody (Inline method) Rozwinięcie odwołań do zmiennej (Inline variable) Wprowadzenie zmiennej objaśniającej (Introduce explaining variable) Awansowanie zmiennej do pola (Promote temporary to field) Zmiana nagłówka metody (Change method signature) Ekstrakcja interfejsu (Extract Interface) Ekstrakcja nadklasy (Extract Superclass) Refactoring - 21
Refaktoryzacje (2) Przemieszczenie metody/pola w dół hierarchii dziedziczenia (Push down method/field) Przemieszczenie metody/pola w górę hierarchii dziedziczenia (Pull up method/field) Enkapsulacja dostępu do pola (Encalpsulate field) Użycie typu nadrzędnego gdzie to możliwe (Use Supertype where possible) Dodanie metod delegujących (Add delegate methods) Oczyszczenie deklaracji import (Clean imports) Minimalizowanie praw dostępu (Minimize Access Rights) Stworzenie metody fabrycznej (Create factory method) Wprowadzenie stałej (Introduce constant) Ustatycznienie metody (Make method static) Bezpieczne usunięcie (Safe delete) Zamiana klasy anonimowej na zagnieżdżoną (Convert anonymous to inner) Zastąpienie zmiennej wyrażeniem (Replace temp with query) Wyodrębnienie na zewnątrz łańcuchów tekstowych (Externalize Strings) Refactoring - 22
Wprowadzenie Obiektu Null Przed class ZamykaczOkien { void pozamykaj() { Okno o = znajdźokno(); if (o!= null) { o.zamknij(); } } Okno znajdźokno() { return null; } } Po class ZamykaczOkien { void pozamykaj() { Okno o = znajdźokno(); o.zamknij(); } } Okno znajdźokno() { return new OknoNull(); } class OknoNull extends Okno { public void zamknij() {} } Refactoring - 23
Redukcja zakresu zmiennej Przed int i=1; zróbcoś(); zróbcośinnego(); obliczjeszczecośinnego(); pierwszeużycie(i);... Po zróbcoś(); zróbcośinnego(); obliczjeszczecośinnego(); int i = 1; pierwszeużycie(i); Refactoring - 24
Wprowadzenie Klasy Wyliczeniowej (1) Przed public class Person { public static final int BLOOD_GROUP_0 = 0; public static final int BLOOD_GROUP_A = 1; public static final int BLOOD_GROUP_B = 2; public static final int BLOOD_GROUP_AB = 3; private int bloodgroup; public Person(int bg) { bloodgroup = bg; } } Po public class Person { private BloodGroup bloodgroup; public Person(BloodGroup bg) { bloodgroup = bg; } } public class BloodGroup { public static final int 0 = new BloodGroup(0); public static final int A = new BloodGroup(1); public static final int B = new BloodGroup(2); public static final int AB = new BloodGroup(3); private int bloodgroup; private BloodGroup(int bg) { bloodgroup = bg; } } Refactoring - 25
Wprowadzenie Klasy Wyliczeniowej (2) Refactoring - 26
Refaktoryzacja w Eclipse Refactoring - 27
Refaktoryzacja w Eclipse Refactoring - 28
Refaktoryzacja w Visual Studio Refactoring - 29