
Partager:
Max est un défenseur des développeurs Python et un ingénieur logiciel qui s'intéresse aux API de communication, à l'apprentissage automatique, à l'expérience des développeurs et à la danse ! Il a suivi une formation en physique, mais il travaille désormais sur des projets open-source et fabrique des objets qui améliorent la vie des développeurs.
Améliorez votre projet logiciel - Première partie : Comprendre une base de code
Temps de lecture : 8 minutes
Avez-vous déjà pris en charge une base de code et réalisé que vous n'étiez pas satisfait de la façon dont le code était écrit ou organisé ? C'est une histoire courante, mais qui peut causer bien des maux de tête. La dette technique peut faire boule de neige, rendant la compréhension du code et l'ajout de nouvelles fonctionnalités exponentiellement plus difficiles.
Dans cette série en trois parties, je vais passer en revue certaines des choses clés que vous voudrez faire pour devenir plus heureux avec votre (ancien) projet brillant. Pour donner des exemples concrets, j'expliquerai comment j'ai remanié et amélioré le logiciel libre Vonage Python SDKune bibliothèque qui fait des appels HTTP aux API de Vonage, mais les principes s'appliquent à n'importe quel type de projet logiciel.
Les exemples de ce billet seront écrits en Python, mais ces principes s'appliquent à des projets dans n'importe quel langage. Il y a également une liste de contrôle pratique à suivre si vous essayez spécifiquement de corriger un projet Python.
La série, en sections
Première partie : Comprendre une base de code (cet article)
Que couvre cette série ?
Dans cette série, nous parlerons de :
Se familiariser avec le code
Devenir confiant pour apporter des changements et remédier à la dette technique
Établir la confiance avec votre patron, votre équipe et vos clients/communauté
Apporter des améliorations
Que faire lorsqu'il est temps de transmettre le projet ?
À la fin de chaque article, vous disposerez de stratégies pour faire face à cette situation et vous vous sentirez capable de le faire !
Sans plus attendre, entamons la première partie...
Première partie : comprendre le projet
Lire des choses !
La première chose à faire est d'essayer de comprendre ce que fait le code dont vous avez hérité et comment il est organisé.
Commencez par parler à toute personne connaissant le projet et lisez toute documentation disponible. Dans mon cas, il y avait un readme dans le repo qui m'a servi de point de départ. Il donnait un bon aperçu de l'état du code lors de sa dernière mise à jour.

La documentation du produit m'a également aidé à comprendre ce que le code était censé faire, car elle décrivait les API que je devais appeler et leur comportement actuel.

Construire des choses !
Une fois que vous avez une idée de ce que fait le code, l'étape suivante consiste à l'explorer en construisant une sorte de projet "Hello, World" - un projet simple qui utilise le code et fait quelque chose de petit, mais d'utile. Comme mon projet fait appel à des API, j'ai écrit un morceau de code très simple qui m'envoie un SMS.
import vonage
client = vonage.Client(key=MY_KEY, secret=MY_SECRET)
client.sms.send_message({
"from": "Max",
"to": MY_NUMBER,
"text": "Hello, world!",
})Cela a fonctionné !

