10 techniques pour débugger votre code

Tout développeur rencontre, à un moment ou à un autre, un problème qu’il a du mal à résoudre. Que ce soit pendant la réalisation d’une nouvelle fonctionnalité ou parce qu’un problème a été découvert en test ou en production. Récemment, j’ai aidé un stagiaire dans une situation similaire. Quand nous avons résolu son problème, j’ai bien senti qu’il voyait mon intervention comme de la magie. Il n’en est rien ! C’est juste l’application d’une série de petites recettes acquises au fil de l’expérience. Lisez cet article pour découvrir mes 10 techniques pour débugger votre code, à utiliser dans l’ordre qui vous plaira.

Vérifiez la syntaxe

Cette astuce s’adresse surtout aux débutants. Si votre problème est que votre code ne compile pas, vous avez un problème de syntaxe ! Quelques pistes pour vous aider à sortir de là :

  • Lisez les messages du compilateur. Autant que possible, le compilateur vous fournit des informations sur le problème qu’il a rencontré. Servez-vous-en !
  • Regardez aussi ce qui se trouve juste avant l’erreur indiquée par le compilateur. Souvent, celui-ci constate qu’il y a un élément inattendu, car il lui manque quelque chose avant cet élément. En conséquence, il faut aussi regarder avant l’erreur donnée par le compilateur !
  • Relisez patiemment votre code.
  • Si vous ne trouvez toujours pas, une bonne technique consiste à enlever, ou commenter, des parties du code, de manière cohérente. Regardez à chaque étape ce qui compile et quels sont les messages d’erreurs remontés.

Ne vous découragez pas, à force de pratiquer vous aurez de moins en moins de problèmes avec la syntaxe.

 

Ajoutez des tests

Vous devriez déjà avoir une bonne couverture de test, si ce n’est pas le cas, voilà un sujet à creuser d’urgence. Toujours est-il que vous avez trouvé un cas où le code ne fait pas ce qui est attendu : transformez-le en test ! Identifiez au maximum la partie d’où semble provenir le problème et isolez là dans un test unitaire le plus simple possible, qui va vérifier le bout de code en question dans tous les cas imaginable (pensez aussi aux cas aux limites).

Ce test vous permet de trouver et résoudre facilement votre problème. Et si le problème ne venait pas de là, vous aurez avancé en écartant cette partie du code, continuez à chercher ailleurs !

Au passage, vous augmentez votre couverture de test, ce n’est donc pas une perte de temps.

 

Revue de votre algorithme

Scrutez votre codeNotamment si vous êtes débutants, mais pas que, votre problème peut être purement algorithmique. Dans ces cas-là, les tests aident vraiment, donc je vous recommande de mettre en place le point précédent. Les tests sont pour moi la meilleure méthode pour fixer un problème d’algorithme. Vous avez peut-être du mal à écrire le bon test qui vous permet de mettre le doigt sur le problème, et du coup d’y trouver une solution.
Faites une passe sur votre algorithme, voire même exécutez le manuellement sur une feuille blanche (vous mettez toutes vos variables sur le bord gauche et ensuite vous faites évoluer leurs valeurs pas à pas). Soyez bien précautionneux, n’allez pas trop vite, faites réellement du pas-à-pas. Ne présupposez rien sur ce que fait l’ordinateur, il faut vraiment lire le code et l’exécuter “bêtement”. Si le problème vient de là, vous devriez le trouver rapidement.
Certains me diront qu’il vaut mieux utiliser le débuggeur ! Je ne suis pas de cet avis, même si je vous en parle au point d’après et si je m’en sers moi-même régulièrement. Je vous recommande de faire appel au débuggeur en second. En effet, l’ordinateur vous facilite trop la vie et vous pourriez passer plusieurs fois à côté du problème. J’ai déjà vu des développeurs trop pressés qui tournaient en rond avec le débuggeur, sans bien savoir comment s’en sortir. De plus, si vous n’êtes pas à l’aise avec l’algorithmique, j’ai constaté que l’exécution manuelle vous fait progresser bien plus vite que l’utilisation du débuggeur !
Pour clore ce sujet, tout développeur doit absolument être complètement à l’aise avec les principes de base de l’algorithmique. Si ce n’est pas votre cas, vous allez facilement gagner en aisance et en productivité en travaillant ce sujet. Vous pouvez pratiquer l’algorithmique en jouant via les sites suivants :

