Rewriting
 12-Year-Old Code

B3b2139e4f2c0eca4efe2379fcebc1c5?s=47 Anna Filina
February 25, 2016

Rewriting
 12-Year-Old Code

Did you ever have to maintain a 12-year-old application? Dead code and tables everywhere, static methods, database queries in between HTML tags and some pages still in PHP3. This presentation will lead you through a progressive rewrite from very old legacy to the latest shiny version of PHP. Learn how to automate legacy testing, how to seamlessly jump between the old and new parts, and how to overcome other challenges that arise from dealing with legacy.

B3b2139e4f2c0eca4efe2379fcebc1c5?s=128

Anna Filina

February 25, 2016
Tweet

Transcript

  1. foolab.ca | @foolabca Rewriting
 12-Year-Old Code ConFoo, Montreal - February

    25, 2016
  2. Anna Filina • Developer • Problem solver • Trainer •

    Advisor • FooLab + ConFoo 2
  3. You Inherited a
 10-Year-Old Codebase

  4. You Inherited a
 12-Year-Old Codebase

  5. You Inherited a
 15-Year-Old Codebase

  6. You Inherited a
 15-Year-Old Codebase Code Doesn't Age Like Wine

  7. The web was 600 pixels wide 7

  8. Feeling old yet? • Y2K bug • Google launched AdWords

    • There was no Twitter, no Facebook, no iTunes • Internet Explorer 5 • ICQ was starting to be cool • Rounded corners = status symbol 8
  9. Objectives • Reduce mistakes • Increase dev. speed • Reduce

    tech. debt • Avoid getting stuck • Increase confidence 9
  10. Code Smells

  11. Global functions include("functions.php"); MyClass::myMethod(); // namespaced function? 11

  12. False security $clean = htmlentities($_POST['input_field']); // use filter functions or

    a framework // use prepared statements 12
  13. What happened at order 20117? if ($order_id > 20117) {

    // use this sql } else { // use that sql } // weakness = time to refactor 13
  14. Average legacy code file • 3000-6000 lines of code. •

    Half of it is commented "in case we need it later". • Method length of 800 lines. • Abuse of helper classes. • Sometimes no classes at all. 14
  15. Complex call graph $instance = Model::getInstanceByCode($code); class Model { public

    static function getInstanceByCode($code) { //... $instances = Cache::getCache($cacheIndex); } } class Cache { public static function getCache($cacheIndex) { //... $cache = File::getFileContent($filePath); } } 15
  16. Codebase • 5,000 classes. • 20,000 methods. • 1,500,000 lines

    of code. 16
  17. Strategy • Make a strategy based on contraints • Full

    rewrite vs progressive ◦ By class ◦ By module ◦ By HTTP call • How to run code side-by-side ◦ Session sharing 17
  18. Before You Code

  19. Data can be lost, stuff can break • Backup: test

    restore • Staging environment: app versions, configs • Simulate deployments/upgrades • Automate tests before code changes • Make a risk assessment ◦ Don't be too optimistic ◦ Account for side-effects 19
  20. Refactoring Example

  21. PHP 3 to PHP 5.6 • HTML + PHP +

    SQL in same file • Includes all over the place • IFs that concatenate SQL • Previous rewrite attempt ◦ Failed, made things worse ◦ Folders of dead code ◦ Classes with static functions (no instances) 21
  22. Solution • Rewrite complex forms in Symfony ◦ mod_rewrite for

    concerned pages • Rewrite biggest module as OOP ◦ Design extraction ◦ Automated tests ◦ Flexible architecture 22
  23. Design Extraction

  24. Avoid code bias • Old code → design docs •

    Validate design docs ◦ Clarify business rules • Improve design ◦ Reduce tech. debt ◦ More flexible • Design docs → new code 24
  25. Code-Level Advice

  26. Infrastructure • Set up logging ◦ Monolog if PHP version

    allows ◦ file_put_contents if really old version • Set up testing ◦ Mocking static methods: Patchwork or equivalent ◦ Cache API call output 26
  27. Code duplication • Sometimes, the bug is repeated 80+ times

    • Remove duplications ASAP 27
  28. Fix long methods • Extract broken part into its own

    method • Write unit tests for it • Fix it • Call it from the mega-method 28
  29. More Stories

  30. ASP Classic to PHP 5.6 • 15+ spaghetti and hacks

    • Language no longer supported • Huge ERP with lots of code 30
  31. Solution • Symfony to rewrite page by page • mod_rewrite

    for concerned pages • DB session adapter in both apps • Page in any language = HTTP request ◦ Guzzle tests FTW! 31
  32. Guzzle tests 32

  33. PHP 5.3 to PHP 5.6 • 12+ spaghetti and hacks

    • Uses deprecated functions • Can't run on PHP 5.6 33
  34. Solution • Split servers into 5.3 and 5.6 for fresh

    start • REST and modern design patterns • AngularJS frontend 34
  35. Splitting the app 35

  36. Alias is your friend (5.3 server) Alias "/module-name" "/var/www/project/angular" <Directory

    "/var/www/project/angular"> RewriteBase /module-name/ </Directory> 36
  37. Stuck?

  38. Try something new • Bounce ideas ◦ New people to

    avoid tunnel vision • Has this been done before? • Can I try another approach? 38
  39. Ask refactoring experts • Pick their brain • Read their

    blog • Hire one for a day ◦ Refactoring strategy ◦ Remove roadblocks ◦ Guidance (one day per week to steer in right direction) 39
  40. Takeaways • Plan before you act • Use known tools

    & methodologies • Get inspiration from others • Refactoring gets easier • Every problem has a solution 40
  41. Anna Filina • Development. • Fix bugs & performance issues.

    • Workshops on testing, Symfony & API. • Advisor on testing strategy, legacy code. 41
  42. @afilina afilina.com