Jouez avec votre base de code et créez votre propre "Hello, World".
Comprendre la structure du code
Il est important de comprendre comment le code du projet est organisé afin de pouvoir conceptualiser plus facilement ce qui se passe lorsque votre "Hello, World" s'exécute. C'est également un excellent moyen d'exercer vos compétences en matière de réflexion architecturale, car vous devrez développer un modèle mental du fonctionnement du code. Cette façon de penser vous aidera à diviser le projet en éléments distincts plus faciles à comprendre, ce qui vous sera utile plus tard lorsque vous voudrez réduire le couplage du code et d'autres effets secondaires.
Dans le cas de notre SDK, le code était organisé en six fichiers distincts (Python est un langage très compact, la base de code Java équivalente est environ 10 fois plus grande !
Un fichier pour initialiser le projet et gérer les importations,
Fichier contenant les méthodes internes,
un fichier contenant les classes d'erreurs personnalisées
Trois fichiers contenant chacun une classe relative à l'une des API de Vonage

La sonnette d'alarme a commencé à retentir lorsque j'ai réalisé qu'il y avait 3 fichiers nommés d'après les API de Vonage, alors que le README affirmait que 12 API différentes étaient prises en charge.
Je me suis rendu compte que la majeure partie du code se trouvait dans un fichier (__init__.py), typiquement utilisé pour les importations, dans une grande classe qui traitait de tout. Comme cela n'aidait en rien la structure, j'ai décidé d'examiner la structure des tests pour obtenir plus d'informations sur la façon dont le code était organisé.
Les tests étaient judicieusement regroupés en modules, ce qui m'a aidé à comprendre les différents composants en jeu. Je recommanderais d'essayer de comprendre la structure de votre code et de vos tests, car les deux peuvent être utiles.

Préparez le développement et lancez les tests !
Il est maintenant temps d'installer les dépendances du projet et de lancer les tests. S'ils passent, en utilisant la dernière version de votre langage et de vos dépendances, c'est une bonne nouvelle ! Le mien n'a pas réussi, j'ai donc commencé avec les versions exactes des dépendances qui étaient mentionnées et j'ai mis à jour progressivement les dépendances pour trouver celles qui ne fonctionnaient pas bien avec la dernière version de mon langage de codage.
Dans cette situation, mettez à jour les dépendances de manière incrémentale et les problèmes devraient se révéler d'eux-mêmes. L'une de vos dépendances a probablement été mise à jour avec un changement radical depuis la dernière utilisation de la base de code. (Dans mon cas, une dépendance a changé la façon dont elle renvoyait les données entre les versions, j'ai donc dû réécrire quelques tests pour gérer les données correctement).
Des outils qui peuvent vous aider
Cette section mentionne quelques façons d'utiliser des outils pour se mettre au diapason d'un projet. L'utilisation d'outils d'analyse de code peut être extrêmement utile car leur utilisation peut être automatisée, ce qui signifie que vous pouvez lancer l'outil aussi souvent que vous le souhaitez et suivre vos progrès lorsque vous commencez à améliorer la base de code.
Les outils sont également très utiles pour planifier le travail, car les informations qu'ils fournissent vous indiquent où se trouvent la dette technique et les points chauds du code, et vous suggèrent comment prioriser votre temps !
Outils d'analyse
L'analyse statique est un moyen d'analyser automatiquement le code source sans avoir à l'exécuter. Elle peut donner un aperçu de la structure d'une base de code, mettre en évidence les duplications et autres cibles de remaniement, et vous avertir de toute vulnérabilité potentielle. Des outils gratuits sont disponibles en ligne pour la plupart des langages, et de nombreux fournisseurs de services payants proposent un volet gratuit pour les projets non commerciaux ou à code source ouvert, par exemple sonarcloud.
L'analyse comportementale permet d'en savoir plus sur un projet en se basant sur l'historique des livraisons. Cela permet de savoir qui a travaillé sur le projet et quand, ce qui a été modifié et quels composants sont fréquemment modifiés ensemble, ainsi qu'une foule d'autres informations. Il s'agit d'une méthode très utile pour les grands projets avec de nombreux committers. CodeScene dispose d'une version gratuite pour les projets open-source et fonctionne bien.
Couverture des tests
La couverture des tests (le pourcentage d'instructions de code couvertes par vos tests) est utile pour déterminer exactement ce que vos tests unitaires testent. Elle peut également mettre en évidence les zones d'une base de code qui ne sont pas testées. Des outils sont disponibles dans la plupart des langages ; pour Python, je recommande couverture.

Score de mutation
La couverture des tests peut vous indiquer quelle partie de votre code est couverte par des tests, mais cela ne vous dit pas dans quelle mesure vos tests testent réellement le comportement de votre code ! Les tests de mutation permettent de mieux comprendre dans quelle mesure vous pouvez faire confiance à vos tests pour faire leur travail et s'assurer que votre code fonctionne comme prévu.
Il prend des instructions dans votre code et les modifie légèrement, par exemple en changeant une chaîne de caractères ou en remplaçant un plus par un moins, etc. pour produire de nombreuses versions "mutantes" de votre code. Votre suite de tests est ensuite exécutée contre chacune de ces versions mutantes de votre code. Comme les choses ont changé, nous nous attendons à ce que les tests échouent - nous disons que nous avons attrapé le mutant. Mais si vos tests réussissent malgré ces changements, le mutant s'est échappé et ces petits changements auraient pu se retrouver en production ! Ainsi, le score de mutation (rapport entre le nombre de mutants détectés et le nombre total de mutants créés) nous indique le degré de confiance que nous devrions avoir dans nos tests.
Il existe des versions de ce document dans de nombreuses langues, notamment Stryker qui prend en charge Javascript, Node.js et C#. En Python, je recommande d'essayer mutmutqui est simple et efficace.

Comprenez la pile d'appels en profilant votre échantillon !
Je vous recommande d'essayer de comprendre la pile d'appels qui se produit lorsque votre "Hello, World" s'exécute. Il existe des outils dans la plupart des langages pour ce faire.
En Python, j'aime recommander un outil appelé Snakeviz pour afficher visuellement votre pile d'appels. Placez votre code "Hello, World" dans une fonction et profilez-la, comme suit :
with cProfile.Profile() as pr:
send_sms() # This function is where the Hello, World code lives
stats = pstats.Stats(pr)
stats.dump_stats(filename='send_sms.prof')Cela génère un fichier appelé send_sms.prof. Si vous l'exécutez en ligne de commande avec Snakeviz...
...il génère un graphique interactif qui vous montre toutes les fonctions que votre fonction appelle, toutes les fonctions qu'elle appelle et toutes les fonctions qu'elle appelle. qu'elles appellent, et ainsi de suite. Cela peut être utile pour vous aider à suivre le chemin de l'ordinateur à travers le code, et peut mettre en lumière la façon dont il fonctionne.

Quelle est la prochaine étape ?
Si vous suivez les suggestions de cet article, vous serez en bonne position pour commencer à établir la confiance, à vous attaquer à la dette technique et à apporter des changements à votre base de code. Revenez bientôt pour la deuxième partie, où nous parlerons de tout cela en détail.
En attendant, vous pouvez nous contacter sur notre Communauté Vonage Slack ou nous envoyer un message sur sur Twitter.
Partager:
Max est un défenseur des développeurs Python et un ingénieur logiciel qui s'intéresse aux API de communication, à l'apprentissage automatique, à l'expérience des développeurs et à la danse ! Il a suivi une formation en physique, mais il travaille désormais sur des projets open-source et fabrique des objets qui améliorent la vie des développeurs.