step-by-step
This is not a work of fiction. 
Design Flaws and Bugs are neither the product of the author's imagination nor 
used fictitiously. 
Any resemblance to real legacy projects is entirely non coincidental.
Uses many attributes from external classes 
Is excessively large and complex 
Is very non-cohesive
Data and behavior that acts on that data belong together. When a method makes 
too many calls to other classes to obtain data or functionality, Feature Envy is in 
the air. 
4 methods are affected by this design flaw
All methods are envy on Policy Details Extended form datas
This is a Context Object and its role is to encapsulate state in a protocol 
independent way. 
This Design Flow doesn't harm the application and can be ignored 
POST /path/policy.do HTTP/1.0 
User-Agent: HTTPTool/1.0 
Content-Type: application/x-www-form-urlencoded 
Content-Length: 532 
policyType=1&eCommerceSys=153 
SubBrokers DelegatedAuthorities ... 
PolicyDetailsForm 
PolicyDetailsExtendedForm 
- policyState 
- policyTypeId 
- billCoding 
- manualAdjustable 
- referringAgent 
- ... 
Categories eCommerceSystems Underwriters
This is the MAJOR design flow found in this class. The Long Methods with very 
high cyclomatic complexity make the code hard to understand, maintain and test. 
105 + 98 + 76 + 30 + 11 + 10 + 10 + … = 350 ~ 400
1. Orchestrates Business Services (3) 
«ApplicationController» 
RequestProcessor 
«Command» 
Action 
«PresentationModel» 
ActionForm 
«POJO» 
BusinessService 
«JSP» 
View 
View Helper 
«Domain Model» 
Policy 
adapt 
use 
0..* 
manage 
access 
1..* 
populate 
invoke 
dispatch 
creates 1 
2 3 
4 
5 
6 
7 
POST /path/policy.do HTTP/1.0 
User-Agent: HTTPTool/1.0 
policyType=1&transType=newPolicy
2. Provides Presentation Model initialization - policy type specific business rules are 
applied - New Policy, Init
3. Provides Presentation Model validation - policy type specific business rules are 
applied - Save, Decline Quote, New Coverage, Apply 
SubBrokers DelegatedAuthorities ... 
PolicyDetailsForm 
PolicyDetailsExtendedForm 
- policyState 
- policyTypeId 
- billCoding 
- manualAdjustable 
- referringAgent 
- ... 
Categories eCommerceSystems Underwriters
4. Populates the Domain Model using the values provided by Presentation Model – 
some values are copied others are derived using policy type specific business rules - 
Save, Decline Quote, New Coverage, Set WIP Data , Apply
60 
50 
40 
30 
20 
10 
0 
PolicyDetailsExtendedAction 
number of commits per year 
commits 
2008 2009 2010 2011 2012 2013 2014
Refactoring is the process of changing a software system in such a way that it does 
not alter the external behavior of the code yet improves its internal structure.
4 Rules to keep in mind when refactoring code: 
 It passes ALL the tests (preserve its external behavior) 
 It minimizes duplication in all its forms 
 It expresses its intent clearly to the reader 
 It removes unnecessary element
It passes ALL the tests (preserve its external behavior) 
0,0% 7.631 
Number of execution paths 
• One unit test case in 3 minutes 
• One man day (6 hours) = 120 branches covered per day 
• 7631 / 120 ~ 64 days 
• 5 day per week = 13 weeks 
TOTAL: 3+ months
It allows for quick production of reliable non regression tests to facilitate code 
refactoring.
 Generate enough pseudo-random data 
 Use a code coverage data
if (PolicyTypes.isUKPolicyType(policy.getPolicyTypeId().intValue()) 
|| _form.getStatus() == Status.RENEWING) { 
if (_form.getWinsArpCode().equals("Y")) { 
policy.setBookedStatus(BookingStatus.ELIGIBLE_FOR_AUTOBOOKING_HELD); 
} else if (_form.getWinsArpCode().equals("C")) { 
policy.setBookedStatus(BookingStatus.FORCED_INVITE); 
} else if (_form.getWinsArpCode().equals("E")) { 
policy.setBookedStatus(BookingStatus.ELIGIBLE_FOR_AUTOBOOKING); 
} 
} 
1 
1 {UK/Travel=1, IT/Travel=7} 
2 
2 {RENEWING=W,NEW=N} 
3 
3 {Y,C,E}
1 7 
Y Y Y Y C C C C E E E E 
T 
ValuesGenerator 
+ ValuesGenerator(List<T>) 
+ getNextValue() : T 
PolicyTypeGenerator 
+ getNextValue() : int 
FormStatusGenerator 
+ getNextValue() : char 
1 
FormWinsArpCodeGenerator 
+ getNextValue() : String 
W W N N 
2 
3 
1 7 1 7 1 7 1 7 1 7 1 7 
W W N N W W N N W W N N 
Y Y Y Y C C C C E E E E 
12
Find a way to capture the output of the system without changing the production 
code 
Direct output 
 HttpSession (Domain Model) 
 Presentation Model 
 HttpRequest 
 Computed ActionForward 
 Thrown Exceptions 