Si vous connaissez d’autres sites, n’hésitez pas à les partager en commentaire.

 

 

Exécution en mode « debug »

Dans la plupart des environnements de développement, vous pouvez demander à lancer votre programme en mode debug. C’est comme l’exécution manuelle que je vous ai présentée juste avant, mais c’est l’ordinateur qui gère les valeurs des variables et la position dans le code. Vous pouvez demander à avancer pas à pas ou à sauter une section. Vous pouvez consulter la valeur de chaque variable et même suivre en continu l’évolution des variables clés. Je vous recommande de tout d’abord progresser par blocs, en regardant les valeurs des variables clés pour identifier si le problème s’est déjà produit ou si tout va bien. Ainsi, vous identifierez rapidement le bloc de code d’où semble venir le problème.

Cherchez alors, par simple lecture du code (ou exécution manuelle comme décrite ci-dessus) à comprendre l’origine du problème. Si ce bloc de code n’a pas de test, ou peu, n’hésitez pas à en ajouter, cela vous permettra de plus facilement vérifier l’ampleur du problème et le fixer.
Si vous ne comprenez pas, recommencez la session de debug en vous concentrant sur le bloc en question. Vous pouvez même utiliser le mode debug pour vérifier que le problème vient de là. En effet, vous pouvez modifier la valeur des variables. En fin de bloc, modifier les variables qui sont en erreur et laisser le programme terminer son exécution. Si vous n’avez plus de problème, c’est bon, cela vient bien de là. Si vous avez toujours le problème, ou plus grave, si le problème a changé, vous devez continuer vos recherches. Vous avez clairement trouvé un bloc de code erroné, mais ce n’est pas le seul… Sad smile

 

Ne présupposez rien : vérifiez tout !

Naturellement nous pensons que tout fonctionne bien. Seulement voilà, nous avons rencontré un problème, cela montre bien qu’il y a au moins une partie du code qui ne fonctionne pas comme attendu. Donc il s’agit de tout vérifier. Bien sûr, je vous invite à débuter vos vérifications par les parties qui ont le plus de chance d’être à l’origine de votre problème Winking smile.
Quelques idées de points à vérifier :

  • Est-ce que toutes les parties de votre code fonctionnent comme attendu ? Si vous avez des tests unitaires, c’est vite vérifié. C’est dommage pour ceux qui n’en ont pas !
  • Est-ce que les éléments réseau sont bien disponibles ? Utilisez ping, traceroute pour vérifier que la communication peut passer.
  • Est-ce que les services web répondent comme attendu ? Si vous avez des services web, récupérez les requêtes que vous leur envoyez dans les logs et exécutez-les à la main pour vérifier le résultat.
  • Est-ce que ce sont bien les bons services qui répondent à vos appels ? Vérifiez, pour chaque appel de votre code à un service tiers, que celui-ci a bien reçu cet appel.

Sur ce dernier point, qui semble assez évident, j’ai une petite anecdote, et le souvenir d’une grosse prise de tête…

 

Anecdote : ma prise de tête avec MySql

La réalité dépasse parfois la fiction !J’installais le CMS WordPress pour faire un test “rapide”. Vers le début, au moment de configurer la base de données, WordPress n’arrivait pas à accéder à ma base locale MySql. J’ai créé une base et un utilisateur dédié, et WordPress ne les voyait pas ! C’était dingue, d’un côté, sur l’interface d’administration, je voyais bien le serveur MySql avec la base de données et l’utilisateur. De l’autre, avec WordPress, j’arrivais à me connecter au serveur, mais je ne pouvais pas accéder à la base et à l’utilisateur. C’est comme s’ils n’existaient pas !

Ce problème m’a facilement pris plus d’une heure jusqu’au moment où je réalise que peut-être je n’accédais pas au même serveur ! Attention, bien sûr, j’avais vérifié l’adresse du serveur et le port ! Tout était identique ! Mais, peut-être, pour une raison qui m’échappait pour le moment, je n’avais pas accès au même serveur MySQL. Aurais-je deux installations concurrentes sur mon ordinateur ?

