Quel processus utilisez-vous normalement lorsque vous tentez de déboguer un problème / problème / bogue avec votre logiciel? [fermé]


15

La plupart des gens semblent considérer le débogage comme un art plutôt que comme une science. Pour ceux qui le traitent ici comme une science plutôt que comme un art - quel (s) processus utilisez-vous normalement face à un nouveau problème / bug / problème?

Réponses:


13

En termes très généraux, ce que je fais est:

  1. Essayez d'isoler le problème. Pensez à ce qui a changé lorsque le bogue est apparu pour la première fois. Sur quoi travaillez-vous? Quelle partie du code modifiez-vous? 99% de mes bugs sont résolus de cette façon. C'est généralement quelque chose de stupide.

  2. Si je devine où est le problème, jetez un œil au code qui semble être la cause. Lis le. Lisez-le à haute voix même. Demandez-vous: "Qu'est-ce que j'essaie de réaliser?". Pour certains types de problèmes: pourrait-il avoir des effets secondaires ou pourrait-il être affecté par du code à un autre endroit d'une manière à laquelle je n'avais pas pensé?

  3. Essayez de différentes manières d'analyser ce qui ne va pas, où et quand (voir ci-dessous).

  4. Si je n'ai toujours aucun indice, je vérifie si une ancienne version de ma source a le même problème, essayez de trouver quand dans ma chronologie de développement le problème est apparu pour la première fois. Pour ce faire, vous devez travailler avec un bon système de contrôle de version, tel que git (git a une fonctionnalité appelée bissect exactement pour ce type de débogage).

  5. Si vous n'avez toujours aucun indice, faites une pause ... cela aide souvent.

  6. Revenez à la planche à dessin - examinez comment votre programme est censé fonctionner et si cela a du sens.

Cela dépend vraiment du type de problème, mais en supposant que j'ai une idée générale de l'endroit où le problème pourrait être, alors:

  • Si je soupçonne que le problème est dans une partie du code / modification récente, j'essaie d'abord de supprimer / commenter / modifier ou quoi que ce soit pour faire disparaître le bogue en simplifiant le code, puis ramener le code problématique et prendre un bon coup d'oeil.

  • Exécutez un débogueur avec des points d'arrêt (si possible) et regardez comment mes données semblent essayer de trouver quand elles commencent à mal fonctionner, pour avoir une meilleure idée de l'endroit où les choses tournent mal.


1
+1 pour faire une pause. Les problèmes les plus difficiles ne deviennent plus difficiles que lorsque vous êtes frustré et lors de votre 6ème heure de débogage. Savoir quand faire une pause est l'une des compétences de débogage les plus utiles que j'ai acquises.
Brad Gardner

Réponse géniale. Je ne peux pas faire mieux.
EricBoersma

1
Tout comme mon approche, mais vous avez oublié le peu où vous demandez à un collègue de jeter un coup d'œil et ils remarquent instantanément l'erreur d'orthographe ...
ChrisAnnODell

1
Excellente réponse. Je veux juste ajouter qu'une once de prévention vaut mieux que guérir. Une grande partie de mon processus de débogage est pendant que je code en premier lieu, je ne fais que de petites modifications incrémentielles et je compile, teste et valide localement entre chacun. De cette façon, si un bogue apparaît soudainement, la liste des suspects probables est très petite et facile à voir avec une bzr qdiffcommande.
Karl Bielefeldt

8

J'essaie d'utiliser le développement piloté par les tests ( TDD ). J'écris un test qui reproduit le bogue, puis j'essaie de réussir le test. Parfois, le fait d'écrire le test aide à trouver le bogue.

Cela me tient hors du débogueur la plupart du temps et fournit des tests de régression pour éviter de réintroduire le bogue.

Quelques liens:


4
Je pense que cette réponse est extrêmement incomplète. Je ne comprends pas autant de votes positifs.
Alex

1
Il obtient seulement autant de votes positifs car il comprend l'acronyme magique: TDD.
Bjarke Freund-Hansen

@Alex - J'ai ajouté quelques liens. Celui "Trouver un BUG, ​​écrire un test" a un exemple. Je peux développer cela, mais c'est vraiment aussi simple que cela.
TrueWill

