490 likes | 620 Views
Refactoring and its role in Test-Driven Development. Miguel J. T. Pessoa Monteiro Escola Superior de Tecnologia de Castelo Branco. Overview. Characterisation of Refactoring Brief History of Refactoring Examples of refactoring steps How refactorings are performed
E N D
Refactoringand its role inTest-Driven Development Miguel J. T. Pessoa Monteiro Escola Superior de Tecnologiade Castelo Branco
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
Refactoring Tenet of Refactoring • Program source code is a mechanism of communication between humans, not between the programmer and the computer.
Intentionality is Important public void add(Object element) { if(!readOnly) { int newSize = size + 1; if(newSize > elements.length) { Object[] newElements = new Object[elemnts.length + 10]; for(int i=0; i<size; i++) newElements[i] = elements[i]; elements = newElements; } elements[size++] = element; } } public void add(Object element) { if(readOnly) return; if(atCapacity()) grow(); addElement(element); }
Characterising Refactoring Martin Fowler: • “a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behaviour.”
Characterising Refactoring Martin Fowler: • “Each transformation does little, • but a sequence of transformations can produce a significant restructuring. • Since each refactoring is small, it's less likely to go wrong”.
The “Two Hat” Metaphor • Programmer always wearing one of 2 hats: • The developer hat • The refactoring hat • If the task can be made easier if the code is structured differently, • Programmer swaps hats and refactors for a while. • Then he swaps hats again, and adds the functionality.
What is not Refactoring • Adding new functionalityis not refactoring • Optimisation is not refactoring • Changing code that does not compileis not refactoring(what would be the behaviour?)
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
Brief History of Refactoring • Griswold W., Program restructuring as an aid to software maintenance. PhD thesis, University of Washington, USA, 1991. • Opdyke W., Refactoring Object-Oriented Frameworks, Ph.D. Thesis, University of Illinois at Urbana-Champaign, USA, 1992. • Roberts D., Brant J., Johnson R., A refactoring tool for smalltalk. Theory and Practice of Object Systems 3(4), pp. 253–263, 1997.
Brief History of Refactoring • Advent of unit tests (e.g. xUnit) • Made manual refactoring possible. • Advent of Extreme Programming (XP) • Test-driven development: Unit testing, Refactoring, Pair programming, etc. • Martin Fowler’s book • Promoted refactoring to buzzword status
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
Reverse Conditional You have a conditional that would be easier to understand if you reversed its sense. Reverse the sense of the conditional and reorder the conditional's clauses. if ( !isSummer( date ) ) charge = winterCharge( quantity ); else charge = summerCharge( quantity ); if ( isSummer( date ) ) charge = summerCharge( quantity ); else charge = winterCharge( quantity );
Rename Method The name of a method does not reveal its purpose. Change the name of the method.
Move Method A method is, or will be, (using or) used by more features of another class than the class on which it is defined. Create a new method with a similar body in the class it uses most. Either turn the old method into a simple delegation, or remove it altogether.
Pull Up Method You have methods with identical results on subclasses. Move them to the superclass.
Extract Method You have a code fragment that can be grouped together. Turn the fragment into a method whose name explains the purpose of the method. void printOwing() { printBanner(); //print detailsSystem.out.println ("name: " + _name); System.out.println ("amount " + getOutstanding());} void printOwing() { printBanner();printDetails(getOutstanding()); }void printDetails (double outstanding) { System.out.println ("name: " + _name); System.out.println ("amount " + outstanding);}
Extract Method You have a code fragment that can be grouped together. Turn the fragment into a method whose name explains the purpose of the method. void printOwing() { printBanner(); //print detailsSystem.out.println ("name: " + _name); System.out.println ("amount " + getOutstanding());} void printOwing() { printBanner();printDetails(getOutstanding()); }void printDetails (double outstanding) { System.out.println ("name: " + _name); System.out.println ("amount " + outstanding);}
Inline Method A method's body is just as clear as its name. Put the method's body into the body of its callers and remove the method. int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; } boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; } int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1; }
Opposite to Extract Method Inline Method A method's body is just as clear as its name. Put the method's body into the body of its callers and remove the method. int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; } boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; } int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1; }
Replace Conditional with Polymorphism You have a conditional that chooses different behavior depending on the type of an object. Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract. double getSpeed() { switch (_type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts; case NORWEIGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage); } throw new RuntimeException ("Should be unreachable"); }
Replace Conditional with Polymorphism You have a conditional that chooses different behavior depending on the type of an object. Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
How Refactorings are Performed • Either manually or automatically. • When done manually, it is always done in small steps (called refactorings). • Larger refactorings are sequences of smaller ones
Manual Refactoring • Manual refactoring steps should always be small, because: • They are safer this way, because the steps are simpler • It is easier to backtrack Pay attention to the mechanics: • Mechanics should stress safety
How Refactorings are Performed • When automatic support is available, it should be preferred, but ... • ... only if the tool is really safe. • Example: Rename Method • Does it check for another method with the same name? • Does it account for overloading? • Does it account for overriding?
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
When to Refactor We should refactor when the code stinks. “If it stinks, change it.” Grandma Beck,discussing child-rearing philosophy
Refactoring and code smells Refactorings remove Bad Smells in the Code i.e., potential problems or flaws • Some will be strong, some will be subtler • Some smells are obvious, some aren’t • Some smells mask other problems • Some smells go away unexpectedly when we fix something else
Refactoring and code smells Examples of code smells: • Duplicated Code, Large Class, Lazy Class, Long Method, Long Parameter List, Primitive Obsession, Speculative Generality, Temporary Field, Inappropriate Intimacy, Data Class, Refused Bequest, Comments, ... • Frequent cause:the paradigm shift problem
Refactoring and code smells Code smells motivate use of refactorings to remove them, e.g. Duplicated Code → Extract Method, Extract Class, Form Template Method, ... Long Method→ Extract Method, Replace Temp with Query, Introduce Parameter Object,Decompose Conditional, ...
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
Unit Tests • Essential prerequisite for refactoring:Solid tests (i.e. good unit test coverage) • Tests warn programmers of problems if they unknowningly break other parts of the application • Tests give an immediate/quick analysis of the effects of a change • Therefore tests give Courage
Unit Tests Essential characteristic of unit tests: • They must be automatic • No need to see console outputs • No need to specially prepare them to run • They should independent of each other • They should run often • They should make it easy to run often(otherwise developers will stop running them) • They must be fast
Unit Tests A test is not an unit test if: • It talks to a database • It communicates across a network • It touches the file system Such tests are good, but not fast enough to run in a suite of thousands of tests
Ciclo RED-GREEN-REFACTOR Escrever um teste Refabricar o código(e testar) Compilar Corrigir os erros do compilador Correr os testes e vera barra verde Correr os testes e vera barra vermelha Escrever novo código
Fase RED Escrever um teste Refabricar o código(e testar) Compilar Corrigir os erros do compilador Correr os testes e vera barra verde Correr os testes e vera barra vermelha Escrever novo código
Fase RED Escrever um teste Refabricar o código(e testar) Compilar Corrigir os erros do compilador Correr os testes e vera barra verde Correr os testes e vera barra vermelha Escrever novo código Fase GREEN
Fase RED Fase REFACTOR Escrever um teste Refabricar o código(e testar) Compilar Corrigir os erros do compilador Correr os testes e vera barra verde Correr os testes e vera barra vermelha Escrever novo código Fase GREEN
Overview • Characterisation of Refactoring • Brief History of Refactoring • Examples of refactoring steps • How refactorings are performed • When to refactor (code smells) • Role of unit tests in refactoring • Resources
Resources – TDD & refactoring • Refactoring home pagewww.refactoring.com/ • Refactoring mailing list at Yahoogroups.yahoo.com/group/refactoring/
Resources – TDD & refactoring test-driven development:A Practical Guide Dave Astels Prentice-Hall/Pearson Education, 2003 ISBN 0-13-101649-0 ___________________________ Test-Driven Development:By Example Kent Beck Addison-Wesley, 2003 ISBN 0-321-14653-0
Resources – TDD & refactoring Refactoring:Improving the Design of Existing Code Martin Fowler Addison-Wesley, 1999 ISBN 0-201-48567-2
Resources – TDD & refactoring Refactoring Workbook William Wake Addison-Wesley, 2003 ISBN 0-32-110929-5
Resources – TDD & refactoring Refactoring to Patterns Joshua Kerievsky Addison-Wesley, 2004 ISBN 0-321-21335-1
Resources – TDD & refactoring JUnit Recipes –Practical Methods for ProgrammerTesting J.B. Rainsberger Manning 2005 ISBN 1932394230
Resources – TDD & refactoring Working Effectively with Legacy Code Michael Feathers Addison-Wesley, 2005 ISBN 0-13-117705-2
Resources – TDD & refactoring Agile Java - Crafting Code with Test-Driven Development Jeff Langr Prentice Hall 2005 ISBN 0-13-148239-4
Refactoring and its role inTest-Driven Development Questions? Miguel J. T. Pessoa Monteiro Escola Superior de Tecnologiade Castelo Branco