Introduction : pourquoi le code legacy n'est pas une fatalité
\nChaque développeur a rencontré du code legacy — cette « boîte noire » que l'on craint de toucher parce que « ça marche, et il ne faut pas y toucher ». Cependant, lorsque la base de code en Kotlin (ou Java, qui est progressivement migrée) commence à freiner le développement, à accumuler des bugs et à effrayer les nouveaux membres de l'équipe, le moment du réusinage est venu. Le réusinage de code legacy en Kotlin n'est pas une simple réécriture, mais un processus systématique d'amélioration de la structure interne sans modifier le comportement externe.
\nDans cet article, nous allons parcourir le chemin complet : de l'analyse de l'état actuel à l'implémentation des pratiques modernes de Kotlin. Vous apprendrez comment transformer en toute sécurité un code obsolète en utilisant les fonctionnalités du langage (nullabilité, fonctions d'extension, classes sealed) sans casser la production.
\n\n1. Diagnostic : comment évaluer l'ampleur du code legacy
\nAvant de se lancer dans le réusinage, il est nécessaire de comprendre à quoi vous avez affaire. Le code legacy en Kotlin provient souvent de projets commencés en Java, puis partiellement migrés. Les signes typiques sont :
\n- \n
- Objets God — des classes qui font tout : de l'analyse à la logique métier. \n
- Absence de tests — le code n'est pas couvert par des tests unitaires, et toute modification est risquée. \n
- Données mutables — abondance de
varau lieu deval, listes mutables transmises entre modules. \n - Cauchemar Null — opérateur
!!dispersé dans tout le code et vérifications infiniesif (x != null). \n
Pour le diagnostic, utilisez des outils : Detekt (analyse statique Kotlin), SonarQube (métriques de qualité) et Inspections IntelliJ IDEA. Créez une liste de contrôle des points problématiques et priorisez-les en fonction du risque et de la fréquence d'utilisation.
\n\n1.1. Établir une carte des dépendances
\nPrenez une feuille de papier ou utilisez PlantUML pour visualiser les relations entre les classes. Si le graphe de dépendances ressemble à une toile d'araignée, c'est un signal d'alarme. Portez une attention particulière aux dépendances cycliques : elles rendent le code fragile et difficile à tester.
\n\n2. Stratégie de réusinage : plan d'action étape par étape
\nUn réusinage sans plan est une voie vers la catastrophe. Utilisez l'approche « Technique des petits pas » (baby steps). Algorithme d'action :
\n- \n
- Documentez le comportement — écrivez des tests de caractérisation (characterization tests) qui figent le comportement actuel du système. \n
- Isolez les modifications — travaillez dans une branche séparée, utilisez des feature toggles pour les parties complexes. \n
- Réusinage par motifs — appliquez des techniques éprouvées (Extract Method, Replace Conditional with Polymorphism, Introduce Parameter Object). \n
- Migration progressive — n'essayez pas de tout réécrire d'un coup. Utilisez les annotations
@Deprecatedpour les anciennes méthodes. \n
2.1. Exemple : remplacer if-else par when et les classes sealed
\nUn code legacy typique en Kotlin contient des chaînes if-else pour gérer les états :
\n// Mauvais : indicateur mutable et if-else\nvar status = "active"\nif (status == "active") {\n // ...\n} else if (status == "inactive") {\n // ...\n} else {\n throw Exception("Statut inconnu")\n}\nRéusinage avec des classes sealed :
\n// Bon : modèle type-safe\nsealed class Status {\n object Active : Status()\n object Inactive : Status()\n data class Custom(val reason: String) : Status()\n}\n\nfun handleStatus(status: Status) = when (status) {\n is Status.Active -> // traitement\n is Status.Inactive -> // traitement\n is Status.Custom -> // traitement avec reason\n}\nCela élimine le besoin de else et rend le code extensible.
3. Travail sécurisé avec les nullable et les collections
\nLe code legacy contient souvent