Rewriting Legacy Code

Rewriting Legacy Code


Did you ever have to maintain a 20-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 pick the right rewrite strategy, and how to overcome other challenges that arise from dealing with legacy.


Anna Filina

May 13, 2020


  1. <animés par la passion> Rewriting Legacy Code THE LEGACY OF

    SOCRATES | MAY 13, 2020 @afilina
  2. Anna Filina ‣ Coding since 1997. ‣ Legacy archaeology. ‣

    Test automation. ‣ Talks and workshops. ‣ YouTube videos.
  3. You Inherited a
 10-Year-Old Codebase

  4. You Inherited a
 15-Year-Old Codebase

  5. You Inherited a
 20-Year-Old Codebase

  6. None
  7. Web in 2000 ‣ Y2K bug. ‣ Internet Explorer 5.

    ‣ ICQ was starting to be cool. ‣ Background music. ‣ Rounded corners = status symbol.
  8. Legacy Sadness

  9. The Methods ‣ Can easily exceed a thousand lines. ‣

    Mixing SQL, PHP and HTML. ‣ Receiving dozens of arguments of arbitrary type. ‣ Accessing hundreds of potentially undefined properties. ‣ Expect properties to have been set by a child 10 method calls ago. ‣ methodName_new, methodName_new2
  10. The Dynamic Types ‣ Null pointer exceptions of every flavor.

    ‣ Attempting to split an array. ‣ Attempting to divide by a null. ‣ Attempting to count the number of elements in a float. ‣ Attempting to max($array1, $array2),
 where array items are of mixed types.
  11. How to Fail a Rewrite

  12. Microservices AWS GitHub React CircleCI ElasticSearch Ansible Docker Symfony Ambitious

    new tech stack
  13. Other Ambitions ‣ SOLID. ‣ Test-driven development. ‣ Strong typing.

    Too many new things at once
  14. Expanding Scope ‣ Rethinking existing features. ‣ New features. ‣

    New work methodology.
  15. Start With the Strategy

  16. Strategy ‣ Version upgrade. ‣ New framework. ‣ Progressive rewrite.

    ‣ Refactoring only. ‣ Full rewrite.
  17. Version Upgrade ‣ PHPCodeSniffer can detect incompatibilities. ‣ Some libs

    might be easier to swap than to fix (PHPExcel). ‣ Regexes are your friends. ‣ Rector can automatically refactor. ‣ Need to freeze development.
  18. None
  19. New Framework ‣ Use dependency injection. ‣ Automate large chunks

    with Rector. ‣ Use adapters. ‣ Need to freeze development.
  20. Product/IndexHandler ProductController indexAction viewAction Product/ViewHandler Routes Routes Product/BaseHandler Example: Zend

    Framework 1 to Zend Expressive
  21. class IndexHandler extends BaseHandler implements RequestHandlerInterface { public function __construct(

    TemplateRendererInterface $template, ProductModel $productModel ) { //... } public function handle(ServerRequestInterface $request): ResponseInterface { return new HtmlResponse(
 $this->template->render('admin::product/index', $view)
 ); } }
  22. Progressive Rewrite ‣ By class. ‣ By module • Can

    switch language. • Use design extraction.
  23. Old Code New Design Old Design New Code

  24. ‣ Some criteria for refactoring: • Need to change. •

    Hard to understand, but need to work with it. Refactoring Only
  25. Full Rewrite ‣ Discouraged. ‣ My criteria: • Can disregard

    existing features. • Few or no integrations. • Can trash old database. • If not, need a team experienced in full rewrites.
  26. Spot Problems Early ‣ PHPStorm inspections. ‣ Pslam: start with

    auto-detected level.
  27. Unknown Unknowns

  28. Docs ‣ No docs. ‣ Too many, little relevance. ‣

    Outdated or misleading.
  29. Tests ‣ No tests. ‣ Not runnable. ‣ Failing. ‣

    Brittle: specific environment or inter-dependencies. ‣ Unreliable.
  30. Dead Code ‣ Unused endpoints. ‣ Commented-out code. ‣ Unused

    classes or methods: exercise extreme caution. ‣ Merge duplicated code (bug repeated 80 times).
  31. Testing Approaches

  32. Version Upgrade Smoke tests Fix code Should work
 for old

    and new versions. Unit tests
  33. New Framework Smoke tests Migrate Should work
 for old and

    new versions. Unit tests
  34. Progressive Rewrite For new code only. Acceptance tests Unit tests

    Should work
 for old and new versions. New code
  35. Refactoring Only For the code that you want to write.

    Acceptance tests Unit tests Should work
 for old and new versions. Refactor
  36. Preparing the Environments

  37. Local Environment ‣ Docker. ‣ Baseline image. ‣ Migration image.

    ‣ Match server / vagrant.
  38. services: php: //... mysql: //... acceptance: //... mysql_test: //...

  39. Gotchas ‣ Pay attention to MySQL mode. ‣ Run composer

    inside Docker, commit composer.lock ‣ Anonymized production database. ‣ Send e-mails to relay: DebugMail, MailTrap, etc.
  40. Staging Environment ‣ Baseline server. ‣ Migration server. ‣ Staging

    config: point to sandboxes.
  41. Credit:

  42. <animés par la passion> THANKS! @afilina