Working with Legacy Code: Lessons in Practice

33
Working Effec-vely with Legacy Code Lessons in Prac-ce

Transcript of Working with Legacy Code: Lessons in Practice

Page 1: Working with Legacy Code: Lessons in Practice

Working  Effec-vely  with  Legacy  Code  

Lessons  in  Prac-ce  

Page 2: Working with Legacy Code: Lessons in Practice

The  Book  

by  Michael  C.  Feathers    

published  2004    

foreword  by            “Uncle  Bob”  Mar-n    

influenced  by            Mar-n  Fowler’s            Refactoring  

Page 3: Working with Legacy Code: Lessons in Practice

What  is  Legacy  Code?  

•  “difficult  to  change  code  that  I  don’t  understand”      •  “code  wriNen  a  long  -me  ago”      •  “code  that  somebody  else  wrote”  

Page 4: Working with Legacy Code: Lessons in Practice

Refactor   Add  Feature   Fix  Bug   Op4mize  Structure   Changes   Changes   Changes  New  Behavior   Changes  Exis-ng  Behavior   Changes  Resource  Usage   Changes  

because  SoTware  is  Never  Done  

Why  do  I  need  to  understand  the  code?  

Page 5: Working with Legacy Code: Lessons in Practice

What  is  Legacy  Code?  

“Code  Without  Tests”  

Page 6: Working with Legacy Code: Lessons in Practice

Two  Methods  of  SoTware  Development  

“Edit  and  Pray”  vs.  

“Cover  and  Modify”  which  brings  us  to…  

 

Page 7: Working with Legacy Code: Lessons in Practice

The  Legacy  Code  Dilemma  

“When  we  change  code,    we  should  have  tests  in  place.”  

 “To  put  tests  in  place,  

 we  oTen  have  to  change  code.”  (But  why?)  

Page 8: Working with Legacy Code: Lessons in Practice

Legacy  Code  Change  Algorithm  

1.  Iden-fy  Change  Point  

2.  Find  Test  Point  

3.  Break  Dependency  

4.  Write  Tests  

5.  Change  and  Refactor  

Page 9: Working with Legacy Code: Lessons in Practice

Seams  

 Exchangeable  Behavior  +  an  Enabling  Point.    Seams  let  you  subs7tute  one  behavior  for  another  by  edi-ng  only  at  the  enabling  point.    Seams  let  you  introduce  test  collaborators.  

Page 10: Working with Legacy Code: Lessons in Practice

Object  Seams  

Most  useful  type  of  seam  for  OOP.  Another  way  of  talking  about  polymorphism.  

Code  without  seam   Code  with  seam  

Page 11: Working with Legacy Code: Lessons in Practice

In  the  Wild  

instead  of  

No  Tests   ==    No  Up-­‐to-­‐Date  Documenta-on  

Page 12: Working with Legacy Code: Lessons in Practice

In  the  Wild  

Duplicate  Code  

Page 13: Working with Legacy Code: Lessons in Practice

In  the  Wild  

Long,  Procedural  Methods  

def generate_pdf

end

Page 14: Working with Legacy Code: Lessons in Practice

In  the  Wild  

Stateful  Programming  •  Keeping  Track  of  Flags  •  HTTP  Session  Abuse  

Page 15: Working with Legacy Code: Lessons in Practice

In  the  Wild  

Curse  of  MVC  •  Fat  Models,  Fat  Controllers  •  Overloaded  Responsibili-es  

Page 16: Working with Legacy Code: Lessons in Practice

So  Many  Problems  

Chapter  6:  “I  Don’t  Have  Much  Time  and  I  Have  to  Change  It”  

Chapter  8:  “It  Takes  Forever  to  Make  a  Change”  

Chapter  10:  “I  Can’t  Run  This  Method  in  a  Test”  

Chapter  16:  “I  Don’t  Understand  the  Code  Well  Enough  To  Change  It”  

Chapter  17:  “My  Applica-on  Has  No  Structure”  

Chapter  19:  “My  Project  Is  Not  Object  Oriented.  How  Do  I  Make  Safe  Changes?  

Chapter  20:  “This  Class  Is  Too  Big  and  I  Don’t  Want  It  to  Get  Any  Bigger”  