Bingo ! J’avais bien 2 instances de serveurs MySql qui étaient toutes les deux connectées au même port de ma machine. Je pensais que par défaut MySql aurait ouvert le port en mode exclusif et cela n’aurait pas été possible. Visiblement, cela l’était. Pour en avoir le cœur net, j’ai stoppé une des instances. Et là, comme par magie, j’avais accès au même serveur ! 🙂

La morale de ma petite aventure : quand on ne comprend pas, il faut vraiment tout vérifier ! Allez jusqu’à constater que l’appel que vous pensez avoir passé à tel composant ou service a bien été reçu et est bien en cours de traitement. Ce n’est pas un autre qui répond à sa place par exemple. 😉

 

Vérifiez les versions des composants que vous utilisez

Le problème en développement logiciel et en informatique en général, c’est que le problème peut vraiment venir d’une très grande variété de sources différente. L’une d’elles est un problème de cohérence entre différentes librairies.

Par exemple :

  • Certaines librairies peuvent avoir des incompatibilités ou nécessiter d’utiliser une autre librairie dans des versions différentes,
  • Vous utilisez une librairie client pour accéder à un serveur (base de données, serveur de messagerie, service distant, etc). Assurez-vous d’avoir la bonne version de librairie correspondant au serveur.
  • Vous utilisez un composant qui facilite l’utilisation d’un autre composant. Par exemple, les ORM. Un ORM -Object Relational Mapping- permet d’échanger avec une base de données relationnelle tout en restant dans le monde objet.

Les technologies sont des ORM tellement devenues standard que la probabilité d’un problème à ce niveau-là est très faible (mais pas nulle). Si vous utilisez une autre couche d’abstraction pour un de vos composants, vérifiez également que la chaine complète est cohérente. J’entends que les versions des éléments suivants sont bien garanties de fonctionner ensemble :

  • Le composant d’abstraction (la librairie ORM Hibernate par exemple),
  • Le composant réel (le pilote JDBC MySql par exemple),
  • Le serveur correspondant (le serveur MySql lui-même).

Afin de vérifier la compatibilité des versions que vous utilisez, il faut vous rendre sur les sites web des éditeurs de chaque composant. Si certains composants sont prévus pour travailler conjointement avec d’autres, les compatibilités vous seront indiquées.

 

Revenir à ce qui fonctionnait

Une autre technique consiste à revenir en arrière jusqu’à une version où le problème ne se présente pas. Ensuite, vous réappliquez les modifications petit à petit en vérifiant si le problème se produit ou pas. Bien sûr, si vous utilisez un outil de gestion des versions, c’est infiniment plus simple. C’est même quasiment impossible de le faire correctement sans cet outil !
Utilisez la recherche dichotomique pour accélérer vos recherches. Faites des sauts importants de plusieurs versions pour isoler les versions les plus proches où cela fonctionne et cela ne fonctionne pas, puis prenez celle du milieu et testez. Regardez la technique suivante pour plus d’information au sujet des recherches dichotomiques.
Petite anecdote à ce sujet, j’ai récemment dû livrer un correctif sur un petit projet. En lançant les tests, je me rends compte qu’un test ne fonctionne pas. Mince, j’ai peut-être cassé une fonctionnalité ? Pour vérifier, je lance le test sur la version d’avant, en ayant bien enregistré mes changements quand même ;). Là, stupeur : le test échoue aussi. Je continue à appliquer la technique et je recherche la version où le test a été ajouté : il échouait déjà dans les mêmes conditions !

Honte sur le développeur qui a ajouté un test erroné, me direz-vous ? Il est vrai qu’il aurait dû, mais je ne suis pas du style à blâmer, je pense que l’on ne progresse pas de cette manière. De plus, pour le coup, c’est plutôt moi le fautif : le projet était tout petit et j’ai fait le choix de ne pas mettre de serveur d’intégration continue. Sans cela, il était facile d’ajouter un test erroné sans s’en rendre compte. J’en assume donc les conséquences.

Quoi qu’il en soit, la technique de retrouver la dernière version qui fonctionne m’a fait gagner du temps pour trouver rapidement la vraie raison du problème.

 

Diviser pour régner ou la recherche dichotomique

