On ne va pas se mentir, la journée type d’un développeur est rythmée par des cafés et des “ça marche pô”.
Et si le dev en question a choisi JS comme langage de programmation, ou de scripting si vous préférez, et bien, ça n'arrange pas les choses.
Mais alors que faire quand “ça marche pô” ?
La technique préférée par les développeurs JS est console.log(‘toto’)
On va spammer notre code malade de console.log(‘toto’) pour vérifier si on rentre bien dans un if ou, de manière générale, si un bout de code est réellement exécuté ou pas.
Il existe pourtant une technique bien plus efficace, mais qui semblerait être peu connue du grand public : l’instruction debugger et l’utilisation des points d'arrêt.
Si ton sourcil s’est levé en mode “uhm, c’est quoi ça ?”, accroche-toi, dans 7 minutes chrono ta vie aura complètement changé :-)
L’instruction debugger
Un exemple va nous aider à comprendre l’utilisation et les avantages de cette instruction, ainsi que la technique du point d'arrêt.
Pour l’occasion j’ai préparé une page web qui nous dit la vérité sur ce fameux debugger, la voici :
Euh… ok… Je ne m’attendais pas à ça…
Bon, on va dire que ça tombe bien, on va déboguer tout ça !
Le code qui donne ce rendu est en VueJs, très basique pour que n’importe qui puisse y trouver ses marques, et il ressemble à ça :
<template>
<main><h1>Hello Blog</h1><h2>L'instruction <code>debugger;</code><b>{{ tellMeAboutIt() }}</b></h2></main></template>
<script>import { theWholeTruth } from'@/theTruth';
exportdefault {
name: 'DebuggerSavedMyLife',
methods: {
/**
* @description Describes the `debugger;` statement
* @returns {string}The truth, the whole truth and nothing but the truth
*/tellMeAboutIt() {
const theTruth = theWholeTruth();
return theTruth;
},
},
}
</script>
Il doit y avoir un problème dans ma méthode tellMeAboutIt(), et c’est fort probable que ça vienne de la fonction que j’appelle à l’intérieur…
Mais tu sais quoi ? Je ne vais pas me prendre la tête, je vais rajouter ma petite instruction comme ça :
L’instruction debugger ne fait rien d’autre que créer un point d’arrêt (breakpoint) pour qu’on puisse arrêter l'exécution de notre script et prendre le temps d'analyser ce qui s'y passe.
C’est une façon d'arrêter le temps à un instant T et fouiller dans le code, un véritable bullet time à la Matrix pendant lequel on peut trouver et buter Le Grand Méchant Bug.
Si on rafraîchit simplement notre page web, on ne verra rien de nouveau… mais si avant de rafraîchir la page on ouvre notre console… it’s bullet time, baby!
Ça y est, le temps s’est arrêté, la console nous montre l’onglet “Sources”, qui contient différents outils pour analyser le code, se déplacer dans l’espace-temps et comprendre d’où vient réellement le problème.
L’onglet Sources en deux mots
Sources nous présente trois sections :
À gauche on retrouve tous les fichiers qui ont été chargés sur la page, y compris les fichiers CSS et HTML, très utile pour naviguer dans la structure de notre application et visualiser/modifier en temps réel chaque fichier.
Au centre on a un focus sur le fichier qui contient le point d’arrêt. La ligne exacte où l'exécution s’est arrêtée est en surbrillance (en vert dans le screenshot).
À droite il y a le panel de débogage, la partie la plus dense et importante qui mérite un aparté.
Le panel de débogage
Résumé des épisodes précédents : le temps s’est arrêté, on est comme Doctor Strange sur une page web qui est totalement congelée et qui ne répond plus.
Le panel de débogage est notre Oeil d'Agamotto, voici un aperçu de ses principaux buttons :
Reprendre l'exécution du script.
Une façon de décongeler l'exécution du script, l’application reprendra son cycle naturel, sauf s'il y a d'autres points d'arrêt, auquel cas l'exécution s'arrêtera à nouveau.
Passer à l’appel de fonction suivant.
Lui, il nous permet d’avancer jusqu'au prochain appel d’une fonction.
Rentrer dans la fonction actuelle.
Si la ligne sur laquelle on s’est arrêté contient un appel à fonction, en cliquant sur ce bouton on sera magiquement téléporté à l'intérieur de cette fonction. Vous allez adorer.
Quitter la fonction actuelle.
À l'inverse, ce bouton nous permet de sortir de la fonction dans laquelle on s’est téléporté.
Étape.
Notre meilleur ami, en cliquant dessus il nous fera avancer dans notre script d’une ligne à la fois, step by step.
Plus en bas dans le panel de débogage, on retrouve plusieurs sections, on va se focaliser sur les sections Scope et Call stack.
La section Scope contient la liste des variables et des fonctions disponibles dans le contexte d'exécution actuel de votre code.
Intéressant de voir que le hoisting de javascript fait que la variable theTruth est déjà disponible dans le scope Local, malgré le fait qu’elle n’ait pas encore été initialisée. Mathemagical!
La section Call stack contient la “pile d’appels”, autrement dit l’historique des fonctions appelées qui font qu’on en est là.
La fonction la plus récente est toujours au sommet de la pile.
Ce n’est pas étonnant donc qu'en haut de la pile on retrouve notre tellMeAboutIt, qui est visiblement appelée par des fonctions obscures qui font surement partie du moteur de VueJs (_sfc_render, renderComponenetRoot, blah blah blah, magie noire).
Dans notre exemple la Call stack ne contient rien d’intéressant, mais c’est un outil très puissant qui nous permettrait de “remonter dans le temps” (ce n’est pas tout à fait ça, mais presque) pour analyser ce qui c’est passé dans notre application juste avant d’arriver à notre point d'arrêt.
Ok, on a toutes les armes pour tacler notre bug, on arrête le blah blah et on y go !
Où est le bug ?
Essayons de faire avancer notre script jusqu’à la ligne 19 pour observer les changements de notre panel de débogage.
C’est intéressant de voir que la valeur de la variable theTruth dans la section Scope => Local du panel de débogage est passée de undefined à “ne sert à rien” (super, merci…).
Le bug vient d’ailleurs, il doit se cacher dans la fonction theWholeTruth().
Pas de panique, je vais rafraîchir la page et cette fois-ci inspecter ce qui se passe dans la fonction qui retourne ce résultat maudit : Keep Calm and F5.
Je vais utiliser les actions du panel de débogage pour :
Avancer jusqu’à la ligne qui appelle la fonction que je veux inspecter (ligne 18)
Rentrer dans la fonctiontheWholeTruth() comme un cowboy dans un saloon, flingue à la main.
Essayons:
Intéressant : theWholeTruth() a l’air de faire un simple join sur un array qui semblerait venir d'une autre fonction : nothingButTheTruth().
On sait ce qu’il faut faire, n’est-ce pas ? ;-)
Let’s go!
Voilà… on a trouvé le responsable du bug.
Autant de suspense, et finalement, il s'agissait juste d’un array de mensonges…
Il ne me reste plus qu'à revenir à mon IDE, dénoncer l’array en question pour faux et usage de faux, rétablir l’ordre dans l’univers et…
Conclusion
L’instruction debugger est un moyen de placer des points d'arrêt dans notre code afin de :
pouvoir évaluer des variables à un instant T
rentrer dans les méthodes/fonctions pour en inspecter le contenu
remonter la pile d’appels pour comprendre qui a appelé quoi et comment
Il existe d’autres façons de placer des points d’arrêt et évaluer les variables d’un Scope donné (directement depuis la console du navigateur), mais je laisserai votre curiosité se déchaîner sur l’interweb ;-)
Le temps à notre disposition est fini, j’ai un bug à résoudre qui me casse la tête là, avant de finir la journée…
…heureusement je sais exactement quoi faire pour le dénicher :-)
Goodbye console.log(‘toto’)
Welcome debugger
Auteur(s)
Giuseppe Cunsolo
Développeur JS @ Eleven-Labs
J'aime le punk rock, les tests unitaires, les gens et la bande dessinée.
Découvrez comment créer un Design System solide avec React. Ce guide simplifié explore les bases essentielles pour concevoir une interface cohérente, améliorer le développement et offrir une expérience utilisateur harmonieuse.
Découvrez comment notre Studio a intégré avec succès des composants React et Varnish ESI sur un site No Code. Explorez les défis à relever et les solutions mises en œuvre