J'ai vu trop d'ingénieurs perdre des heures (voire des jours) sur des bugs qu'ils auraient pu résoudre en 20 minutes. Leur erreur ? Se jeter directement dans le code, poser des breakpoints au hasard, ajouter des console.log partout, et espérer tomber sur le problème.
Spoiler : ça ne marche pas. Ou plutôt, ça marche parfois, mais c'est inefficace et frustrant.
Aujourd'hui, je veux partager une approche qui m'a fait gagner un temps fou : suivre la chaîne, de l'extérieur vers l'intérieur.
Quand quelque chose plante, le réflexe de beaucoup de devs c'est :
Le problème avec cette approche ? Tu pars d'hypothèses. Tu penses savoir où est le problème. Et la plupart du temps, tu te trompes.
Résultat : tu passes des heures à débuguer le mauvais endroit.
L'idée est simple : avant de toucher au code, tu analyses ce qui se passe de l'extérieur vers l'intérieur. Tu commences par ce qui est le plus loin du cœur de ton système, et tu remontes progressivement.
Concrètement, ça donne :
Cette approche a un avantage énorme : chaque étape réduit le périmètre de ton investigation. Tu ne cherches plus une aiguille dans une botte de foin, tu sais exactement où regarder.
Ça paraît évident, mais je vois encore des gens débuguer sans avoir clairement défini le problème.
Avant toute chose, pose-toi ces questions :
Si tu ne peux pas répondre clairement à ces questions, tu n'es pas prêt à débuguer. Tu vas partir dans tous les sens.
Si ton système utilise du tracing distribué (OTLP, Datadog APM...), c'est ta meilleure arme.
Une trace te montre exactement le parcours d'une requête à travers tous tes services. Tu vois :
C'est incroyablement puissant. En quelques secondes, tu peux identifier :
J'ai résolu des bugs en production en moins de 5 minutes grâce aux traces, là où sans ça j'aurais passé des heures à deviner.
C'est le moment d'en mettre en place. Sérieusement. L'investissement initial est vite rentabilisé.
En attendant, tu peux te rabattre sur les IDs de corrélation dans tes logs (si tu en as), ou reconstituer le parcours manuellement — mais c'est laborieux.
Les logs, c'est le pain quotidien du debug. Mais encore faut-il savoir les utiliser correctement.
Ne lis pas tous les logs de ta stack. C'est une perte de temps monumentale. Utilise tes outils de recherche :
Les logs se lisent chronologiquement. Tu veux comprendre ce qui s'est passé avant l'erreur, pas seulement l'erreur elle-même.
Souvent, le vrai problème est quelques lignes plus haut : une connexion refusée, un timeout, une valeur inattendue...
Parfois, l'absence de log est plus parlante que les logs eux-mêmes. Si tu t'attends à voir un log et qu'il n'est pas là, c'est que :
Les métriques te donnent une vue d'ensemble de l'état de ton système. Elles répondent à des questions différentes des logs :
C'est le fameux framework RED et USE. Si tu ne connais pas, je te conseille de te renseigner.
Superpose tes métriques avec les déploiements, les changements de config, les incidents externes... Souvent, le coupable devient évident : "Tiens, le taux d'erreur a explosé pile 5 minutes après le déploiement de 14h32."
Ce n'est qu'après avoir fait tout ça que tu devrais ouvrir ton IDE.
À ce stade, tu as normalement :
Maintenant, tu peux lire le code avec un objectif précis. Tu cherches une chose spécifique, pas "le bug quelque part dans 100k lignes".
Le code te permet de valider (ou invalider) tes hypothèses. Si les logs te disent "valeur null reçue", le code te dit pourquoi cette valeur peut être null et ce qui se passe quand elle l'est.
C'est tentant de "refactorer en passant" ou de "corriger un autre truc que j'ai vu". Résiste. Tu es là pour résoudre un problème précis. Note les autres trucs pour plus tard.
Situation : un client signale que certaines de ses requêtes échouent avec une erreur 500.
Étape 1 — Symptômes :
/api/ordersÉtape 2 — Traces : Je récupère un trace ID depuis les logs du client. La trace me montre :
Étape 3 — Logs : Je filtre les logs de l'Inventory Service autour du moment de l'erreur :
ERROR: Connection refused to database replica-2
WARN: Falling back to primary database
ERROR: Query timeout after 30000ms
Étape 4 — Métriques : Je regarde les métriques de l'Inventory Service :
Conclusion : Le déploiement de 7h55 a introduit un bug qui ne ferme pas correctement les connexions DB dans certains cas. Le pool se sature, les nouvelles requêtes timeout.
Temps total : 15 minutes. Sans cette approche méthodique, j'aurais probablement passé des heures à lire du code au hasard.
C'est LA plus grosse erreur. Tu perds un temps fou à chercher au mauvais endroit.
"Depuis quand ça se passe ?" est une question cruciale. Corrèle toujours avec les déploiements, les changements de config, les pics de charge...
Les traces sans les logs, c'est incomplet. Les logs sans les métriques, c'est du tunnel vision. Utilise tout ce que tu as.
Si tu ne peux pas reproduire le problème, tu ne peux pas valider ta solution. Investis du temps pour trouver un cas reproductible.
"J'ai ajouté un try/catch et ça marche maintenant." Non. Tu as caché le problème, pas résolu. Comprends la cause racine.
Débuguer intelligemment, c'est une compétence qui s'apprend. Et la clé, c'est la méthode.
Commence par l'extérieur : les symptômes, les traces, les logs, les métriques. Chaque étape réduit le périmètre. Quand tu arrives au code, tu sais exactement ce que tu cherches.
Cette approche m'a fait gagner des centaines d'heures. Elle fera pareil pour toi.
La prochaine fois que quelque chose plante, résiste à l'envie d'ouvrir l'IDE immédiatement. Respire, ouvre tes dashboards, et suis la chaîne.