Chapitre 5.4.11Les erreurs

Comprendre ce qui se passe quand ça plante.

5 minutes de lecture

Les bugs font partie du quotidien des développeurs. Comprendre comment ils se manifestent et comment on les identifie te permettra de mieux collaborer avec les équipes techniques quand quelque chose ne fonctionne pas.

Les types d'erreurs

Toutes les erreurs ne se valent pas. On les classe en grandes familles :

Les erreurs de syntaxe

C'est l'équivalent d'une faute de grammaire. Le programme refuse de se lancer parce qu'il ne comprend pas ce qu'on lui a écrit.

Erreur de syntaxe
// Il manque la parenthèse fermante
if (age >= 18 {
    console.log("Majeur")
}
// SyntaxError: Unexpected token '{'

Ce sont les erreurs les plus faciles à corriger. L'éditeur de code les souligne en rouge avant même qu'on exécute le programme, et le message dit exactement où se trouve le problème.

Les erreurs d'exécution

Le code est bien écrit, mais quelque chose se passe mal au moment où il tourne. C'est comme une recette de cuisine correctement rédigée, mais tu te rends compte en la suivant qu'il te manque un ingrédient.

Erreur d'exécution
let client = null
console.log(client.email)
// TypeError: Cannot read properties of null (reading 'email')

Ici, on essaie de lire l'email d'un client qui n'existe pas (null). Le programme plante avec un message d'erreur. C'est le type d'erreur le plus courant dans le développement web.

Côté visiteur, ça ne ressemble jamais à ça. Une erreur d'exécution sur un site, c'est une page blanche, un message générique "une erreur est survenue", ou une page marquée 500, ce fameux code que nous détaillons dans le chapitre sur les codes HTTP. Le détail technique, lui, reste dans les journaux du serveur, et c'est très bien ainsi.

Les erreurs qu'on a prévues

Toutes les erreurs ne sont pas des bugs. Une commande refusée parce que le stock est vide, un formulaire rejeté parce que l'email est mal formé, un virement bloqué parce que le plafond est atteint, ce sont des règles métier qui font leur travail. Le code les a prévues, il affiche un message compréhensible et s'arrête proprement.

La distinction compte quand on discute avec l'équipe technique. "Le paiement a échoué" peut désigner un bug ou une règle qui a fonctionné, et le traitement n'est pas du tout le même.

Un site ne doit jamais montrer à l'utilisateur le message technique brut ni la stack trace dont nous parlons plus bas. Ils révèlent la version des outils utilisés et l'organisation interne du code, exactement ce qu'un attaquant cherche à connaître. Si tu vois ce genre d'écran sur ton propre site, signale-le, c'est un problème de sécurité avant d'être un problème d'esthétique.

Les erreurs de logique

Les plus vicieuses. Le programme tourne sans planter, mais il fait la mauvaise chose. Pas de message d'erreur, pas de crash, juste un résultat faux.

Erreur de logique
function calculerRemise(prix, pourcentage) {
    return prix + prix * pourcentage / 100  // + au lieu de -
}

console.log(calculerRemise(100, 20))  // 120 au lieu de 80

Le programme est content, il ne plante pas. Mais les clients paient plus cher au lieu de moins cher. Ce genre d'erreur peut passer inaperçu pendant des semaines si personne ne vérifie les résultats. C'est exactement ce que les tests automatisés, que nous verrons dans un prochain chapitre, servent à attraper, en vérifiant que le programme produit bien les valeurs attendues.

Le message d'erreur

Quand un programme plante, il produit un message d'erreur. Apprendre à le lire, c'est déjà la moitié du travail de débogage.

Un message d'erreur contient généralement :

  • Le type d'erreur : TypeError, SyntaxError, ReferenceError... Le nom donne déjà un indice sur la nature du problème.
  • La description : un texte en anglais qui explique ce qui s'est passé. Par exemple, "Cannot read properties of null" signifie qu'on a essayé d'accéder à quelque chose sur une variable vide.
  • L'emplacement : le fichier et le numéro de ligne où l'erreur s'est produite.
Un message d'erreur typique
TypeError: Cannot read properties of null (reading 'email')
    at envoyerConfirmation (commandes.js:42)
    at traiterCommande (commandes.js:18)
    at main (index.js:7)

La stack trace

Les lignes qui suivent le message d'erreur forment ce qu'on appelle la "stack trace" (trace de la pile d'exécution). C'est le chemin que le programme a suivi jusqu'au moment du crash.

Dans l'exemple ci-dessus, on lit de bas en haut : le programme a démarré dans main (fichier index.js, ligne 7), qui a appelé traiterCommande (commandes.js, ligne 18), qui a appelé envoyerConfirmation (commandes.js, ligne 42), et c'est là que ça a planté.

C'est exactement comme remonter le fil d'un accident, "la voiture a freiné parce que le feu est passé au rouge parce qu'il y avait un piéton sur le passage". La stack trace raconte l'histoire en sens inverse.

Quand tu signales un bug à un développeur, le plus utile que tu puisses lui donner, c'est le message d'erreur complet avec la stack trace. Une capture d'écran qui montre juste "une erreur s'est produite" sans le détail, ça oblige le développeur à reproduire le problème de son côté, ce qui peut prendre des heures.

Les erreurs silencieuses

Certaines erreurs ne font pas planter le programme. Elles passent inaperçues et causent des comportements étranges, une page qui affiche des données vides, un calcul qui retourne un résultat bizarre, un email qui ne part jamais.

C'est souvent le résultat d'une mauvaise gestion de l'absence de valeur. On a vu dans le chapitre sur les variables que null et undefined représentent le vide. Quand le code ne prévoit pas ces cas, il ne plante pas toujours. Il continue avec des données manquantes et produit un résultat incomplet ou faux.

Exemple :

Un formulaire d'inscription ne rend pas le champ "téléphone" obligatoire. Le code qui génère la facture essaie d'afficher le numéro de téléphone du client. Au lieu de planter, il affiche "undefined" sur la facture. Personne ne s'en rend compte pendant 3 mois, jusqu'à ce qu'un client mécontent appelle.

En production, personne ne regarde l'écran des visiteurs. Ce sont des outils dédiés qui collectent ces erreurs silencieuses ou bruyantes, les regroupent et préviennent l'équipe, comme nous le verrons dans le chapitre sur le monitoring et les logs. Sans eux, c'est le client mécontent qui joue ce rôle, avec trois mois de retard.

Quand tu croises une erreur

La prochaine fois qu'un collègue ou un utilisateur te montre une erreur, tu sauras maintenant la décrypter. Cherche le type d'erreur et la description, ils te disent ce qui s'est passé. Regarde la stack trace, elle te dit où ça s'est passé. Et même si tu ne comprends pas tout, tu peux transmettre ces informations à un développeur, ce qui lui fera gagner un temps précieux.

Bien signaler un bug

C'est probablement la compétence la plus utile de tout ce chapitre, et elle ne demande aucune notion de programmation. Un bug bien décrit se corrige dans l'heure, un bug mal décrit se discute pendant trois jours.

  • Les étapes pour le reproduire : "je me connecte, j'ajoute le produit 4521 au panier, je choisis la livraison en point relais, je clique sur payer". Pas "le paiement ne marche pas".
  • Ce que tu attendais, et ce qui s'est passé : les deux, séparément.
  • Le contexte : quand, sur quel navigateur ou quel téléphone, avec quel compte ou quel numéro de commande. Un bug qui n'arrive que sur Safari ou que pour les clients professionnels est à moitié résolu quand on le sait.
  • Le message d'erreur complet : une capture d'écran, ou mieux, le texte copié.

"Ça marche chez moi" n'est pas de la mauvaise foi. Le développeur teste sur sa machine, avec ses données et sa connexion, et le bug n'existe parfois que chez un client, avec son historique et son navigateur. C'est précisément pour réduire cet écart que les chapitres sur les environnements et sur Docker existent. Plus ton rapport est précis, plus l'écart se comble vite.

Qualifier et prioriser

Tous les bugs ne se valent pas, et c'est souvent à toi qu'il revient de le dire. Bloquant quand personne ne peut plus payer, majeur quand une fonctionnalité importante échoue pour une partie des clients, mineur quand un libellé est mal aligné. Cette gravité décide de ce qui se corrige dans l'heure et de ce qui attend la prochaine version.

Reste une frontière qui fait débat dans toutes les équipes, celle entre un bug et une évolution. Un bug, c'est un comportement contraire à ce qui avait été demandé. Une évolution, c'est un comportement conforme à ce qui avait été demandé, mais qu'on aimerait différent. Les deux sont légitimes, ils ne se traitent pas dans la même file, et confondre les deux est la source de friction numéro un entre produit et technique.

Et maintenant

Tu sais lire du code, tu sais lire une erreur. Il reste un dernier sujet avant de refermer cette initiation, et c'est sans doute celui qui pèse le plus lourd au quotidien, puisque la majeure partie du code qui fait tourner une application n'a jamais été écrite par l'équipe qui la maintient. Nous allons parler des frameworks et des bibliothèques.

PrécédentLes principes SOLID Tous les chapitres SuivantFrameworks et bibliothèques