Software Engineering Refactoring CIT2C06 Software Engineering AY 2006/2007 Oct Semester TEMASEK INFORMATION TECHNOLOGY SCHOOL Objectives Describe List the purpose of code refactoring. code smells. Apply code refactoring. 2 TEMASEK INFORMATION TECHNOLOGY SCHOOL What is Code Refactoring The process of changing a software system in such a way that it: improves the internal code structure does not alter external behavior of code public class Student { public String name; public static void main(String[] args) { Student s1 = new Student(); s1.name = “Tan Ah Beng”; Student s2 = new Student(); s2.name = “Lim Ah Seng”; } } Any problems with this code? 3 TEMASEK INFORMATION TECHNOLOGY SCHOOL Code Refactoring in Action Use getter and setter methods Step 1: Create getter and setter methods public class Student { public String name; public String getName() { return name; } public void setName(String newName) { name = newName; } public static void main(String[] args) { Student s1 = new Student(); s1.name = “Tan Ah Beng”; Student s2 = new Student(); s2.name = “Lim Ah Seng”; } } 4 TEMASEK INFORMATION TECHNOLOGY SCHOOL Code Refactoring in Action Step 2: Find all clients; replace references with calls. Do this one at a time public class Student { public String name; public String getName() { return name; } public String setName(String newName) { name = newName; } public static void main(String[] args) { Student s1 = new Student(); s1.setName(“Tan Ah Beng”); Student s2 = new Student(); s2.name = “Lim Ah Seng”; } } 5 TEMASEK INFORMATION TECHNOLOGY SCHOOL Code Refactoring in Action Step 3: Compile and test Back to step 2: Replace other references public class Student { public String name; public String getName() { return name; } public String setName(String newName) { name = newName; } public static void main(String[] args) { Student s1 = new Student(); s1.setName(“Tan Ah Beng”); Student s2 = new Student(); s2.setName(“Lim Ah Seng”); } } 6 TEMASEK INFORMATION TECHNOLOGY SCHOOL Code Refactoring in Action Back to step 3: Compile and test Step 4: Once all clients are changed, make the field private Step 5: Compile and test one last time public class Student { private String name; public String getName() { return name; } public String setName(String newName) { name = newName; } public static void main(String[] args) { Student s1 = new Student(); s1.setName(“Tan Ah Beng”); Student s2 = new Student(); s2.setName(“Lim Ah Seng”); } } 7 TEMASEK INFORMATION TECHNOLOGY SCHOOL Refactoring Why refactor? Improves the design of software Makes software easier to understand Helps you find bugs Helps you program faster When do we refactor? When you add function When you need to fix a bug When you do a code review 8 TEMASEK INFORMATION TECHNOLOGY SCHOOL Detecting Code Smells Code smells are warning signs about problems within the code Common smells Duplicated code Long methods Long parameter list Large classes (in terms of instance variables, methods and lines) Data clumps (groups of data items appearing together in lots of places) Comments (is it really a bad smell?) 9 TEMASEK INFORMATION TECHNOLOGY SCHOOL Refactoring Cycle 1. 2. Start with a working program While smells remain a. Choose the worst smell b. Select a refactoring that will address the smell c. Apply the refactoring Remember: the condition for refactoring safely is to have tests to cover those code we want to refactor 10 TEMASEK INFORMATION TECHNOLOGY SCHOOL Code Refactoring Parameterize Pass method Whole Object Replace Magic Number with Named Constants 11 TEMASEK INFORMATION TECHNOLOGY SCHOOL Parameterize Method Several methods do similar things but each uses different values Replace them with one method that uses a parameter for the different values Toy getTenPercentDiscountedPrice():double getFivePercentDiscountedPrice():double Toy getDiscountedPrice(percent):double 12 TEMASEK INFORMATION TECHNOLOGY SCHOOL Parameterize Method Example public class Wizard { private int willPower; public int castFireSpell(int damage) { return damage + (willPower * 1.1); } public int castColdSpell(int damage) { return damage + (willPower * 2.1); } public static void main(String[] args) { …………………………… damage = wizard.castFireSpell(damage); damage = wizard.castColdSpell(damage); …………………………… } } 13 TEMASEK INFORMATION TECHNOLOGY SCHOOL Parameterize Method in Action public class Wizard { private int willPower; public int castFireSpell(int damage) { return damage + (willPower * 1.1); } public int castColdSpell(int damage) { return damage + (willPower * 2.1); } public int castSpell(int damage, int factor) { return damage + (willPower * factor); } public static void main(String[] args) { …………………………… damage = wizard.castFireSpell(damage); damage = wizard.castColdSpell(damage); …………………………… } } 14 TEMASEK INFORMATION TECHNOLOGY SCHOOL Parameterize Method in Action public class Wizard { private int willPower; public int castFireSpell(int damage) { return damage + (willPower * 1.1); } public int castColdSpell(int damage) { return damage + (willPower * 2.1); } public int castSpell(int damage, int factor) { return damage + (willPower * factor); } public static void main(String[] args) { …………………………… damage = wizard.castSpell(damage,1.1); damage = wizard.castColdSpell(damage); …………………………… } } 15 TEMASEK INFORMATION TECHNOLOGY SCHOOL Parameterize Method in Action public class Wizard { private int willPower; public int castFireSpell(int damage) { return damage + (willPower * 1.1); } public int castColdSpell(int damage) { return damage + (willPower * 2.1); } public int castSpell(int damage, int factor) { return damage + (willPower * factor); } public static void main(String[] args) { …………………………… damage = wizard.castSpell(damage,1.1); damage = wizard.castSpell(damage,2.1); …………………………… } } 16 TEMASEK INFORMATION TECHNOLOGY SCHOOL Pass Whole Object You get several values from an object and pass these values as parameters in a method call Send the whole object instead int low = tempRange.getLow(); int high = tempRange.getHigh(); int ave = monitor.computeAverage(low, high); int ave = monitor.computeAverage(tempRange); 17 TEMASEK INFORMATION TECHNOLOGY SCHOOL Pass Whole Object Example class Game { void throwGrenade(Person rambo, Grenade g) { int xPos = rambo.getX(); int yPos = rambo.getY(); if (g.isWithinRange(xPos, yPos)) rambo.addDamage(10); } } class Grenade { boolean isWithinRange(int xPos, int yPos) { if ((xPos >= gx) && (xPos <= gx + 25) && (yPos >= yx) && (yPos <= yx + 25)) return true; else return false; } } 18 TEMASEK INFORMATION TECHNOLOGY SCHOOL Pass Whole Object in Action class Game { void throwGrenade(Person rambo, Grenade g) { int xPos = rambo.getX(); int yPos = rambo.getY(); if (g.isWithinRange(rambo, xPos, yPos)) rambo.addDamage(10); } } class Grenade { boolean isWithinRange(Person r, int xPos, int yPos) { if ((xPos >= gx) && (xPos <= gx + 25) && (yPos >= yx) && (yPos <= yx + 25)) return true; else return false; } } 19 TEMASEK INFORMATION TECHNOLOGY SCHOOL Pass Whole Object in Action class Game { void throwGrenade(Person rambo, Grenade g) { int xPos = rambo.getX(); int yPos = rambo.getY(); if (g.isWithinRange(rambo, xPos, yPos)) rambo.addDamage(10); } } class Grenade { boolean isWithinRange(Person r, int xPos, int yPos) { if ((r.getX() >= gx) && (r.getX() <= gx + 25) && (r.getY() >= yx) && (r.getY() <= yx + 25)) return true; else return false; } } 20 TEMASEK INFORMATION TECHNOLOGY SCHOOL Pass Whole Object In Action class Game { void throwGrenade(Person rambo, Grenade g) { int xPos = rambo.getX(); int yPos = rambo.getY(); if (g.isWithinRange(rambo, xPos, yPos)) rambo.addDamage(10); } } class Grenade { boolean isWithinRange(Person r, int xPos, int yPos) { if ((r.getX() >= gx) && (r.getX() <= gx + 25) && (r.getY() >= yx) && (r.getY() <= yx + 25)) return true; else return false; } } 21 TEMASEK INFORMATION TECHNOLOGY SCHOOL Replace Magic Number with Named Constant In your code, you use literals directly Instead of using the literals directly, create a constant giving it an appropriate name, and use the constant instead double parcelAmount (double wt) { return 0.50 * wt; } private final static double AIRMAIL_RATE = 0.50; double parcelAmount (double wt) { return AIRMAIL_RATE * wt; } 22 TEMASEK INFORMATION TECHNOLOGY SCHOOL Recap What is refactoring and why is it important? Describe 3 code smells. Give examples on the application of the following refactorings: Parameterize Method Pass Whole Object Replace Magic Number with Named Constant 23