Page 17: Working with Legacy Code: Lessons in Practice

This  Class  is  Too  Big  

Methods  defined  on  Job:  

Page 18: Working with Legacy Code: Lessons in Practice

Single  Responsibility  Principle  

“Every  class  should  have  a  single  responsibility:      It  should  have  a  single  purpose  in  the  system,      and  there  should  be  only  one  reason  to  change  it.”  

Page 19: Working with Legacy Code: Lessons in Practice

Seeing  Responsibili-es  

Group  Methods  

Page 20: Working with Legacy Code: Lessons in Practice

Seeing  Responsibili-es  

Effect  Sketch:      Show  Internal  Rela-onships  

Page 21: Working with Legacy Code: Lessons in Practice

Seeing  Responsibili-es  

Primary  Responsibility    “Job  presents  damper  inspec-on  data  in  report  form.”    “Job  generates  files  of  reports.”    “Job  deletes  report  files.”    “Job  produces  graphs  of  damper  inspec-on  data.”    “Job  persists  and  retrieves  representa-ons  of  jobs  in  a  database.”    

Page 22: Working with Legacy Code: Lessons in Practice

Iden-fy  Change  Point  

We  want  to  refactor  Job  to  extract  Reporter.  

1.  Iden-fy  Change  Point  

2.  Find  Test  Point  

3.  Break  Dependency  

4.  Write  Tests  

5.  Change  and  Refactor  

Page 23: Working with Legacy Code: Lessons in Practice

Find  Test  Point  Intercep-on  Points    Higher  Level  Tes-ng  

–  don’t  have  to  break  dependencies  –  verifies  that  your  feature  actually  works  –  slow,  inconvenient  –  hard  to  automate  –  not  tes-ng  in  isola-on  

 Progressive  Strategy  

 

1.  Iden-fy  Change  Point  

2.  Find  Test  Point  

3.  Break  Dependency  

4.  Write  Tests  

5.  Change  and  Refactor  

Page 24: Working with Legacy Code: Lessons in Practice

Break  Dependencies  

Required  for  unit  tes-ng.  Less  necessary  for  higher-­‐level  tes-ng.  We’re  gonna  skip  it  (but  just  this  -me).    

1.  Iden-fy  Change  Point  

2.  Find  Test  Point  

3.  Break  Dependency  

4.  Write  Tests  

5.  Change  and  Refactor  

Page 25: Working with Legacy Code: Lessons in Practice

Write  Tests  

“Tes-ng”  in  the  Interac-ve  Console:  

1.  Iden-fy  Change  Point  

2.  Find  Test  Point  

3.  Break  Dependency  

4.  Write  Tests  

5.  Change  and  Refactor  

Page 26: Working with Legacy Code: Lessons in Practice

Change  and  Refactor  

This  was  harder  than  it  looks.  

1.  Iden-fy  Change  Point  

2.  Find  Test  Point  

3.  Break  Dependency  

4.  Write  Tests  

5.  Change  and  Refactor  

Page 27: Working with Legacy Code: Lessons in Practice

Refactored  Code  

Five  different  extracted  classes    

(plus          two        more)  

Page 28: Working with Legacy Code: Lessons in Practice

Extract  Class…Again  

   

Page 29: Working with Legacy Code: Lessons in Practice

BeNer  With  Seam?  We  can  add  a  seam  by  injec-ng  the  dependency  on  the  reporter.  

This  way,  we  can  test  in  isola-on  by  passing  in  a  FakeReporter.  

Unfortunately,  this  makes  our  produc-on  code  ugly:  

Page 30: Working with Legacy Code: Lessons in Practice

Seams  Everywhere  

Page 31: Working with Legacy Code: Lessons in Practice

Legacy  Code  Ain’t  So  Bad  

•  No  writer’s  block.  •  Learn  as  you  go.  •  Easy  scapegoat!  •  Unavoidable,  so  learn  to  love  it.  

Page 32: Working with Legacy Code: Lessons in Practice

Thanks  J  

Working  Effec7vely  with  Legacy  Code  

Michael  Feathers          Amar  Shah  @amar47shah  

Page 33: Working with Legacy Code: Lessons in Practice

because  SoTware  is  Never  Done  

Refactor  to  Remove  Demeter  Viola-on