Cette technique n’est pas vraiment une technique en elle-même, c’est plus une méthode de travail transverse que vous allez pouvoir utiliser dans les autres techniques. Je trouve intéressant de vous la présenter ici, car j’ai vu beaucoup de développeurs, notamment juniors, effectuer des recherches beaucoup trop séquentielles.
La recherche dichotomique est un algorithme qui permet de rechercher un élément plus rapidement dans un tableau trié. L’algorithme procède ainsi :

  • Regarder la case au milieu de la zone d’analyse,
  • Si l’élément recherché est égal, c’est bon, nous l’avons trouvé,
  • Si l’élément recherché est plus grand, continuer avec la partie droite du tableau comme zone d’analyse,
  • Et si l’élément recherché est plus petit, continuer avec la partie gauche comme zone d’analyse,
  • Tant que nous n’avons pas trouvé l’élément, boucler sur le premier point.

J’aime comparer cet algo à l’adage “diviser pour régner”. Il suffit d’isoler des sous parties et si nous avons un critère de sélection, nous pourrons facilement choisir sur quelle partie continuer l’analyse.
Par exemple, vous pouvez l’utiliser pour :

  • Rechercher plus rapidement la version de code qui pose problème en réduisant les bornes de recherches min et max. Min étant la version où le code fonctionne, max étant celle où il ne fonctionne pas,
  • Isoler les blocs de codes qui fonctionnent ou pas avec le débuggeur en mettant les points d’arrêts à plusieurs endroits stratégiques. Dès que vous constatez que le problème s’est produit via la valeur des variables, vous savez que le problème se trouve entre ce point d’arrêt et le précédent.
    Pensez-y et utilisez ce type de recherche dès que possible.

Labyrinthe

Notez ce que vous faites et les résultats obtenus

À force d’avancer dans la résolution de votre problème, vous pourriez oublier une partie des pistes que vous avez suivies. Afin de garder l’esprit alerte et d’analyser au mieux les différents symptômes de votre problème, je vous recommande de noter vos différentes tentatives et constatations. Cela vous aidera à y voir plus clair et à aller plus rapidement à la solution.

 

Versionnez vos recherches

Assurez-vous d’avoir enregistré votre code de départ dans votre outil de gestion de version. Je vous recommande d’utiliser GIT et je suppose cela dans cette technique.
Si vous devez modifier beaucoup de code pour vos recherches, créez une nouvelle branche locale et versionnez vos changements et ajouts dans cette branche. Si nécessaire vous pouvez même créer plusieurs branches. Assurez-vous juste que le nom soit explicite, par exemple :
TEMP-RechercheProbleme-NOM-DU-PROBLEME
Assurez-vous qu’elles restent en local, ce serait une surcharge inutile de les partager avec le reste de l’équipe.
En faisant cela, vous pourrez facilement :

  • Revenir sur un état intermédiaire pour tester autre chose,
  • Récupérer les différentes modifications que vous souhaitez conserver dans le code. Il faudra alors les ajouter spécifiquement à la branche principale.

Si vous ne connaissez pas GIT, ou la gestion des versions, je vous recommande vivement de vous documenter sur le sujet, cela vous sera très utile !

 

En conclusion

Je n’utilise pas toutes ces techniques en même temps. J’adapte en fonction du problème rencontré et du délai de résolution. Par exemple, au début, je ne note rien ni ne m’inquiète de créer une branche spécifique. Au bout d’un moment, 1/2h à 1h par exemple, je vais commencer à prendre des notes et versionner ce que je fais. Restez souples et combinez ces techniques intelligemment en fonction de votre contexte. Et, comme toujours, c’est en forgeant que l’on devient forgeron. Ne vous dites pas que si vous mettez du temps à résoudre ce problème, ou si vous avez un problème, c’est que vous n’êtes pas compétent. Nous rencontrons tous de nombreux problèmes techniques, et c’est tant mieux, car c’est ce qui nous permet d’apprendre ! J’ai maintenant 18 ans d’expérience en développement web, et j’ai encore régulièrement des problèmes à solutionner. C’est normal !
Et vous, avez-vous d’autres techniques à ajouter à cette liste ? Avez-vous vécu une expérience où une de ces techniques vous a aidé à trouver la solution ?

 

Crédits photo :

Partager l'article
  •  
  •  
  •  
  •  

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.