Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Refactoring

6,734 views

Published on

How to improve your code quality? The answer is continuous refactoring. Learn more about refactoring. Know the most frequent code smells (antipatterns), telling when to refactor. Go through the catalog of well-known refactorings, telling how to improve your code.

Published in: Software
  • Be the first to comment

Refactoring

  1. 1. Refactoring! How to improve your code! ARTEM TABALIN!
  2. 2. What is refactoring?! Definition. Goals. When to Refactor. Pitfalls.!
  3. 3. What is Refactoring?! ! “Refactoring is a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.”! - Martin Fowler! Is it just cleaning up code?! The technique of cleaning up code in more organized and controlled way!
  4. 4. The Two Hats! Two distinct activities! 1.  adding functions 2.  refactoring! These two activities should NOT take place at the same time!
  5. 5. Goals! •  Prevent code quality reduction! •  Make code clear! •  Help to find bugs! •  Help to program faster
  6. 6. When to Refactor! The Rule of Three Three strikes and you refactor! 1.  You do something the first time! 2.  You do similar thing again with regret! 3.  On the third time – start refactoring! !
  7. 7. When to Refactor! •  When adding new functionality! •  understanding the code! •  prepare code for adding new functionality! •  When fixing a bug! •  error is a sign for refactoring! •  Code reviews!
  8. 8. Problems with Refactoring! Database! •  difficult to change since tightly coupled to scheme! •  existing data migration! Changing Interface! •  deprecate old interface! •  just call new method in old method! •  don’t publish premature interfaces!
  9. 9. When You Shouldn’t Refactor! Low code quality! •  easier rewrite than refactor! •  code should work correctly before refactoring! Deadline is too close! •  postpone refactoring = technical debt!
  10. 10. Smelling Code! Signs of low quality code!
  11. 11. Code Duplication! •  The same code in two methods! Extract Method! •  The same code in two subclasses! Extract Method + Pull Up Field / Method! •  The same code in two different classes! Extract Class!
  12. 12. Long Method! •  Sections in method! •  Wish to comment part of code ! •  Long loops and conditionals! Extract Method!
  13. 13. Large Class! •  To many methods! •  To many fields! Extract Class / Extract Subclass!
  14. 14. Long Parameter List! •  Method can calculate parameter itself! Replace Parameter with Method! •  Parameters are fields of single object! Preserve Whole Object! •  Several related parameters! Introduce Parameter Object!
  15. 15. Divergent Change! •  Class is changed for different reasons! Extract Class!
  16. 16. Shotgun Surgery! •  Lots of little changes to lot of different classes! Move Method / Move Field!
  17. 17. Feature Envy! •  Method is interested in another class too much! Move Method [+ Extract Method]! Exceptions! •  Strategy! •  Visitor! •  Data Access Layer!
  18. 18. Data Clumps! •  Few data items together in lots of places! Extract Class / Introduce Parameter Object!
  19. 19. Primitive Obsession! •  Avoiding small classes and using primitives instead! range, money, phone, array instead of object! Replace Data Value with Object! Extract Class / Introduce Parameter Object!
  20. 20. Switch Statements! •  Switch statements all over the class! Replace Type Code with Subclasses! Replace Conditional with Polymorphism! •  Few switch statements! Replace Type Code with Strategy / State! •  Null special cases! Introduce Null Object!
  21. 21. Speculative Generality! We need this functionality someday! •  Unnecessary base class! Collapse Hierarchy! •  Unnecessary delegation! Inline Class! •  Strange abstract method name! Rename Method!
  22. 22. Inappropriate Intimacy! Classes too coupled! •  Use fields and methods of each other! Change Bidirectional Association with Unidirectional! •  Have common interests! Extract Class! •  High coupling due to inheritance! Replace Inheritance with Delegation!
  23. 23. Other Smells! •  Lazy Class! Inline Class! •  Temporary Field! Extract Class! •  Message Chains getThis().getThat().getObject().method()! Hide Delegate! •  Refused Bequest! Replace Inheritance with Delegation! !
  24. 24. Comments! Used like a deodorant Indicators of bad code! If you need a comment try to refactor! •  Extract Method! •  Rename Method! •  Introduce Assertion! !
  25. 25. Catalog of Refactorings!
  26. 26. Composing Methods! Extract Method. Inline Method. Temporary Variables. Replace Method with Method Object. !
  27. 27. Extract Method! Turn the fragment of code into a method! When •  Method is too long! •  Code needs an explanatory comment! Why •  Increase reusability! •  Higher level methods become more readable! •  Easier to override!
  28. 28. Extract Method! public  void  PrintClient(Client  client)  {          PrintBanner();          //  print  client  details          Console.Write("Name:  "  +  client.Name);          Console.Write("Address:  "  +  client.Address);   }   public  void  PrintClient(Client  client)  {          PrintBanner();          PrintClientDetails(client);   }   private  void  PrintClientDetails(Client  client)  {          Console.Write("Name:  "  +  client.Name);          Console.Write("Address:  "  +  client.Address);   }  
  29. 29. Inline Method! Put the method body to callers and remove it! When •  Method body is as clear as its name! •  Calling method is badly factored! Why •  Reduce redundant delegation! •  Restructure calling method!
  30. 30. Inline Method! public  int  GetRating()  {          return  MoreThanFiveLateDeliveries()  ?  2  :  1;   }   private  bool  MoreThanFiveLateDeliveries()  {          return  _numberOfLateDeliveries  >  5;   }   public  int  GetRating()  {          return  (_numberOfLateDeliveries  >  5)  ?  2  :  1;   }  
  31. 31. Replace Temp with Query! Extract expression to a method and replace temp! When •  Temp holds an expression result for other methods! •  Temp prevents from another refactoring! Why •  Cleaner code! •  Shorter method! •  The result is available to all methods!
  32. 32. Replace Temp with Query! public  double  GetPrice()  {          double  basePrice  =  _quantity  *  _itemPrice;            return  (basePrice  >  1000)                    ?  basePrice  *  0.95                  :  basePrice  *  0.98;   }   public  double  GetPrice()  {          return  (BasePrice  >  1000)                    ?  BasePrice  *  0.95                  :  BasePrice  *  0.98;   }     private  double  BasePrice  {          get  {  return  _quantity  *  _itemPrice;  }   }  
  33. 33. Introduce Explaining Variable! Assign a part of expression to explaining variable! When •  Complex condition! •  Complex algorithm! Why •  Improve code readability! !
  34. 34. Introduce Explaining Variable! if  ((platform.toUpperCase().indexOf("MAC")  >  -­‐1)  &&          (browser.toUpperCase().indexOf("IE")  >  -­‐1)  &&          isInitialized()  &&  resize  >  0)  {          //  do  something   }   var  isMac  =  platform.toUpperCase().indexOf("MAC")  >  -­‐1;   var  isIEBrowser  =  browser.toUpperCase().indexOf("IE")  >  -­‐1;   var  isResized  =  resize  >  0;   if  (isMac  &&  isIEBrowser  &&  isInitialized()  &&  isResized){          //  do  something   }  
  35. 35. Replace Method with Method Object! Transform long method into object! When •  Long method with lots of temp variables! Why •  Improve readability! •  Increase reusability! !
  36. 36. Replace Method with Method Object! class  Transaction  {          public  double  BankFee()  {                  double  amount;                  double  price;                  double  tax;                  //  long  computations          }   Transaction +BankFee() BankFeeCalculator -amount -price -tax +Compute() 1 return new BankFeeCalculator(this).Compute();
  37. 37. Moving Features Between Objects! Move Method. Move Field. Extract Class. Inline Class. Hide Delegation.!
  38. 38. Move Method! Move the method to the class that uses it most! When •  Method references another object too much! •  Two classes are too coupled! •  Class is overcomplicated! Why •  Lower coupling! •  Simplify design! !
  39. 39. Move Method! class  Account  {      private  AccountType  _type;      public  double  BankCharge()  {          double  result  =  FIXED_FEE;          if(HasOverdraft())              result  +=  OverdraftFee();          return  result;      }      private  double  OverdraftFee()  {          if(_type.IsPremium())  {              //  premium  account          }  else  {              //  standard  account          }      }     class  Account  {      public  double  BankCharge()  {          double  result  =  FIXED_FEE;          if(HasOverdraft())              result  +=  _type.OverdraftFee();          return  result;      }   class  AccountType  {      public  double  OverdraftFee()  {          if(IsPremium())  {              //  premium  account          }  else  {              //  standard  account          }      }  
  40. 40. Move Field! Move the field to class that uses it most! When •  Another class uses a field more than its owner! •  Performing Extract Class refactoring! Why •  Lower coupling! •  Simplify design! ! !
  41. 41. Move Field!   class  Account  {      private  AccountType  _type;      private  double  _interestRate;      public  double  InterestRate  {          get  {  return  _interestRate;  }      }      double  Interest(int  days)  {          return  InterestRate  *  days/365;      }       class  Account  {      double  Interest(int  days)  {          return  _type.InterestRate  *  days/365;      }   class  AccountType  {      private  double  _interestRate;      public  double  InterestRate  {          get  {  return  _interestRate;  }      }  
  42. 42. Extract Class! Create new class and move fields and methods! When •  Class is too big! •  Single Responsibility Principle violation! •  Data or methods dependent on each other! Why •  Simplify design! ! !
  43. 43. Extract Class! Person -name -officeAreaCode -officeNumber +OfficePhone() Person -name +OfficePhone() PhoneNumber -areaCode -number +Phone() -officePhone
  44. 44. Inline Class! Move fields & methods from class and remove it! When •  Class is useless! Why •  Simplify design! ! !
  45. 45. Inline Class! Person -name -areaCode -number +Phone() Person -name +Phone() PhoneNumber -areaCode -number +Phone() -phone
  46. 46. Hide Delegate! Create method on the server to hide the delegate! When •  object.getAnotherObject().method()! Why •  Lower coupling! •  Strengthen encapsulation! ! !
  47. 47. Hide Delegate! Client Person +Department() Department +Manager() Client Person +Manager() Department
  48. 48. Organizing Data! Self Encapsulate Field. Replacing Value with Object. Replace Magic Number with Constant. Replace Type Code with Subclasses/State/Strategy.!
  49. 49. Self Encapsulate Field! Create and use getter and setter to access field! When •  Provide access to the field from outside! •  Override property in a child class! Why •  Strengthen encapsulation! •  Higher flexibility! ! !
  50. 50. Self Encapsulate Field! private  double  _interestRate;   public  double  Interest(int  days)  {      return  _interestRate  *  days/365;   }   private  double  _interestRate;       public  double  InterestRate  {      get  {  return  _interestRate;  }      set  {  _interestRate  =  value;  }   }   public  double  Interest(int  days)  {      return  InterestRate  *  days/365;   }        
  51. 51. Replace Data Value with Object! Turn the data item to an object! When •  Data item has dedicated methods! •  Data items are used together in lots of places! Why •  Higher flexibility! ! !
  52. 52. Replace Data Value with Object! Order -customer: string Order Customer -name: string-customer
  53. 53. Replace Magic Number with Constant! Replace magic value with named constant! When •  There is a magic value in the code! Why •  Improve code readability! ! !
  54. 54. Replace Magic Number with Constant! double  PotentialEnergy(double  mass,  double  height)  {      return  mass  *  9.81  *  height;   }   static  const  double  GRAVITATIONAL_CONSTANT  =  9.81;   double  PotentialEnergy(double  mass,  double  height)  {      return  mass  *  GRAVITATIONAL_CONSTANT  *  height;   }    
  55. 55. Replace Type Code with Subclasses! Replace the type code with subclasses! When •  There is a type code influencing on class behavior! Why •  Increase extensibility! ! !
  56. 56. Replace Type Code with Subclasses! class  Employee  {      private  EmployeeType  _type;      Employee(EmployeeType  type)  {          _type  =  type;      }      public  double  Bonus  {          get  {              switch(_type)  {                  case  EmployeeType.Engineer:                      return  0.0;                  case  EmployeeType.Salesman:                      return  0.25;              }          }      }   } abstract  class  Employee  {      abstract  EmployeeType  Type  {  get;  }      abstract  double  Bonus  {  get;  }   }   class  Engineer:  Employee  {      public  override  EmployeeType  Type  {          get  {                return  EmployeeType.Engineer;            }      }      public  override  double  Bonus  {          get  {                return  0.0;            }      }   }  
  57. 57. Replace Type Code with State/Strategy! Replace the type code with state/strategy classes! When •  There is a type code influencing on class behavior! •  Type code may change during object life! Why •  Increase extensibility! ! !
  58. 58. Replace Type Code with State/Strategy! Employee EmployeeType << enum >> EmployeeType Salesman Engineer -type Employee Salesman Engineer -type
  59. 59. Simplifying Conditional Expressions! Decompose Conditional Expression. Replace Conditional with Polymorphism. Guard Clauses. Introduce Null Object.!
  60. 60. Decompose Conditional! Extract methods from condition and branches! When •  Condition with complex expression and branches! Why •  Improve code readability! !
  61. 61. Decompose Conditional! if  (date.Before(SUMMER_START)  ||  date.After(SUMMER_END))      charge  =  quantity  *  _winterRate  +  _winterServiceCharge;   else      charge  =  quantity  *  _summerRate;   if  (NotSummer(date))      charge  =  WinterCharge(quantity);   else        charge  =  SummerCharge(quantity);  
  62. 62. Replace Nested Conditional with Guard Clauses! Use guard clauses for all special cases! When •  Conditional expression with special case branch! Why •  Improve code readability! !
  63. 63. Replace Nested Conditional with Guard Clauses! double  PayAmount()  {      double  result;      if(_isDead)          result  =  DeadAmount();      else  {          if(_isSeparated)                result  =  SeparatedAmount();          else  {              if(_isRetired)                    result  =  RetiredAmount();              else                    result  =  NormalAmount();          }      }      return  result;   }     double  PayAmount()  {      if(_isDead)            return  DeadAmount();      if(_isSeparated)            return  SeparatedAmount();      if(_isRetired)            return  RetiredAmount();        return  NormalAmount();   }  
  64. 64. Replace Conditional with Polymorphism! Move every condition branch to subclass method! When •  There are conditions depending on object type! Why •  Increase extensibility! •  Improve code readability! ! !
  65. 65. Replace Conditional with Polymorphism! class  Employee  {      public  double  PayAmount()  {          switch  (_type)  {              case  EmployeeType.Engineer:  return  _salary;              case  EmployeeType.Salesman:  return  _salary  +  _commission;              case  EmployeeType.Manager:  return  _salary  +  _bonus;              default:  throw  new  WrongEmployeeTypeException();            }      }   Employee +PayAmount() Engineer +PayAmount() Salesman +PayAmount() Manager +PayAmount()
  66. 66. Introduce Null Object! Replace null value with special class! When •  There are lots of null checks! Why •  Reduce conditionals! ! !
  67. 67. Introduce Null Object! if(employee  ==  null)      name  =  NAME_PLACEHOLDER;   else        name  =  employee.FullName;   Employee +FullName() NullEmployee +FullName()
  68. 68. Making Method Calls Simpler! Rename Method. Separate Query from Modifier. Preserve Whole Object. Introduce Parameter Object. Error Handling Refactorings.!
  69. 69. Rename Method! Change method name! When •  Method name doesn't show its intention ! Why •  Improve code readability!
  70. 70. Rename Method! SecurityPrice +LowerLimitExceed() SecurityPrice +IsLowerLimitExceeded()
  71. 71. Separate Query from Modifier! Create methods for query and for modification! When •  Method returning value modifies object state! Why •  Simplify interface!
  72. 72. Separate Query from Modifier! public  List<Employee>  FindRetired(List<Employee>  employees)  {      var  result  =  new  List<Employee>();      foreach(var  emp  in  employees)  {          if(emp.IsRetired)  {              AddBonus(emp);              result.Add(emp);          }      }      return  result;   }   public  List<Employee>  FindRetired(List<Employee>  employees)  {      return  employees.Where(emp  =>  emp.IsRetired).ToList();       }   public  void  AddBonusToRetired(List<Employee>  employees)  {      foreach(var  emp  in  employees)  {          if(emp.IsRetired)              AddBonus(emp);      }   }    
  73. 73. Preserve Whole Object! Send the whole object to the method! When •  Method has several object field values as params! Why •  Simplify interface! !
  74. 74. Preserve Whole Object! DateTime  start  =  Period.Start;   DateTime  end  =  Period.End;   List<Event>  events  =  schedule.FindEvents(start,  end);         List<Event>  events  =  schedule.FindEvents(Period);  
  75. 75. Introduce Parameter Object! Replace method parameters with an object! When •  Method accepts several related parameters! Why •  Simplify interface!
  76. 76. Introduce Parameter Object! Schedule +FindEvents(DateTime start, DateTime end) Schedule +FindEvents(Period period)
  77. 77. Replace Error Code with Exception! Throw exception instead of returning error code! When •  Method returns error code! Why •  Simplify interface!
  78. 78. Replace Error Code with Exception! int  Withdraw(int  amount)  {      if  (amount  >  _balance)  {          return  -­‐1;      }      else  {          _balance  -­‐=  amount;          return  0;      }   }   void  Withdraw(int  amount)  {      if  (amount  >  _balance)            throw  new  BalanceException();        _balance  -­‐=  amount;   }  
  79. 79. Replace Exception with Test! Put conditional instead of throwing exception! When •  Exception is used non-exceptional case! Why •  Improve code readability!
  80. 80. Replace Exception with Test! public  double  ValueForPeriod(int  periodIndex)  {      try  {          return  _values[periodIndex];      }      catch  (IndexOutOfRangeException  e)  {          return  0;      }   }   public  double  ValueForPeriod(int  periodIndex)  {      if  (periodIndex  >=  _values.length)      return  0;      return  _values[periodIndex];   }  
  81. 81. Generalization Refactorings! Pull Up and Push Down Method/Field. Replace Inheritance with Delegation. Extract Subclass/Superclass. !
  82. 82. Pull Up Field/Method! Move method/field into the superclass! When •  The same method/field is in several child classes! Why •  Remove duplication!
  83. 83. Pull Up Field/Method! Salesman +name Engineer +name Employee +name Salesman Engineer Employee
  84. 84. Push Down Field/Method! Move method/field into the subclass! When •  Superclass has method/field used only in one child! Why •  Simplify design!
  85. 85. Push Down Field/Method! Salesman +ComissionRate Engineer Employee +ComissionRate Salesman Engineer Employee
  86. 86. Extract Subclass! Create subclass for subset of features! When •  Subset of features used only in some instances! Why •  Improve code readability! !
  87. 87. Extract Subclass! Event +Start: DateTime +Duration: TimeSpan +Repeat: EventPeriodicity Event +Start: DateTime +Duration: TimeSpan PeriodicEvent +Repeat: EventPeriodicity
  88. 88. Extract Superclass! Create superclass and move common features! When •  Several classes have the same subset of features! Why •  Remove duplication! !
  89. 89. Extract Superclass! AccountTransaction +Change: decimal +Saldo: decimal +TradeDate: DateTime Transaction +Change: decimal +TradeDate: DateTime Order +Amount: int +Price: decimal +Change: decimal +Security: Security +TradeDate: DateTime AccountTransaction +Saldo: decimal Order +Amount: int +Price: decimal +Security: Security
  90. 90. Replace Inheritance with Delegation! Put superclass to a field and use delegation! When •  Unable to say “subclass is a superclass”! •  Subclass implements superclass interface partially! Why •  Simplify design! !
  91. 91. Replace Inheritance with Delegation! Array +Insert(T item) +IsEmpty() Stack +Push(T Item) +Pop(): T Array +Insert(T item) +IsEmpty() Stack +Push(T Item) +Pop(): T +IsEmpty() -array return _array.IsEmpty();
  92. 92. Architectural Refactorings! Tease Apart Hierarchies. Extract Hierarchy. Convert Procedural Design to Objects. Separate Domain from Presentation. !
  93. 93. Tease Apart Inheritance! Create two hierarchies using one another! When •  The inheritance hierarchy has two responsibilities! Why •  Simplify design! !
  94. 94. Tease Apart Inheritance! Security Bond Security BondAction SecurityOperation SellingDelivery 1 * DeliveredBondSoldAction Action
  95. 95. Extract Hierarchy! Create hierarchy with subclass per special case! When •  The single class overwhelmed with conditionals! Why •  Improve code readability! •  Improve architecture! !
  96. 96. Extract Hierarchy! Logger +SendEmail(message) +WriteToFile(message) +WriteToSystemLog(message) Logger SystemLogger FileLogger EmailLogger
  97. 97. Convert Procedural Design to Objects! Turn data into objects and behavior into methods! When •  The classes with long methods but without fields! •  The classes with fields but without methods! Why •  Improve code readability! •  Improve architecture! !
  98. 98. Convert Procedural Design to Objects! OrderCalculator +CalculatePrice(order) +CalculateTaxes(order) OrderOrderLine Order +Price() +Taxes() OrderLine +Price() +Taxes() 1 *
  99. 99. Separate Domain from Presentation ! Create domain logic classes separated from ui! When •  UI logic is mixed with domain logic! Why •  Improve code readability! •  Improve architecture! !
  100. 100. Separate Domain from Presentation! ClientPage (business logic embedded) ClientClientPage 1
  101. 101. Thank you!! Your questions, please!! ARTEM TABALIN!
  102. 102. References! •  Martin Fowler Refactoring! •  Robert C. Martin Clean Code! •  Steve McConnell Code Complete!!

×