6CS002, Dr K Buckley 1 Refactoring Dr. Kevan Buckley 6CS002, Dr K Buckley 2 Lecture Outcomes • To understand refactoring – What it is – Why we do it – How we do it • Some common refactorings • Refactoring in Eclipse • Refactoring an application – Calculator application 6CS002, Dr K Buckley 3 Refactoring "Refactoring is the process of changing a software system in such a way that it does not alter the external behaviour of the code yet improves the internal structure. It is a disciplined way to clean up code that minimizes the chances of introducing bugs. In essence when you refactor you are improving the design of code after it has been written ." "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - Martin Fowler, 1999,"Refactoring: Improving the Design of Existing Code" "Refactoring is the art of improving the design of existing code. Refactoring provides us with ways to recognise problematic code and gives us recipes for improving it." - William C. Wake, 2004, "Refactoring Workbook" 6CS002, Dr K Buckley 4 Refactoring: • Improves the design of software – Without refactoring, the design of a program will decay over time. • Changes are often made to realise short-term goals • Code looses its structure – cumulative – "Lava Flow" – Poorly designed code results in more code • Duplications • There is more code to understand and maintain • Makes software easier to understand – Make the code better communicate its purpose • Less to remember (if it is your code) • Easier to understand (if it is somebody else's) – Refactor to understand unfamiliar code. 6CS002, Dr K Buckley 5 Refactoring: • Helps you find bugs – Makes you focus on a deep understanding of what the code does • Clarifying assumptions often identifies bugs – Makes code more robust • Helps you program faster – Good software is build on a good design – By alleviating the decay we improve design • Improves quality – Less time spent debugging • High quality components lead to high quality products 6CS002, Dr K Buckley 6 Refactoring: • Does not just include any changes in a system – design improvements or new functionality not included • Is not rewriting from scratch – improves existing code, rather than risk recoding • Is not just any restructuring intended to improve code – refactoring concentrates on safe transformations • Changes the balance between up-front design and emergent design – refactoring lowers the cost and risk of the emergent approach • Can be small or large – system must be kept running at all times 6CS002, Dr K Buckley 7 When To Refactor • When you add a new function – If you struggle to understand code to add a new feature, you should refactor to make it easier to understand. – If the present design does not allow easy addition of a new feature, refactor it so that it does. • Allows the new feature to be incorporated. • Eases the job of adding new features in the future. • When you need to fix a bug – Improving your understanding of the code leads to finding a bug • Whilst you do a code review – To explain your code to other programmers 6CS002, Dr K Buckley 8 Refactoring in Eclipse • One reason we use eclipse is its powerful refactoring capabilities Refactoring menu You should spend time learning to use eclipse properly 6CS002, Dr K Buckley 9 Simple Refactorings The following slides outline some of the simple refactorings 6CS002, Dr K Buckley 10 Extract Method • You have a code fragment that can be grouped together. • Turn the fragment of code into a method whose name explains the purpose of the method. • Can alleviate the need for comments inside methods. – The method name clearly explains the purpose. – Fine details can go in javadoc comments and result in documentation. • Resulting methods might be usable elsewhere 6CS002, Dr K Buckley 11 public class ExtractMethodBefore { int [][] points = {{ 1 , 2 },{ 3 , 4 },{ 5 , 6 }}; public void printPoints() { // print points in natural order for ( int y = 0 ; y < points.length; y++) { for ( int x = 0 ; x < points[ 0 ].length; x++) { System.out.print(points[y][x]); } System.out.println(); } // print points in transposed order for ( int x = 0 ; x < points[ 0 ].length; x++) { for ( int y = 0 ; y < points.length; y++) { System.out.print(points[y][x]); } System.out.println(); } } } Apply extract method 6CS002, Dr K Buckley 12 public class ExtractMethodAfter { int [][] points = {{ 1 , 2 },{ 3 , 4 },{ 5 , 6 }}; public void printPoints() { printPointsInNaturalOrder(); printPointsInTransposedOrder(); } private void printPointsInNaturalOrder() { for ( int y = 0 ; y < points.length; y++) { for ( int x = 0 ; x < points[ 0 ].length; x++) { System.out.print(points[y][x]); } System.out.println(); } } private void printPointsInTransposedOrder() { for ( int x = 0 ; x < points[ 0 ].length; x++) { for ( int y = 0 ; y < points.length; y++) { System.out.print(points[y][x]); } System.out.println(); } } 6CS002, Dr K Buckley 13 Rename Method • The name of a method does not reveal its purpose. • Rename the method. • Good method names are self-documenting – Better public interface. – Easier maintenance and code understanding • Similarly variables with poor names should be renamed. 6CS002, Dr K Buckley 14 public class BeforeRenameMethod { private int width, height, area; public BeforeRenameMethod ( int width, int height) { this .width = width; this .height = height; mysteriousOperation(); } public void y( int height) { this .height = height; mysteriousOperation(); } public void x( int width) { this .width = width; mysteriousOperation(); } private void mysteriousOperation() { area = width * height; } } Apply rename method 6CS002, Dr K Buckley 15 public class AfterRenameMethod { private int width, height, area; public AfterRenameMethod( int width, int height) { this .width = width; this .height = height; calculateArea(); } public void setHeight ( int height) { this .height = height; calculateArea(); } public void setWidth ( int width) { this .width = width; calculateArea(); } private void calculateArea () { area = width * height; } } 6CS002, Dr K Buckley 16 Parameterise Method • Several Methods do similar things but with different values contained in the method body. • Create one method that uses a parameter for different values. – Replace the calls to the old method one by one. – Eventually delete the old methods. • Reduces duplication. • Provides a more flexible method that can be used elsewhere. 6CS002, Dr K Buckley 17 public class BeforeParameteriseMethod { int [][] points = { { 1 , 2 }, { 3 , 4 }, { 5 , 6 } }; public void processPoints() { multiplyByTwo(); multiplyByThree(); } private void multiplyByTwo() { for ( int y = 0 ; y < points.length; y++) { for ( int x = 0 ; x < points[ 0 ].length; x++) { points[y][x] = points[y][x] * 2 ; } } } private void multiplyByThree() { for ( int y = 0 ; y < points.length; y++) { for ( int x = 0 ; x < points[ 0 ].length; x++) { points[y][x] = points[y][x] * 3 ; } } } Apply parameterise method 6CS002, Dr K Buckley 18 public class AfterParameteriseMethod { int [][] points = {{ 1 , 2 }, { 3 , 4 }, { 5 , 6 }}; public void processPoints() { multiplyBy( 2 ); multiplyBy( 3 ); } private void multiplyBy( int factor) { for ( int y = 0 ; y < points.length; y++) { for ( int x = 0 ; x < points[ 0 ].length; x++) { points[y][x] = points[y][x] * factor; } } } public static void main(String[] args) { new AfterParameteriseMethod().processPoints(); } } 6CS002, Dr K Buckley 19 Introduce Explaining Variable • You have a complicated expression. • Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose. • Makes code more readable as the variables document the code – Self documenting code 6CS002, Dr K Buckley 20 public class BeforeIntroduceExplainingVariable { public void printCopyingCosts( double width, double height) { if (width*height> 80 || Math.sqrt(width*width+height*height)> 90 ) { System.out.println( "Paper is over size" ); System.out.println( "Cost is £4 per sheet" ); } else { System.out.println( "Paper is normal size" ); System.out.println( "Cost is £1 per sheet" ); } } } Apply introduce explaining variable