7

Il existe un certain nombre de définitions du mot science, mais il semble que vous vous référiez peut-être à ce que l'on pourrait appeler plus précisément la " méthode scientifique ". La méthode scientifique peut être résumée comme l'observation de certains phénomènes (vraisemblablement un bug ou un comportement de programme inattendu), la formulation d'une ou de plusieurs hypothèses pour expliquer le comportement, et l'expérimentation la plus probable pour le prouver (écrire un test qui reproduit le problème de manière fiable).

Les types de bugs (phénomènes) qui peuvent survenir sont pratiquement infinis et certains ne nécessitent pas nécessairement un processus bien défini. Par exemple, parfois vous observez un bogue et vous savez instantanément ce qui l'a causé simplement parce que vous êtes très familier avec le code. D'autres fois, vous savez qu'à partir d'une certaine entrée (action, série d'étapes, etc.), un résultat incorrect se produit (plantage, mauvaise sortie, etc.). Pour ces cas, cela ne nécessite souvent pas beaucoup de réflexion "scientifique". Une réflexion peut aider à réduire l'espace de recherche, mais une méthode courante consiste simplement à parcourir le code dans un débogueur et à voir où les choses ont mal tourné.

Cependant, les situations que je trouve les plus intéressantes et peut-être dignes d'un processus scientifique sont celles où l'on vous remet un résultat final et qu'on vous demande d'expliquer comment cela s'est produit. Un exemple évident de ceux-ci est un vidage sur incident. Vous pouvez charger le vidage sur incident et observer l'état du système et votre travail consiste à expliquer comment il est arrivé dans cet état. Le vidage sur incident (ou principal) peut afficher une exception, un blocage, une erreur interne ou un état "indésirable" tel que défini par l'utilisateur (par exemple, lenteur). Pour ces situations, je suis généralement suivre les étapes suivantes:

  • Observation étroite : Étudiez les informations entourant directement le problème spécifique, le cas échéant. Les choses évidentes ici sont la pile d'appels, les variables locales si vous pouvez les voir, les lignes de code entourant le problème. Ce type d'étude de localisation spécifique n'est pas toujours applicable. Par exemple, l'étude d'un système "lent" peut ne pas avoir un emplacement de départ évident comme celui-ci, mais une situation de crash ou d'erreur interne aura probablement un point d'intérêt immédiat et évident. Une étape spécifique ici pourrait être d'utiliser des outils tels que windbg (exécutez! Analyse -v sur un vidage sur incident chargé et regardez ce qu'il vous dit).

  • Large observation : étudiez d'autres parties du système. Examinez l'état de tous les threads du système, examinez toutes les informations globales (nombre d'utilisateurs / opérations / éléments, transactions / processus / widgets actifs, etc.), les informations du système (OS), etc. Si l'utilisateur a fourni des détails externes , pensez à ceux-ci en conjonction avec ce que vous avez observé. Par exemple, s'ils vous ont dit que le problème se produit tous les mardis après-midi, demandez-vous ce que cela pourrait signifier.

  • Hypothétiser: C'est la partie vraiment amusante (et je ne suis pas gênant que ce soit amusant). Cela nécessite souvent beaucoup de réflexion logique à l'envers. Il peut être très agréable de penser à la façon dont le système est entré dans son état actuel. Je soupçonne que c'est la partie que beaucoup de gens considèrent comme un art. Et je suppose que cela pourrait être si le programmeur commence simplement à lancer des choses au hasard pour voir ce qui colle. Mais avec l'expérience, cela peut être un processus assez bien défini. Si vous pensez très logiquement à ce stade, il est souvent possible de définir des ensembles possibles de chemins qui ont conduit à l'état donné. Je sais que nous sommes dans l'état S5. Pour que cela se produise, S4a ou S4b devait se produire et peut-être S3 avant S4a, etc. Le plus souvent, il peut y avoir plusieurs éléments qui pourraient conduire à un état donné. Parfois, il peut être utile d'écrire sur un bloc-notes un simple diagramme de flux ou d'état ou une série d'étapes liées au temps. Les processus réels ici varieront considérablement en fonction de la situation, mais une réflexion sérieuse (et un réexamen dans les étapes précédentes) à ce stade fournira souvent une ou plusieurs réponses plausibles. Notez également qu'une partie extrêmement importante de cette étape consiste à éliminer les choses impossibles. Supprimer l'impossible peut aider à réduire l'espace de la solution (rappelez-vous ce que Sherlock Holmes a dit sur ce qui reste après avoir éliminé l'impossible). Notez également qu'une partie extrêmement importante de cette étape consiste à éliminer les choses impossibles. Supprimer l'impossible peut aider à réduire l'espace de la solution (rappelez-vous ce que Sherlock Holmes a dit sur ce qui reste après avoir éliminé l'impossible). Notez également qu'une partie extrêmement importante de cette étape consiste à éliminer les choses impossibles. Supprimer l'impossible peut aider à réduire l'espace de la solution (rappelez-vous ce que Sherlock Holmes a dit sur ce qui reste après avoir éliminé l'impossible).

  • Expérience : Dans cette étape, essayez de reproduire le problème sur la base des hypothèses dérivées à l'étape précédente. Si vous avez réfléchi sérieusement à l'étape précédente, cela devrait être très simple. Parfois, je "triche" et modifie la base de code pour aider un test donné. Par exemple, j'ai récemment enquêté sur un accident dont j'ai conclu qu'il s'agissait d'une condition de course. Afin de le vérifier, j'ai simplement mis un Sleep (500) entre quelques lignes de code pour permettre à un autre thread de faire ses mauvaises choses au "bon" moment. Je ne sais pas si cela est autorisé dans la "vraie" science, mais c'est parfaitement raisonnable dans le code que vous possédez.

Si vous réussissez à le reproduire, il est probable que vous ayez presque terminé (il ne vous reste plus qu'à la réparer ... mais c'est pour un autre jour). Assurez-vous de vérifier le nouveau test dans le système de test de régression. Et je dois souligner que je voulais que cette déclaration précédente sur le fait qu'il soit simple d'être ironique. La recherche d'une solution et sa mise en œuvre peuvent nécessiter un travail important. Je pense que la correction d'un bogue ne fait pas partie du processus de débogage mais est plutôt du développement. Et si le correctif est impliqué, cela devrait nécessiter une certaine conception et une révision.


La plupart des bogues que j'ai vus n'étaient pas reproductibles de manière fiable, et, pour le sous-ensemble qui l'était, la majorité nécessitait encore un travail de débogage important après leur reproduction, avant que tout travail de correction puisse commencer. Même si au lieu de dire "réussir à le reproduire", vous dites "réussir à restreindre un test unitaire qui exerce clairement le bogue", je dirais que le travail de débogage n'est pas terminé. Pour moi, le débogage est terminé une fois que j'ai tous les deux un correctif, je peux prouver qu'il résout le problème, et j'ai une preuve fiable que mon correctif est ce qui résout réellement les choses.
blueberryfields

Je suis d'accord que cela peut demander beaucoup de travail pour le réparer. J'utilisais en effet le sarcasme dans mes mots "simple étape pour le réparer", mais cela ne ressort pas très bien dans le type.

4

Essayez de réduire le cas de test. Lorsqu'il est suffisamment petit, il est généralement plus facile de localiser le code correspondant à l'origine du problème.

Il est probable qu'un nouvel enregistrement soit à l'origine du problème et la version quotidienne précédente était correcte. Dans ce cas, votre journal des modifications du contrôle de code source devrait vous aider à décider qui intercepter.

De plus, si vous êtes en C / C ++, envisagez d'exécuter valgrind ou purifier pour isoler les problèmes liés à la mémoire.


2

La partie la plus difficile du débogage consiste à isoler le problème, en particulier lorsque le problème est enfoui sous plusieurs couches. Au collège, j'ai étudié l'enregistrement de musique et, curieusement, il y avait un cours Studio Electronics qui s'applique directement ici. Je vais utiliser le débogage d'un environnement de studio comme illustration du processus de débogage systématique.

  1. Testez vos compteurs. En utilisant une tonalité de test à une tension calibrée connue, le multimètre doit lire "U" (gain unitaire). Traduction: Si vos outils sont cassés, vous ne pouvez pas les utiliser pour découvrir ce qui ne va pas.
  2. Testez chaque composante / gain en travaillant à l'envers depuis la fin. En utilisant la même tonalité de test appliquée à l'entrée de la scène, il ne devrait y avoir aucun changement à la sortie de la scène. Traduction: En isolant chaque objet de la sortie vers l'arrière, nous renforçons la confiance dans notre code jusqu'à ce que nous trouvions l'endroit où il gâche. S'il faut quelques couches à vos outils pour signaler le problème, vous devez savoir que les couches intermédiaires n'y contribuent pas.

Le débogage du code n'est vraiment pas si différent. Le débogage est beaucoup plus facile lorsque le code lève une exception. Vous pouvez remonter à partir de la trace de pile de cette exception et définir des points d'arrêt à des positions clés. Habituellement, juste après avoir défini une variable, ou sur la ligne qui appelle la méthode qui lève l'exception. Vous pouvez constater qu'une ou plusieurs des valeurs ne sont pas correctes. Si ce n'est pas correct (une valeur nulle alors qu'il ne devrait pas y en avoir, ou la valeur est hors de portée), alors c'est un processus pour découvrir pourquoi ce n'est pas correct. Les points de rupture dans un IDE sont équivalents aux points de test électroniques (conçus pour une sonde de compteur pour vérifier le circuit).

Maintenant, une fois que j'ai traversé cette partie difficile de la découverte de mon vrai problème, je vais écrire des tests unitaires pour vérifier cela à l'avenir.


2

Avec les bugs désagréables que j'ai du mal à retrouver en fin d'après-midi, ma stratégie la plus efficace est de me lever et de partir pendant quelques minutes. Habituellement, de nouvelles idées sur les sources d'erreur possibles commencent à apparaître après seulement 30 secondes.


2

Pour une approche plus pratique:

  1. Si le bogue est lié à une exception non gérée - regardez la trace de la pile. Les références nulles, index hors limites, etc. et vos propres exceptions définies sont les plus courantes, vous pouvez attribuer ce bug à un développeur junior, c'est probablement facile et une bonne expérience d'apprentissage.

  2. Si cela ne se produit pas sur chaque machine, c'est probablement une forme de problème de concurrence / problème de thread. Ce sont super amusants à retrouver, mettez votre programmeur senior ennuyé dessus. Beaucoup de journalisation, de bonnes connaissances et de bons outils y parviennent.

  3. Une autre grande classe de bogues est lorsque l'équipe de test ou le (s) client (s) n'aiment pas un comportement particulier. Par exemple, ils n'aiment pas que vous décidiez d'afficher les ID utilisateur ou que, lors de la recherche, vous n'obteniez pas de saisie semi-automatique. Ce sont de vrais bugs, pensez à avoir une meilleure gestion des produits et des développeurs avec une vue plus large. Cela devrait prendre un temps relativement court à un développeur pour "corriger" cela s'il construit le système en pensant à l'expansion.

  4. 80% de tous les autres bogues sont résolus en ayant un bon système de journalisation et en collectant suffisamment d'informations pour les résoudre. Utilisez le traçage intégré avec plusieurs niveaux de systèmes de journalisation complexes comme Log4Net / Log4J

  5. les bogues de performance sont une catégorie à part, la règle la plus audacieuse ici est «mesurer d'abord, corriger plus tard! plus tard, une simple diminution de 3 à 4% du temps de réponse.


Si je pouvais +1 chacun de ces 5 individuellement, je le ferais!
jmort253

1

J'ai deux approches:

  1. Divisez le problème donné en parties plus petites, puis conquérez chaque partie plus petite en suivant Divide and ConquerParadigm.
  2. Chaque fois que je doute d'une valeur quelconque, j'imprime simplement les valeurs des variables pour voir exactement ce qui entre et sort de la variable.

Ces approches m'ont aidé la plupart du temps.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.