$30 off During Our Annual Pro Sale. View Details »

Réécriture de code vieux de 17 ans

Réécriture de code vieux de 17 ans

Anna Filina
PRO

October 27, 2017
Tweet

More Decks by Anna Filina

Other Decks in Programming

Transcript

  1. @afilina
    Réécriture de code vieux de 17 ans
    Forum PHP, Paris - 27 octobre 2017

    View Slide

  2. Anna Filina
    • Sauvetage de projet
    • Code legacy
    • Développement
    • Conférences
    • Formations privées
    • Contrebande
    d'éléPHPants

    View Slide

  3. Vous avez hérité d'un code
    de 17 ans
    Ça ne vieillit pas comme le vin.

    View Slide

  4. Le Web était large de 600px

    View Slide

  5. Vous vous sentez vieux?
    • Bug de l'an 2000.
    • Internet Explorer 5.
    • ICQ commençait à devenir cool.
    • Coins ronds = marque de distinction.
    • PHP 4!

    View Slide

  6. Legacy

    View Slide

  7. Code smells

    View Slide

  8. Préoccupations mixtes
    mysql_query('...');
    $total = 0;
    foreach ($products as $p) {
    $total += $p['qty'] * $p['price'];
    }
    ?>
    Total: = $total ?>

    View Slide

  9. Variables mal nommées
    $a = //...
    $array = //...
    $item3 = //...

    View Slide

  10. Fonctions et constantes globales
    include("functions.php");
    MyClass::myMethod();
    // une fonction dans un namespace?
    myMethod(DEV_MODE);

    View Slide

  11. Conditions douteuses
    if ($order_id > 20117) {
    // use this sql
    } else {
    // use that sql
    }
    // faiblesse = occasion pour le refactoring

    View Slide

  12. Longues méthodes
    public function importCsv($path, $googleApiKey, $databaseDsn, $databaseUser, $databasePassword)
    {
    // Convert CSV to array of conferences
    $lines = file($path);
    $csv = array_map('str_getcsv', $lines);
    $conferences = [];
    foreach ($csv as $line) {
    $conference = new Conference();
    $conference->name = $line[0];
    $conference->location = $line[1];
    $conferences[] = $conference;
    // Get coordinates for location
    $location = urlencode($conference->location);
    $url = 'https://maps.googleapis.com/maps/api/geocode/json?address='.$location.'&key='.$googleApiKey;
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $response = curl_exec($curl);
    curl_close($curl);
    $json = json_decode($response);
    if (count($json->results) == 0) {
    continue;
    }
    $latitude = $json->results[0]->geometry->location->lat;
    $longitude = $json->results[0]->geometry->location->lng;
    $coordinates = $latitude.','.$longitude;
    $conference->coordinates = $coordinates;
    // Save conference to database
    $pdo = new PDO($databaseDsn, $databaseUser, $databasePassword);
    $statement = $pdo->prepare('REPLACE INTO conference (name, location, coordinates) VALUES (?, ?, ?)');
    $statement->execute([
    $conference->name,
    $conference->location,
    $conference->coordinates,
    ]);

    View Slide

  13. Fichier de code legacy moyen
    • 3000-6000 lignes de code.
    • La moitié est commentée "juste au cas".
    • Des méthodes de 800 lignes.
    • Parfois pas de classes.

    View Slide

  14. Code base
    • 5 000 classes.
    • 20 000 méthodes.
    • 1 500 000 lignes de code.

    View Slide

  15. Avant de coder

    View Slide

  16. Stratégie
    • Bâtir une stratégie selon les
    contraintes
    • Réécriture complète vs
    progressive:
    ◦Par classe.
    ◦Par feature/module.
    ◦Par appel HTTP.
    • Exécuter le code côte à côte:
    ◦Partage de BD/session.
    ◦mod_rewrite.

    View Slide

  17. Les données se perdent, les choses se brisent
    • Sauvegarde: test de restauration.
    • Anonymisez les données
    sensibles.
    • Staging: simulez les
    déploiements/processus batch.
    • Automatisez les tests avant les
    changements.
    • Faites une évaluation de risque:
    ◦ Ne soyez pas trop optimistes.
    ◦ Tenez compte des effets secondaires.

    View Slide

  18. Utilisez les données legacy réelles

    View Slide

  19. Exemple de réécriture
    (échec)

    View Slide

  20. PHP 3 vers PHP 5.6
    • HTML + PHP + SQL dans un fichier.
    • Des include partout.
    • SQL concaténé par des if.
    • Tentative de réécriture:
    ◦ Échouée, a rendu les choses pires.
    ◦ Dossiers de code mort.
    ◦ Classes avec méthodes statiques (pas d'instances).

    View Slide

  21. Solution
    • Réécrire les formulaires complexes en
    Symfony:
    ◦ mod_rewrite pour les pages concernées.
    • Réécrire le plus gros module en orienté-
    objet:
    ◦ Extraction de design.
    ◦ Architecture flexible.
    ◦ Tests automatisés.

    View Slide

  22. Une fonctionnalité ne
    devrait pas prendre plus
    qu'un sprint

    View Slide

  23. Extraction de design

    View Slide

  24. Éviter d'être biaisé par le code
    • Ancien code → design.
    • Valider le design:
    ◦Clarifier les règles d'affaires.
    • Améliorer le design:
    ◦Réduire la dette technique.
    ◦Plus flexible.
    • Design → nouveau code.

    View Slide

  25. Correction de bogues

    View Slide

  26. Duplication de code
    • Un bogue répété 80 fois.
    • Enlever les doublons au
    plus vite.

    View Slide

  27. Corriger les méga-méthodes
    • Extraire la partie brisée dans sa propre
    méthode.
    • Écrire des tests unitaires pour la
    nouvelle méthode.
    • Réparer.
    • Appeller à partir de la méga-méthode.

    View Slide

  28. Trouver les groupes logiques
    Convert CSV to array of conferences.
    Get coordinates for conference location.
    Save conference to database.
    Bloc de code
    Commentaire
    Bloc de code
    Commentaire
    Bloc de code
    Commentaire

    View Slide

  29. Extraire et tester
    Bloc de code
    Méthode
    Bloc de code
    Commentaire
    Bloc de code
    Commentaire
    Appel

    View Slide

  30. Nommer
    Bloc de code
    Méthode
    Bloc de code
    Méthode
    Bloc de code
    Méthode
    Appel
    Appel
    Appel
    getConferencesFromCsv
    getLocationCoordinates
    saveConference

    View Slide

  31. Exemple de réécriture
    (succès)

    View Slide

  32. ASP Classic vers PHP 5.6
    • Spaghetti et raccourcis (15+).
    • Langage plus supporté.
    • Gros ERP avec beaucoup de code.

    View Slide

  33. Solution
    • Réécrire page par page vers Symfony.
    • mod_rewrite pour les pages concernées.
    • Adaptateur de sessions en BD dans les
    deux applications.
    • Page dans n'importe quel langage =
    requête HTTP.

    View Slide

  34. View Slide

  35. Tests Guzzle

    View Slide

  36. Tester les méthodes statiques
    $mock = Mockery::mock('alias:SomeClass');
    $mock->shouldReceive('staticMethod')->andReturn(42);

    View Slide

  37. Coincé?

    View Slide

  38. Essayez quelque chose de nouveau
    • Partagez les idées.
    ◦ De nouvelles personnes pour élargir la vision.
    • Est-ce que ça a déjà été fait?
    • Puis-je essayer une autre approche?

    View Slide

  39. À retenir
    • Faire une stratégie.
    • Vous le touchez, vous le refactorisez.
    • Utiliser des outils et des méthodologies
    connus.
    • Inspirez-vous des autres.
    • Le refactoring devient plus facile.
    • Chaque problème a une solution.

    View Slide

  40. Refactoring: Improving the
    Design of Existing Code
    Martin Fowler

    View Slide

  41. @afilina afilina.com
    joind.in

    View Slide