Indirect output 
 Errors sent by email to operation team
 Use a non intrusive solution - the existing code should not be modified 
 Non Serializable objects must be serialized too 
 Persist the output into a human readable format 
 Provide a mechanism to omit some fields 
Current date/time populated somewhere by one of the SUT indirect colaborators 
Error stack 
serializer.registerOmitField(Policy.class, “creationDate"); 
serializer.registerOmitField(Policy.class, "lastModifiedDate"); 
serializer.registerOmitField(Throwable.class, "stackTrace"); 
framework: XStream
Number of execution paths 
98,0%
Missing return statement 
zoneReferred value is computed but not used – always returns 0 b.c.
Dead Code 
the second branch is unreachable because the 
generateDynamicList variable is hardcoded to true
Unnecessary null check 
if the address is null, a new address is 
created on the fly.
Policy Type is used to implement business rules variations for all 3 responsibilities: 
 initialize 
 validate 
 save 
32 
Accident / Travel ITA 2010
Method body Method body Common to ALL 
COUNTRY specific 
YEAR / TYPE specific 
> 1k
Common to ALL 
Policies 
Common to a 
specific COUNTRY 
Specific by YEAR / 
TYPE 
ALL 
IT 
2010/Travel 2012/Travel 
UK 
2010/Accident 
RESPONSIBILITIES 
I 
N 
I 
T 
I 
A 
L 
I 
Z 
E 
V 
A 
L 
I 
D 
A 
T 
E 
S 
A 
V 
E
 Single Responsibility Principle 
 Open for Extension Close for Modification 
 Group together things that change together
InitializationRulesFactory 
+ getRulesForPolicyType() : InitializationRules 
asks 
provides 
PolicyAction 
# initialize() : void 
# validate() : void 
«interface» 
InitializationRules 
use 
+ initialize() : void 
CommonInitializationRules 
+ initialize() : void 
DEUInitializationRules 
+ initialize() : void 
UKInitializationRules 
+ initialize() : void 
UK2012InitializationRules 
+ initialize() : void 
ValidationRulesFactory 
+ getRulesForPolicyType() : ValidationRules 
«interface» 
ValidationRules 
+ validate() : void 
CommonValidationRules 
+ validate() : void 
UKValidationRules 
+ validate() : void 
DEUValidationRules 
+ validate() : void 
UK2012ValidationRules 
+ validate() : void 
UK2014ValidationRules 
+ validate() : void 
use 
asks 
provides
red 
green 
refactor 
commit 
green 
revert
A. Extract ALL initialization rules into a new Class 
The refactoring steps are depicted below 
 Use Extract Class and create a new class to express the split-off responsibilities 
 Use Move Field on each relevant field 
 Use Move Method to move method over from old class to new one 
 Use Replace constructor with Factory Method and create a new dedicated class 
responsible to provide the right subclass of InitializePolicyFormService based on 
Policy Type. In this way we separate the instantiation responsibility from 
initialization responsibility.
B. Extract NDL specific initialization rules into a new Subclass that extends the 
Class created above 
The refactoring steps are depicted below 
 Use Extract Subclass and define a new subclass that hosts the specific NDL 
initialization rules 
 Use Push Down Method on methods specific to NDL. 
 Copy methods that contains conditional logic specific to NDL and simplify the 
method preserving only the conditional leg relevant for NDL context. Make the 
original method protected 
 Update the Factory Class to return this subclass if Policy Type belongs to NDL
C. Refactor the Factory Method 
 Use Replace conditional dispatcher with Command 
D. Repeat steps (B) and (C) for each Country / Year / Policy Type.
Refactoring Improves the Design of Software 
 Without refactoring, the design of the program will decay (people change code to 
realize short-term goals without a full comprehension of the design) 
 Loss of the structure of code has a cumulative effect (the harder it is to see the 
design in the code, the harder it is to preserve it)
Books 
 http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672 
 http://www.amazon.com/Refactoring-Patterns-Joshua-Kerievsky/dp/0321213351 
Articles 
 http://java.dzone.com/articles/testing-legacy-code-golden 
 http://blog.adrianbolboaca.ro/2014/05/legacy-coderetreat-golden-master/ 
 http://martinsson-johan.blogspot.fr/2014/01/golden-master-and-legacy-few-insights.html 
Tools 
 http://approvaltests.sourceforge.net/ 
 http://xstream.codehaus.org/

Refactoring legacy code: step-by-step examples

  • 1.
  • 2.
    This is nota work of fiction. Design Flaws and Bugs are neither the product of the author's imagination nor used fictitiously. Any resemblance to real legacy projects is entirely non coincidental.
  • 8.
    Uses many attributesfrom external classes Is excessively large and complex Is very non-cohesive
  • 9.
    Data and behaviorthat acts on that data belong together. When a method makes too many calls to other classes to obtain data or functionality, Feature Envy is in the air. 4 methods are affected by this design flaw
  • 10.
    All methods areenvy on Policy Details Extended form datas
  • 11.
    This is aContext Object and its role is to encapsulate state in a protocol independent way. This Design Flow doesn't harm the application and can be ignored POST /path/policy.do HTTP/1.0 User-Agent: HTTPTool/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 532 policyType=1&eCommerceSys=153 SubBrokers DelegatedAuthorities ... PolicyDetailsForm PolicyDetailsExtendedForm - policyState - policyTypeId - billCoding - manualAdjustable - referringAgent - ... Categories eCommerceSystems Underwriters
  • 12.
    This is theMAJOR design flow found in this class. The Long Methods with very high cyclomatic complexity make the code hard to understand, maintain and test. 105 + 98 + 76 + 30 + 11 + 10 + 10 + … = 350 ~ 400
  • 14.
    1. Orchestrates BusinessServices (3) «ApplicationController» RequestProcessor «Command» Action «PresentationModel» ActionForm «POJO» BusinessService «JSP» View View Helper «Domain Model» Policy adapt use 0..* manage access 1..* populate invoke dispatch creates 1 2 3 4 5 6 7 POST /path/policy.do HTTP/1.0 User-Agent: HTTPTool/1.0 policyType=1&transType=newPolicy
  • 15.
    2. Provides PresentationModel initialization - policy type specific business rules are applied - New Policy, Init
  • 16.
    3. Provides PresentationModel validation - policy type specific business rules are applied - Save, Decline Quote, New Coverage, Apply SubBrokers DelegatedAuthorities ... PolicyDetailsForm PolicyDetailsExtendedForm - policyState - policyTypeId - billCoding - manualAdjustable - referringAgent - ... Categories eCommerceSystems Underwriters
  • 17.
    4. Populates theDomain Model using the values provided by Presentation Model – some values are copied others are derived using policy type specific business rules - Save, Decline Quote, New Coverage, Set WIP Data , Apply
  • 18.
    60 50 40 30 20 10 0 PolicyDetailsExtendedAction number of commits per year commits 2008 2009 2010 2011 2012 2013 2014
  • 19.
    Refactoring is theprocess of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.
  • 20.
    4 Rules tokeep in mind when refactoring code:  It passes ALL the tests (preserve its external behavior)  It minimizes duplication in all its forms  It expresses its intent clearly to the reader  It removes unnecessary element
  • 21.
    It passes ALLthe tests (preserve its external behavior) 0,0% 7.631 Number of execution paths • One unit test case in 3 minutes • One man day (6 hours) = 120 branches covered per day • 7631 / 120 ~ 64 days • 5 day per week = 13 weeks TOTAL: 3+ months
  • 22.
    It allows forquick production of reliable non regression tests to facilitate code refactoring.
  • 23.
     Generate enoughpseudo-random data  Use a code coverage data
  • 24.
    if (PolicyTypes.isUKPolicyType(policy.getPolicyTypeId().intValue()) ||_form.getStatus() == Status.RENEWING) { if (_form.getWinsArpCode().equals("Y")) { policy.setBookedStatus(BookingStatus.ELIGIBLE_FOR_AUTOBOOKING_HELD); } else if (_form.getWinsArpCode().equals("C")) { policy.setBookedStatus(BookingStatus.FORCED_INVITE); } else if (_form.getWinsArpCode().equals("E")) { policy.setBookedStatus(BookingStatus.ELIGIBLE_FOR_AUTOBOOKING); } } 1 1 {UK/Travel=1, IT/Travel=7} 2 2 {RENEWING=W,NEW=N} 3 3 {Y,C,E}
  • 25.
    1 7 YY Y Y C C C C E E E E T ValuesGenerator + ValuesGenerator(List<T>) + getNextValue() : T PolicyTypeGenerator + getNextValue() : int FormStatusGenerator + getNextValue() : char 1 FormWinsArpCodeGenerator + getNextValue() : String W W N N 2 3 1 7 1 7 1 7 1 7 1 7 1 7 W W N N W W N N W W N N Y Y Y Y C C C C E E E E 12
  • 26.
    Find a wayto capture the output of the system without changing the production code Direct output  HttpSession (Domain Model)  Presentation Model  HttpRequest  Computed ActionForward  Thrown Exceptions Indirect output  Errors sent by email to operation team
  • 27.
     Use anon intrusive solution - the existing code should not be modified  Non Serializable objects must be serialized too  Persist the output into a human readable format  Provide a mechanism to omit some fields Current date/time populated somewhere by one of the SUT indirect colaborators Error stack serializer.registerOmitField(Policy.class, “creationDate"); serializer.registerOmitField(Policy.class, "lastModifiedDate"); serializer.registerOmitField(Throwable.class, "stackTrace"); framework: XStream
  • 28.
  • 29.
    Missing return statement zoneReferred value is computed but not used – always returns 0 b.c.
  • 30.
    Dead Code thesecond branch is unreachable because the generateDynamicList variable is hardcoded to true
  • 31.
    Unnecessary null check if the address is null, a new address is created on the fly.
  • 32.
    Policy Type isused to implement business rules variations for all 3 responsibilities:  initialize  validate  save 32 Accident / Travel ITA 2010
  • 33.
    Method body Methodbody Common to ALL COUNTRY specific YEAR / TYPE specific > 1k
  • 34.
    Common to ALL Policies Common to a specific COUNTRY Specific by YEAR / TYPE ALL IT 2010/Travel 2012/Travel UK 2010/Accident RESPONSIBILITIES I N I T I A L I Z E V A L I D A T E S A V E
  • 35.
     Single ResponsibilityPrinciple  Open for Extension Close for Modification  Group together things that change together
  • 36.
    InitializationRulesFactory + getRulesForPolicyType(): InitializationRules asks provides PolicyAction # initialize() : void # validate() : void «interface» InitializationRules use + initialize() : void CommonInitializationRules + initialize() : void DEUInitializationRules + initialize() : void UKInitializationRules + initialize() : void UK2012InitializationRules + initialize() : void ValidationRulesFactory + getRulesForPolicyType() : ValidationRules «interface» ValidationRules + validate() : void CommonValidationRules + validate() : void UKValidationRules + validate() : void DEUValidationRules + validate() : void UK2012ValidationRules + validate() : void UK2014ValidationRules + validate() : void use asks provides
  • 37.
    red green refactor commit green revert
  • 38.
    A. Extract ALLinitialization rules into a new Class The refactoring steps are depicted below  Use Extract Class and create a new class to express the split-off responsibilities  Use Move Field on each relevant field  Use Move Method to move method over from old class to new one  Use Replace constructor with Factory Method and create a new dedicated class responsible to provide the right subclass of InitializePolicyFormService based on Policy Type. In this way we separate the instantiation responsibility from initialization responsibility.
  • 39.
    B. Extract NDLspecific initialization rules into a new Subclass that extends the Class created above The refactoring steps are depicted below  Use Extract Subclass and define a new subclass that hosts the specific NDL initialization rules  Use Push Down Method on methods specific to NDL.  Copy methods that contains conditional logic specific to NDL and simplify the method preserving only the conditional leg relevant for NDL context. Make the original method protected  Update the Factory Class to return this subclass if Policy Type belongs to NDL
  • 40.
    C. Refactor theFactory Method  Use Replace conditional dispatcher with Command D. Repeat steps (B) and (C) for each Country / Year / Policy Type.
  • 41.
    Refactoring Improves theDesign of Software  Without refactoring, the design of the program will decay (people change code to realize short-term goals without a full comprehension of the design)  Loss of the structure of code has a cumulative effect (the harder it is to see the design in the code, the harder it is to preserve it)
  • 44.
    Books  http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672  http://www.amazon.com/Refactoring-Patterns-Joshua-Kerievsky/dp/0321213351 Articles  http://java.dzone.com/articles/testing-legacy-code-golden  http://blog.adrianbolboaca.ro/2014/05/legacy-coderetreat-golden-master/  http://martinsson-johan.blogspot.fr/2014/01/golden-master-and-legacy-few-insights.html Tools  http://approvaltests.sourceforge.net/  http://xstream.codehaus.org/

Editor's Notes

  • #42 Emergent design – create an initial design and then extend the design as we learn more
  • #43 Emergent design – create an initial design and then extend the design as we learn more
  • #44 Emergent design – create an initial design and then extend the design as we learn more