Advertisement
Advertisement

More Related Content

Advertisement
Advertisement

Living With Legacy Code

  1. ving Li with Legacy Code
  2. @rowan_m
  3. @rowan_m Plusnet Ibuildings
  4. What is “Legacy Code”?
  5. What is “Legacy Code”? Code without tests Code you've “inherited” Code no-one understands Technical debt
  6. Who has never created Legacy Code?
  7. My own little story
  8. Pragmatic, not ideal istic My own little story
  9. Starting a project
  10. Aim to understand the concepts and motivations
  11. Try using the application
  12. Find and then read any / all documentation
  13. Official: Che Project brief ( ) c kli Requirements ( ) st Tech. Spec. ( ) Actual: Emails ( ) Meeting notes ( ) Progress: Gant charts ( ) Burndowns ( ) Overtime logs ( ) Quality: Bug tracker ( ) Complaints ( ) User Forums ( )
  14. Talk to the original developers
  15. Talk to the users … especially the “different” ones
  16. Approaching the code
  17. Catalogue the live platform & environment
  18. Recreate it!
  19. Deploy the code
  20. PHP: Che php.ini ( ) c kli PEAR / PECL modules ( ) st Compile options ( ) Patches ( ) The Rest: OS ( ) Package manager ( ) Web server ( ) Web server modules ( ) Site config. ( ) Database ( ) Cache ( ) JS libraries ( ) Firewall rules ( ) Proxies ( ) Services running ( )
  21. Time to enter The Code
  22. Time to enter The Code Reading Static analysis Dynamic analysis
  23. http://www.phpdoc.org/ doc php Title phpdoc -ti 'Sweet Application' -pp -o HTML:Smarty:PHP -d Libraries Style -t Docs Code in here Docs out here!
  24. Beware of type-hiding! Type-hinting /** * @param array $opts Current options * @return array Options with flag set */ function setFlag(array $opts) { $opts['flag'] = true; return $opts; } Type-hiding /** * @param int $fullPence Full price in pence * @return float Discounted price in pence */ function applyDiscount($fullPence) { return ($fullPence * 0.8); }
  25. ygen dox doxygen -s -g ~/doxy.conf vim ~/doxy.conf # edit at least this Code in here OUPUT_DIRECTORY # play with the rest cd ~/dev/project Docs out here doxygen ~/doxy.conf http://www.stack.nl/~dimitri/doxygen/
  26. http://ctags.sourceforge.net/ ta gs c Code in here #!/bin/bash Tags out here cd ~/Dev/ && ctags-exuberant -f ~/.vimtags -h ".php" -R --exclude=".git" --links=no --totals=yes --tag-relative=yes --PHP-kinds=+cf --regex-PHP='/abstracts+classs+([^ ]+)/1/c/' --regex-PHP='/interfaces+([^ ]+)/1/c/' --regex-PHP='/(publics+|statics+|abstracts+|protecteds+|privates+) ↵ functions+&?s*([^ (]+)/2/f/' Voodoo
  27. ml http://www.bouml.fr/ bou
  28. ml http://bouml.free.fr/ bou
  29. ml http://bouml.free.fr/ bou
  30. ml http://bouml.free.fr/ bou
  31. ml http://bouml.free.fr/ bou
  32. ml http://bouml.free.fr/ bou
  33. ou ml b
  34. ffer esni co d rowan@swordbean:~/Dev/ZendFramework-1.9.4/library/Zend/Service$ phpcs --standard=Zend Exception.php FILE: /home/rowan/Dev/ZendFramework-1.9.4/library/Zend/Service/Exception.php -------------------------------------------------------------------------------- FOUND 1 ERROR(S) AND 2 WARNING(S) AFFECTING 3 LINE(S) -------------------------------------------------------------------------------- 17 | WARNING | Line exceeds 80 characters; contains 87 characters 32 | WARNING | Line exceeds 80 characters; contains 87 characters 36 | ERROR | Opening class brace must be on a line by itself 36 | ERROR | Closing brace must be on a line by itself -------------------------------------------------------------------------------- http://pear.php.net/package/PHP_CodeSniffer/
  35. t in uous Con io n Inte grat http://jenkins-ci.org/ http://phpundercontrol.org/ http://sismo.sensiolabs.org/
  36. Decisi on tim e!
  37. Decisi on tim e! Ign cod ore e a it , nyw ay a cto r, ref est ite, st, t Rewr , te test
  38. Ignore it, code anyway
  39. Ignore it, code anyway Please don't.
  40. Ignore it, code anyway Please don't. however...
  41. Deadlines, clients, money, etc.
  42. Deadlines, clients, money, etc. Make everyone aware of the risks Secure a follow-up project
  43. Why do you need the code?
  44. Why do you need the code? simple Library dependency Adding new behaviour Changing behaviour complex
  45. Isolate legacy dependencies
  46. Isolate legacy dependencies Create an anti-corruption layer
  47. Complete isolation Create a legacy service
  48. Partial isolation Wrapper classes or methods
  49. Wrapper class <?php include('/home/victorvon/secrets.inc'); /** * @param array $person willing volunteer */ function extract_brain(&$person) { $brain = $person['brain']; unset($person['brain']); } return $brain; Some code /** you need * @param array $person * @return bool living or not :( */ function create_life($person) { require_once(LIB_DIR.'../nuts_n_bolts.inc'); kerzap(); $person['living'] = true; return $person; } ?>
  50. class VictorWrapper { Wrapper class public function __construct() { require_once '/home/victorvon/tragedy.php'; } public function extractBrain(Person $p) { // format to legacy style $pLgcy = $this->toArray($p); // run legacy code $bLgy = extract_brain($pLgcy); // format to new style $p = $this->toPerson($pLgcy); Some code $b = $this->toBrain($bLgcy); return array($p, $b); you can use } :) public function createLife(Person $p) { // validate if ($person->isAlive()) throw new LivingException(); // format to legacy style $pLgcy = $this->toArray($p); // run legacy code $pLgy = create_life($pLgcy); // format to new style return $this->toPerson($pLgcy); } }
  51. Changing the code
  52. Changing the code Take an incremental approach Commit to 1 day at a time
  53. Why? Difficult to estimate Hidden dependencies Unknown behaviour
  54. 1. Get it into version control
  55. 2. Identify the inflection point
  56. 3. Create integration & acceptance tests
  57. 4. Set up your continuous integration environment
  58. 5. Rewrite and refactor!
  59. Types of changes
  60. Mixed → Procedural
  61. includes HTML PHP HTML HTML PHP HTML PHP HTML PHP PHP HTML PHP HTML HTML PHP HTML PHP
  62. includes function function function includes HTML PHP HTML HTML echo HTML HTML PHP HTML HTML echo HTML PHP HTML PHP if HTML if PHP foreach HTML PHP HTML HTML echo HTML HTML PHP HTML HTML echo HTML PHP foreach
  63. Procedural → OO
  64. includes function function function function free code
  65. includes includes function static method function static method function static method function static method free code static method
  66. includes includes includes function static method constructor function static method method function static method method function static method method free code static method method
  67. Sprout method / class
  68. public function createInvoice(Account $acc, array $charges) { $invoice = new Invoice(); foreach ($charges as $chg) { $invoice->addLine($chg->getDesc(), $chg->getAmount()); } return $invoice; } The existing code “We just need to be able to give each client their own personal discount on certain charges.”
  69. public function createInvoice(Account $acc, array $charges) { $invoice = new Invoice(); foreach ($charges as $chg) { $invoice->addLine($chg->getDesc(), $chg->getAmount()); } return $invoice; } The new code private function calcDiscount(Account $acc, Charge $chg) { $accDisc = new AccountDiscounter($acc); $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; }
  70. public function createInvoice(Account $acc, array $charges) { $invoice = new Invoice(); Call it foreach ($charges as $chg) { // Sprout new behaviour! $chg = $this->calcDiscount($acc, $chg); $invoice->addLine($chg->getDesc(), $chg->getAmount()); } return $invoice; } private function calcDiscount(Account $acc, Charge $chg) { $accDisc = new AccountDiscounter($acc); $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; }
  71. Untestable OO → testable OO
  72. Dependency Inversion / Extraction
  73. The Problem public function calcDiscount(Account $acc, Charge $chg) { $accDisc = new AccountDiscounter($acc); $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; } Untestable!
  74. The Problem public function calcDiscount(Account $acc, Charge $chg) { $accDisc = new AccountDiscounter($acc); $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; } Untestable! class AccountDiscounter { public function __construct(Account $acc) { // check cache // contact the database // call a web service } }
  75. Quick Solution public function calcDiscount(Account $acc, Charge $chg) { $accDisc = $this->getAccountDiscounter($acc); $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; } Mock object in your test Override method protected function getAccountDiscounter(Account $acc) { return new AccountDiscounter($acc); }
  76. Dependency Injection Solution public function __construct(AccountDiscounter $ad) { $this->discounter = $ad; } Pass it into the class public function calcDiscount(Account $acc, Charge $chg) { $accDisc = $this->discounter; $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; }
  77. (v2) → Dependency Injection Solution public function __construct(IAccountDiscounter $ad) { $this->discounter = $ad; } Make an interface public function calcDiscount(Account $acc, Charge $chg) { $accDisc = $this->discounter; $discountedCharge = $accDisc->calculate($chg); return $discountedCharge; }
  78. Summary Analyse Plan Test IsolatE Change Test MORE
  79. Any questions? Feedback to: https://joind.in/6020 @rowan_m
  80. Further reading: Michael Feathers Martin Fowler http://www.flickr.com/photos/flatlinevision/1514971535/ http://commons.wikimedia.org/wiki/File:Weird_Tales_November_1950.jpg http://commons.wikimedia.org/wiki/File:AdventuresIntoDarkness1401.jpg http://www.flickr.com/photos/locationscout/3594432797/ http://www.flickr.com/photos/rawhead/3466304669/ http://commons.wikimedia.org/wiki/File:Rocket_to_the_Moon_54893.jpg http://commons.wikimedia.org/wiki/File:Weird_Chills_July.jpg http://commons.wikimedia.org/wiki/File:Terrific_01.jpg http://commons.wikimedia.org/wiki/File:Strange_Fantasy_01.jpg http://commons.wikimedia.org/wiki/File:Beware_01.JPG http://www.flickr.com/photos/erokcom/2873449983/ http://www.flickr.com/photos/locationscout/3594433235/ http://commons.wikimedia.org/wiki/File:Weird_Chills_Sept.JPG http://commons.wikimedia.org/wiki/File:Weird_Comics_01.JPG http://www.flickr.com/photos/x-ray_delta_one/3972988193/ http://commons.wikimedia.org/wiki/File:Weird_Tales_January_1950.jpg ts di http://commons.wikimedia.org/wiki/File:Plan_nine_from_outer_space.jpg http://www.flickr.com/photos/javyer/3545217741/ http://www.flickr.com/photos/76074333@N00/318034222/ http://commons.wikimedia.org/wiki/File:Dime_Mystery_Magazine_July_1934.jpg http://www.flickr.com/photos/quinnanya/3802177022/ C re
Advertisement