Débarrassez-vous des bugs avec un process scientifique : le débug !
La réparation des bugs de logiciel ressemble à la relecture d’un article. Vous devez tous les trouver, apporter des corrections, et vous assurer que ce sont des améliorations par rapport à l’original. Ce process basique s’appelle le débug. Pour débugger un logiciel de manière efficace, vous devez utiliser une approche méthodique pour identifier et résoudre chaque problème. Spécifiquement, pour chaque bug que vous voyez, vous devez respecter les étapes suivantes :
Étape 1 : Observez le bug
Avant de supposer que vous êtes face à un bug, assurez-vous qu’il est bien réel !
Avez-vous déjà vu un logiciel échouer puis se mettre soudainement à fonctionner à nouveau ? Votre connexion réseau a pu être interrompue pendant deux minutes, ou votre ordinateur effectuait peut-être une mise à jour au moment où votre application a redémarré spontanément. Vous ne reverrez peut-être jamais ce problème particulier, car il était dû à un pépin et à une convergence de facteurs peu probables. Ce n’était peut-être même pas un problème à la base !
Étape 2 : Écrivez un test répétable pour le comportement correct attendu
Pour commencer le travail sur un bug, vous devez être capable de vérifier que c’est quelque chose que vous pouvez reproduire, comprendre, corriger, et dont vous pouvez prouver la réparation. Cela signifie que vous avez besoin d’un moyen de reproduire le problème, afin que vous puissiez enquêter à son sujet et vérifier son comportement. Quel serait un moyen fiable de mettre en place votre logiciel de manière prévisible pour que (a) il fasse quelque chose et (b) que vous vérifiez le résultat ? Cela ressemble à une tâche pour un test automatique ! 🙂
Pour ce faire, créez un test pour le comportement attendu de votre logiciel sans le bug. (Il échouera à sa première exécution, car vous avez un bug !) Ainsi, quand vous pensez avoir résolu le problème, vous pouvez lancer le test. S’il réussit, vous saurez que vous avez corrigé le problème avec succès ! De plus, avec un test, vous verrez si quelqu’un réintroduit ce bug un jour.
Étape 3 : Proposez une théorie sur la raison de l’apparition du bug
Quand vous commencez par un test, vous pouvez enquêter pour déterminer quel élément dans le code fait échouer le test. En étudiant le code alors que votre test échoue, vous trouverez une ou plusieurs idées sur les causes possibles du problème. Chacune de ces idées peut être listée et soumise à enquête en testant votre solution. Devinez quoi ? Ces excellentes idées que vous avez trouvées sont des théories !
Et si j’arrive à voir immédiatement quelle est l’erreur dans le code ? Je dois toujours écrire un test et imaginer des théories ?
Certaines erreurs sembleront évidentes. En voyant le message d’erreur, vous pourriez penser intuitivement que vous savez ce qu’il se passe. Imaginons que vous remarquez qu’une exception ait été levée depuis une classe que vous venez de modifier. Cela semble être une solution évidente pour ce bug. Est-ce qu’il ne serait pas tentant de lancer votre IDE, vous plonger dans le code, et trouver le chemin le plus rapide pour contourner le problème ?
Mais êtes-vous sûr de déjà savoir quel est le problème ? Même si vous supprimez le symptôme (l’exception) pour l’instant, vous n’aurez peut-être pas traité les causes profondes. En ne prenant pas le temps d’examiner les causes premières possibles, le risque existe toujours qu’un problème sous-jacent provoque le chaos dans votre programme d’une autre façon.
De plus, le fait de contourner un bug signifie généralement que vous ajoutez un cas spécial à votre logiciel, qui est contraire à son comportement normalement attendu. En parlant de cas spécial, je veux parler de manipulation de la logique de votre programme d’une façon qui n’est pas cohérente avec le design original du code. Ceci compliquera votre logiciel, et vous devrez envisager des situations inhabituelles dès que vous ferez une modification.
Si l’erreur est évidente, vous avez une théorie à valider, et l’écriture du test la confirmera. Je sais qu’il est difficile de ne pas se lancer immédiatement, mais il vous faut déterminer précisément pourquoi le bug a été déclenché, et non uniquement comment l’éliminer. En commençant par une théorie et un test automatique pour la vérifier, vous pouvez cibler un problème spécifique et être sûr que vous l’avez réparé !
Étape 4 : Confirmez ou infirmez la théorie
Et maintenant, essayez de confirmer votre théorie en menant l’enquête dans votre code. Votre but est de réparer le test qui échoue. Avec votre théorie, nous espérons que vous réparerez le bug, ainsi qu’une série d’autres problèmes similaires. Si ce n’est pas le cas, revenez à l’étape 2 et recommencez avec une nouvelle théorie, jusqu’à avoir trouvé une réponse.
Étape 5 : Résolvez le bug
Rappelez-vous que les bugs arrivent souvent à plusieurs. Une seule erreur peut se manifester par une série de bugs similaires. Il m’est arrivé à de multiples reprises d’avoir réparé un bug et de le voir fermer une série d’autres bugs similaires. Encore une fois, une bonne façon de résoudre cela est d’effectuer davantage de tests.
Comment appliquer ces étapes à l’investigation d’un bug réel ?
Imaginons que vous ayez construit une application d’e-commerce. Vous avez reçu un rapport de bug indiquant que, lorsqu’une utilisatrice essaye d’enlever un seul élément de son panier, elle se retrouve avec un élément de plus plutôt qu’un élément de moins. Comment aborderiez-vous ce cas en utilisant la structure ci-dessus ?
Parcourons les étapes ensemble :
Étape 1 : Reproduisez ! Tout d’abord, il vous faut vous assurer qu’il s’agit d’un bug réel. Il existe différentes façons dont vous pouvez le reproduire dans une application en exécution :
Demandez à l’utilisateur de vous montrer ce qu’il s’est passé, ce qui pourrait confirmer la réalité du bug ;
Consultez tous les logs que vous avez pour comprendre ce qu’il s’est passé dans le logiciel à ce moment-là (en supposant que vous ayez de bons logs). Si ce n’est pas le cas, enrichissez-les et réessayez.
Étape 2 : Écrivez un test ! Vous savez peut-être ce que vous devez réparer à ce stade. Il y a peut-être un + à la place d’un -. Plutôt que de vous précipiter, une manière méthodique de vous assurer que vous ne commettez pas d’autres erreurs serait d’écrire un test. Vous pourriez écrire un test voué à l’échec qui s’attend à ce que le panier soit vide lorsque vous enlevez le seul élément qui s’y trouve. Il devrait échouer.
Étape 3 : Générez des théories ! Regardez le code et essayez de définir pourquoi le test échoue.
Étape 4 : Testez vos théories ! Utilisez le test qui échoue pour reproduire le bug, et, sur la base de vos théories, testez différentes réparations jusqu’à ce qu’il soit résolu (c’est-à-dire, que les éléments soient supprimés du panier). Le test restera dans votre code et aidera d’autres développeurs à s’assurer qu’il ne se casse pas à nouveau.
Étape 5 : Résolvez votre bug ! Vous aurez peut-être besoin de tests supplémentaires si vous avez découvert plus de bugs.
On dirait que ce process peut prendre pas mal de temps. Et si je suis sous pression et que le bug doit être réparé le plus vite possible ?
Nous avons tous connu cela. Mais le fait de réparer quelque chose le plus vite possible ne signifie pas qu’il ne faut pas le reproduire, comprendre, et tester. Il le faut si l’on veut avoir une chance de la réparer vraiment.
Imaginez que vous décidiez de réparer quelque chose sans respecter la procédure ci-dessus. Votre première impulsion sera peut-être de tester manuellement (ou de tâtonner), mais cela peut prendre plus longtemps que vous ne le pensez. Arrêtez-vous et repensez votre approche. Les tests manuels peuvent être lents et peu fiables comparés aux tests automatiques.
Si vous décidez de sortir une réparation effectuée à la va-vite, vous devez tout de même nettoyer derrière vous. Ne voudriez-vous pas être sûr que vous avez résolu le véritable problème et que vous n’en avez pas causé d’autres ? Voudriez-vous pouvoir savoir si le bug sera réintroduit accidentellement à l’avenir ? Moi oui !
Ne répétez pas la même négligence qui s’est produite lors de l’écriture initiale de votre code. Prenez le temps de réparer votre bug de façon fiable.
Vivre dans un monde de bugs
En tant qu’ingénieur logiciel, vous avez autant de chances d’éliminer les bugs de votre logiciel que les jardiniers en ont d’éliminer les insectes de leurs jardins.
Les bugs sont un résultat de l’erreur humaine. C’est-à-dire qu’ils font partie de la nature. Nous essayons de les éliminer depuis toujours, mais vous pouvez au mieux réduire la probabilité qu’ils apparaissent. Un logiciel n’est jamais parfait.
Vous pouvez au mieux essayer de les éviter en utilisant les pesticides suivants :
Testez largement pour prouver que vous répondez à vos exigences métiers et techniques connues.
Écrivez le logiciel pour qu’il soit aussi résistant à l’échec que possible à l’aide des bonnes pratiques de développement.
Abordez les rapports de bug calmement.
Prenez un bug comme une opportunité de comprendre quelque chose que vous n’avez pas vu la première fois, et de prouver méthodiquement qu’elle a été réparée.
Dans ce cours, nous nous concentrerons sur les deux derniers points et nous apprendrons comment utiliser des outils pour nous familiariser avec les bugs qui se faufilent entre les lignes de code !
En résumé
Les tests peuvent réduire la probabilité d’apparition des bugs, mais ils n’ont que la qualité des scénarios qui ont été imaginés au départ.
Pour résoudre un bug de façon fiable, utilisez la méthode scientifique et une série d’expérimentations avec des tests répétables :
Écrivez un test répétable pour le comportement correct attendu.
Investiguez la raison de l’échec de ce test et imaginez des théories.
Testez les théories et les solutions pour rectifier le test qui échoue.
Faites réussir le test qui échoue et résolvez le bug.
Envie d'appliquer cette méthodologie ? Commencez par installer votre environnement de débug, en suivant le prochain chapitre !