Les changements de Python 2 à 3 rendent le remaniement du code inévitable
La perspective de devoir se plonger dans un ancien code pour le faire fonctionner avec une nouvelle version du langage est l'une des choses que les développeurs essaient d'éviter à tout prix. Il est difficile de comprendre un vieux code, des changements inattendus peuvent introduire de nouveaux bogues, les performances risquent d'en souffrir et il s'agit d'un effort considérable pour un rendement limité. Après tout, vous n'ajoutez rien de nouveau, vous faites simplement en sorte qu'il fonctionne comme avant. Cet article présente quelques exemples de modifications apportées à Python 2 et 3 qui rendent le remaniement du code inévitable.
Vous avez donc votre application Python 2 qui fonctionne comme prévu. Elle fonctionne parfaitement depuis quelques années maintenant, l'équipe de développement a aplani toutes les difficultés et tout le monde est satisfait de ses performances. Elle fait son travail et disparaît lorsqu'elle n'est plus nécessaire.
Mais, soudain, une nouvelle vulnérabilité est publiée, visant Python 2. Les correctifs de sécurité ne sont plus disponibles car la version 2 n'est plus prise en charge officiellement, de sorte que votre fantastique application, sans qu'il y ait faute de sa part, est maintenant vulnérable elle aussi et est devenue un problème de sécurité pour l'organisation. En tant que responsable informatique diligent, vous chargez votre équipe de développement de donner la priorité à la refonte du code pour qu'il fonctionne avec une version sécurisée de Python 3.
Votre équipe avait d'autres projets en cours, et tout cela est maintenant mis en attente. C'est une décision coûteuse, mais elle doit être prise, n'est-ce pas ? Il faut quelques semaines pour rassembler tous les détails concernant les changements de code nécessaires et la façon dont ils affectent d'autres sections du code, inattendues ou dont on ne se souvient plus. Une grande partie de la logique de base doit être réécrite, car certaines fonctionnalités ont été dépréciées depuis Python 2, et le remplacement dans Python 3 n'est pas instantané, donc de nouveaux tests unitaires doivent être créés également.
Quelques semaines passent encore, alors que les développeurs s'efforcent de comprendre un code mal documenté, écrit par un ancien collègue qui ne fait plus partie de l'organisation. Il semble que certaines sections du code "fonctionnent", mais personne ne comprend plus pourquoi. Oh, et quelques dépendances ne supportent pas Python 3 et ne le feront probablement pas de sitôt - les projets ne semblent plus être supportés.
Après des mois de travail acharné, l'équipe de développement revient avec une construction Frankenstein d'une nouvelle version de l'application. Elle ressemble légèrement à l'originale ; certains choix d'interface utilisateur rendent difficile l'utilisation des connaissances accumulées, et il est donc nécessaire de former à nouveau les opérateurs.
Les performances semblent être affectées dès qu'une modification est apportée à la base de données. Personne ne sait exactement pourquoi, mais l'une des dépendances qui a dû être écrite à partir de zéro a mieux géré ce problème. Et tous les projets initiaux que l'équipe avait en main sont maintenant en retard et dépassent le budget également.
L'équipe est revenue avec certaines des conclusions à conserver comme connaissances utiles pour les futurs efforts de refactoring :
Division :
Python 3 : 5/2 == 2,5
Python 2 : 5/2 == 2 (doubler sur "/" à "//" retourne l'ancien comportement)
La division d'entiers renvoie désormais un flottant et non plus un int.
Imprimer :
Python 3 : print("")
Python 2 : print ""
Changements de dictionnaire :
Python 3 : les méthodes dict keys(), items(), values() retournent des vues
Python 2 : ces méthodes retournent des listes. De plus, les méthodes iterkeys(), iteritems, et itervalues() ne sont plus supportées.
Triage :
Python 3 : cmp() ne devrait plus être utilisé.
Texte et binaire :
Les données textuelles et binaires sont désormais des concepts différents et ne doivent plus être stockées dans des chaînes de caractères. Certaines opérations sur les chaînes de caractères ne fonctionnent plus dans les données où elles fonctionnaient auparavant, car elles contiennent des caractères qui ne sont plus autorisés dans les chaînes de caractères.
Tuples :
Les paramètres des tuple ne peuvent plus être dépaquetés comme auparavant.
Plusieurs mots-clés ont été supprimés :
“<>” is now “!=”.
Les littéraux entiers ne fonctionnent plus avec un l ou un L de fermeture.
Les littéraux de chaîne ne fonctionnent plus avec un u ou U de fermeture.
L'importation de tout ce qui se trouve dans un module ne fonctionne désormais qu'au niveau du module, et non à l'intérieur d'une fonction.
Et beaucoup, beaucoup d'autres changements (La liste complète peut être consultée ici : https://docs.python.org/3/whatsnew/3.0.htmlqui a été utilisé comme source pour cet article).
À la fin du processus, l'application fonctionne moins bien qu'avant ; aucun avantage réel n'a été retiré du passage à un nouveau niveau de langage - seules les constructions qui remplaçaient les anciennes fonctionnalités ont été utilisées, et aucune nouvelle fonctionnalité avancée, car l'objectif était simplement de la faire fonctionner à nouveau. Il s'agissait d'une tâche coûteuse qui a affecté de nombreuses autres activités de l'organisation et provoqué des perturbations à tous les niveaux.
Qu'est-ce qui aurait pu être fait à la place ?
Une meilleure alternative existe sous la forme d'Extended Lifecycle Support for Python. En fournissant des corrections de sécurité opportunes sans introduire de changements au niveau du langage, le problème aurait pu être résolu simplement en déployant le service. Le même code aurait continué à fonctionner tel quel, la faille de sécurité aurait été corrigée et toutes les autres perturbations auraient pu être entièrement évitées.