Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rewriting Legacy Code

Rewriting Legacy Code

Did you ever have to maintain a 15-year-old application? Dead code everywhere, hard dependencies, null pointer exceptions, database queries mixed with HTML, no tests and most libraries have been discontinued.

This presentation will show you how to modernize your application using a variety of strategies. You will learn how to avoid common pitfalls, automate legacy testing, manage your development environment and overcome various challenges that arise from dealing with legacy.

Anna Filina

August 20, 2020
Tweet

More Decks by Anna Filina

Other Decks in Programming

Transcript

  1. Anna Filina ‣ Coding since 1997. ‣ Legacy archaeology. ‣

    Test automation. ‣ Talks and workshops. ‣ Twitter advice (@afilina) ‣ YouTube videos.
  2. History Since 2000 2004 PHP 5.0 2005 Symfony 2006 Zend

    Framework 2008 Clean Code 2011 Laravel 2001 PHPUnit
  3. 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 10 children down. ‣ methodName_new, methodName_new2
  4. 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.
  5. Version Upgrade ‣ No need to freeze development. ‣ PHPCodeSniffer

    can detect incompatibilities. ‣ Also need to patch libs & framework. ‣ Some libs might be easier to swap than to fix (PHPExcel). ‣ Regexes are your friends. ‣ Rector can automatically refactor.
  6. New Framework ‣ Use dependency injection. ‣ Automate large chunks

    with Rector. ‣ Use adapters. ‣ Need to freeze development.
  7. 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)
 ); } }
  8. ‣ Remove dead code. ‣ Move logic to a better

    location. ‣ Split long functions. Techniques
  9. ‣ Some criteria for refactoring: • Need to change. •

    Hard to understand, but need to work with it. Refactoring Only
  10. 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.
  11. Version Upgrade Characterization tests Fix code Should work
 for old

    and new versions. Unit tests New/refactored code. What failed in E2E.
  12. New Framework Characterization tests Migrate Should work
 for old and

    new versions. Unit tests New/refactored code. What failed in E2E.
  13. Progressive Rewrite For new code only. Characterization tests Unit tests

    Should work
 for old and new versions. New code
  14. Refactoring Only For the 
 upcoming code. Characterization tests Unit

    tests Should work
 for old and new versions. Refactor
  15. Gotchas ‣ Pay attention to MySQL mode. ‣ Run composer

    inside Docker, commit composer.lock ‣ Anonymized production database. ‣ Send e-mails to relay: DebugMail, MailTrap, etc.