Comment réduire le nombre de bugs lors du codage?


30

Personne n'est parfait, et quoi que nous fassions, nous allons produire de temps en temps du code contenant des bogues. Quelles sont certaines méthodes / techniques pour réduire le nombre de bogues que vous produisez, à la fois lors de l'écriture de nouveaux logiciels et de la modification / maintenance du code existant?


Une bonne méthode consiste à faire plus de conception initiale (pas trop, mais suffisamment pour rendre votre code plus structuré et plus facile à comprendre).
Giorgio

Connexes: Existe
moucher

Réponses:


58

Évitez le codage de fantaisie. Plus le code est compliqué, plus il y a de bogues. Habituellement, sur les systèmes modernes, un code clairement écrit sera rapide et assez petit.

Utilisez les bibliothèques disponibles. Le moyen le plus simple de ne pas avoir de bogues lors de l'écriture d'une routine utilitaire est de ne pas l'écrire.

Apprenez quelques techniques formelles pour les choses les plus compliquées. S'il y a des conditions compliquées, clouez-les avec un stylo et du papier. Idéalement, connaissez certaines techniques de preuve. Si je peux prouver que le code est correct, il est presque toujours bon, sauf pour les gros bugs, stupides et évidents, faciles à corriger. Évidemment, cela ne va que jusqu'à présent, mais parfois vous pouvez formellement raisonner sur des choses petites mais compliquées.

Pour le code existant, apprenez à refactoriser: comment apporter de petites modifications dans le code, souvent à l'aide d'un outil automatisé, qui rendent le code plus lisible sans changer le comportement.

Ne faites rien trop vite. Prendre un peu de temps à l'avance pour bien faire les choses, pour vérifier ce que vous avez fait et pour réfléchir à ce que vous faites peut être rentable plus tard.

Une fois que vous avez écrit le code, utilisez ce que vous avez pour le rendre bon. Les tests unitaires sont excellents. Vous pouvez souvent écrire des tests à l'avance, ce qui peut être une excellente rétroaction (si cela est fait de manière cohérente, il s'agit d'un développement piloté par les tests). Compilez avec les options d'avertissement et faites attention aux avertissements.

Demandez à quelqu'un d'autre de regarder le code. Les révisions de code formelles sont bonnes, mais elles peuvent ne pas être à un moment opportun. Les requêtes Pull, ou similaire si votre scm ne les prend pas en charge, permettent des révisions asynchrones. La vérification des contacts peut être un examen moins formel. La programmation par paires garantit que deux paires d'yeux regardent tout.


x2 - ce que Ryan a dit.
JBRWilkinson

2
aussi la plupart des langues peuvent être plus ou moins pointilleuses. Vous voulez que ce soit aussi difficile que possible.

1
"Apprenez quelques techniques formelles pour les choses les plus compliquées." ... par exemple?
Dan Rosenstark

1
@Yar: J'attends quelque chose comme les systèmes expliqués dans ce livre: amazon.com/Verification-Sequential-Concurrent-Programs-Computer/… ; même si je dois dire qu'un livre spécifique est extrêmement sec et terne, il y en a probablement beaucoup mieux (mais c'est le seul que j'ai lu).
Joeri Sebrechts

30

Les tests unitaires vous permettent de réduire le nombre de bogues qui apparaissent une deuxième fois. Si vous trouvez un bogue dans votre code, l'écriture d'un test unitaire fera en sorte qu'il ne revienne pas plus tard. (De plus, il est parfois difficile de penser à tous les cas et d'écrire des milliers de tests unitaires à l'avance)


3
«Penser à tous les cas à l'avance» conduit à des interfaces propres et entièrement spécifiées, ce qui ne peut être qu'une bonne chose. Les tests unitaires ne sont difficiles à écrire que si vous les adaptez à du code qui n'a pas été conçu en pensant aux tests.
Mike Seymour

1
Si vous le pouvez, vous devriez. Malheureusement, dans la plupart des cas, j'ai vu les tests unitaires comme quelque chose qui coûte plus cher que "corriger les bugs très rapidement". Donc, si vous le pouvez, alors vous devriez écrire des tests à l'avance, mais si ce n'est pas considéré comme "rentable", alors les écrire avec les corrections de bogues vous aide à le construire au fil du temps sans consacrer trop de budget à l'écriture de tests unitaires .
Ryan Hayes

4
"Les tests montrent la présence, pas l'absence de bugs." - E. Dijkstra. Cela dit, les tests automatisés sont certainement un moyen très utile de maintenir et d'augmenter la qualité des logiciels.
limist

9

+1 sur les deux commentaires de test unitaire.

Au-delà de cela, définissez le niveau d'avertissement le plus élevé proposé par votre compilateur et assurez-vous que les avertissements sont traités comme des erreurs. Les bogues se cachent souvent dans ces erreurs "erronées".

De même, investissez dans des outils d'analyse statique qui s'exécutent au moment de la compilation (je les considère comme un niveau supplémentaire d'avertissements du compilateur).


+1 pour le commentaire d'analyse statique. Il est inestimable d'obtenir toutes ces informations gratuitement :)
Morten Jensen

9

En plus de ce qui a été mentionné:

  • N'ignorez pas les codes d'erreur - par exemple, ne présumez pas que vous avez obtenu un résultat valide, qu'un fichier a été créé avec succès, etc ... Parce qu'un jour, quelque chose se produira.
  • Ne présumez pas que votre code n'entrera jamais dans une condition et que par conséquent "il est sûr d'ignorer cette condition".
  • Testez votre code, puis faites-le tester par quelqu'un d'autre. Je trouve que je suis la pire personne à tester mon propre code.
  • Faites une pause, puis relisez votre code et voyez si vous "avez manqué l'évidence". Ça m'arrive souvent.

Beaucoup d'autres choses que j'oublie en ce moment, mais les autres y penseront sûrement. :)


7
Et si vous êtes si sûr que la condition X ne se produira jamais ... utilisez une assertion pour vous assurer que lorsque la condition X se produira , vous en serez informé (par le biais d'une exception, ou de la journalisation, ou autre).
Frank Shearar

@MetalMikester: Les tests unitaires sont bons. Mais avec des langages de haut niveau et de bonnes bibliothèques, la plupart des bogues durs nécessitent des tests d'intégration et de régression pour être cloués.
Vecteur

9

J'ai développé un style de programmation assez fonctionnel, bien que mes langages principaux soient C ++ et Python. J'ai trouvé que si je transmettais tout le contexte à une fonction (ou méthode) dont cette fonction a besoin pour faire son travail et que je renvoie les données significatives que je recherche, mon code est devenu beaucoup plus robuste.

L'état implicite est l'ennemi et d'après mon expérience, c'est la source n ° 1 de bugs. Cet état peut être des variables globales ou des variables membres, mais si les résultats dépendent de quelque chose qui n'est pas passé à la fonction que vous demandez des problèmes. De toute évidence, il n'est pas possible d'éliminer l'état, mais sa minimisation a d'énormes effets positifs sur la fiabilité du programme.

J'aime aussi dire à mes collègues que chaque branche (si, pendant, alors? :) est un bug probable. Je ne peux pas dire quelle sera la manifestation du bogue, mais moins le comportement de votre code est conditionnel, plus il est probable qu'il soit exempt de bogues simplement parce que la couverture du code pendant l'exécution sera plus cohérente.

Allez comprendre, toutes ces choses ont également des effets positifs sur les performances. Gagner!


D'après mon expérience, il peut devenir rapidement fastidieux de faire circuler tout l'état pour chaque appel, si les méthodes sont aussi petites qu'elles devraient l'être. Ce problème peut être résolu en utilisant de nombreuses petites classes immuables avec des durées de vie d'objet courtes. De cette façon, vous pouvez stocker l'état temporaire en tant que champs et supprimer l'objet lorsque vous n'en avez plus besoin. :-)
Jørgen Fogh

Une autre considération pour ce cas où cela devient fastidieux est que vous essayez peut-être de faire passer trop d'état. :)
dash-tom-bang

Dans de nombreux cas, c'est vrai, mais ce n'est souvent pas le cas. Dans certains domaines, vous devez avoir accès à de nombreux états, même si vous n'avez pas beaucoup d' état mutable . Je travaille actuellement sur un générateur de code où j'ai besoin d'accéder à plusieurs tables de symboles. Je ne veux pas les transmettre à chaque méthode.
Jørgen Fogh

8
  • Écrivez moins de code qui en fait plus.
  • Pensez aux implications de bas niveau et aux ramifications de haut niveau
  • Contemplez l'abstraction que vous créez dans votre code.
  • Si possible, n'écrivez que la complexité essentielle.

J'allais écrire un gros article qui se résume à "écrire moins qui fait plus" (IOW connaît et utilise les outils à votre disposition). Je vais juste attribuer +1 à cela à la place.
Kaz Dragon

1
Mais attention à ne pas obtenir de code sophistiqué lorsque vous essayez d'obtenir moins de code.
gablin

1
@gablin: la fantaisie est dans l'œil du spectateur à bien des égards. Je peux écrire et lire du code aujourd'hui que j'aurais été stupéfait il y a 4 ans. Aujourd'hui, Haskell me plaît. :)
Paul Nathan

8

Une réponse un peu moins technique: ne programmez pas lorsque vous êtes fatigué (9h / jour suffisent), ivre ou «cuit». Quand je suis fatigué, je n'ai pas la patience requise pour écrire du code propre.


2
La plupart des programmeurs mettent généralement plusieurs années à réaliser cela. C'est un point important.
Jeff Davis

7

Rédiger des tests unitaires et des tests d'intégration .


5

Quelques bonnes réponses ici concernant les tests unitaires et les outils. La seule chose que je peux y ajouter est la suivante:

Impliquez vos testeurs le plus tôt possible

Si vous avez une équipe de test, ne tombez pas dans le piège de les traiter comme les gardiens de la qualité de votre code et d'attraper vos défauts pour vous. Au lieu de cela, travaillez avec eux et impliquez-les le plus tôt possible (sur les projets agiles, ce sera dès le début du projet, mais nous pouvons toujours trouver des moyens de les impliquer plus tôt si nous essayons vraiment).

  • Découvrez quel est leur plan de test. Passez en revue leurs cas de test avec eux - les couvrez-vous tous avec votre code?
  • Demandez-leur leur compréhension des exigences. Est-ce la même que la vôtre?
  • Donnez-leur les premières versions de travail pour effectuer des tests exploratoires - vous serez étonné des améliorations qu'ils suggéreront.

Avoir une bonne relation de travail avec vos testeurs signifie que vous pouvez détecter très tôt les mauvaises hypothèses et les défauts, avant qu'ils ne puissent faire de dégâts. Cela signifie également que les testeurs se sentent autorisés à aider à la conception du produit et à détecter les problèmes d'utilisabilité lorsqu'il est temps de les résoudre.


4

Outils d'analyse statique

Les plugins et les applications comme FindBugs explorent votre code et trouvent des endroits où il y a des bogues potentiels . Les endroits où les variables ne sont pas initialisées et utilisées ou tout simplement des choses folles qui 9 fois sur 10, facilitent considérablement l'apparition de bogues. Des outils comme celui-ci m'aident à empêcher que ma tête osseuse ne bouge sur la route même si ce n'est pas encore un bug.

PS: N'oubliez pas de toujours rechercher pourquoi un outil vous dit que quelque chose ne va pas. Jamais mal à apprendre (et tout ne va pas bien dans toutes les situations).


3

Inspection de code ou autres formes d'examen par les pairs comme la programmation de paires.

Les examens de code structurés tels que l'inspection Fagan peuvent être au moins aussi efficaces et efficients que les tests unitaires et se sont même révélés meilleurs que les tests unitaires dans certains cas. Les inspections peuvent également être utilisées plus tôt dans le cycle de vie du logiciel et avec des artefacts autres que le code.

Peer Reviews in Software de Karl Wiegers est un excellent livre sur ce sujet.


2

En plus de toutes les autres suggestions ici, activez tous les avertissements possibles au plus haut niveau de sensibilité et traitez-les comme des erreurs. Utilisez également les outils de peluchage de la langue.

Vous seriez étonné de voir combien d'erreurs simples peuvent être détectées par des avertissements et combien de ces choses simples se traduisent par de vrais bogues dans votre code.


2

Beaucoup de bonnes réponses ici, mais quelques choses que je voulais ajouter. Assurez-vous de bien comprendre l'exigence. J'ai vu beaucoup de bugs lorsque l'utilisateur pensait que l'exigence signifiait X et que le programmeur pensait que cela signifiait Y. Repoussez pour obtenir des éclaircissements sur les exigences médiocres ou ambiguës. Je sais que nous aimons tous intervenir et coder, mais plus vous passerez de temps à assurer la compréhension, moins il y aura de retouches et de corrections de bogues.

Apprenez à connaître l'entreprise que vous soutenez, vous verrez souvent des choses dans les exigences qui manquent ou nécessitent des explications supplémentaires. Sachez que si vous effectuez la tâche Y comme indiqué, cela cassera la fonctionnalité Z existante.

Comprenez la structure de votre base de données. De nombreux bogues résultent d'une requête syntaxiquement correcte, mais qui renvoie des résultats incorrects. Apprenez à reconnaître quand vos résultats sont amusants. Si j'écris une requête de rapport complexe, je demande toujours à un spécialiste technique d'examiner mes résultats avant de le marquer comme prêt à l'emploi, ils verront inévitablement quelque chose dans les données que j'ai manquées. Ensuite, prenez note de ce qu'ils ont attrapé et souvenez-vous que la prochaine fois que vous ferez quelque chose de similaire.


1

Je pense que la technique la plus importante est de prendre son temps . Si vous sentez que vous avez besoin de deux jours pour coder un nouveau module, mais que votre patron vous oblige à coder en une seule journée ... votre code sera probablement plus bogué.

Un des livres que j'ai lu il y a quelque temps, disait que vous ne devriez pas vivre avec des fenêtres cassées , parce que les gens ne se soucient pas si quelqu'un se casse ... Le codage est le même, tout le monde se souciera d'être le premier à faire quelque chose de mal mais rapide , mais aucun ne se souciera d'un code infernal , avec beaucoup de bugs, et un design et un style très pauvres.


1

Je suis la pratique de Test-Code-Test au lieu de Code-test-code-test. Cela m'aide à penser aux cas d'utilisation et à cadrer la logique de manière appropriée


1

Utilisez des outils d'inspection de code comme ReSharper ou des IDE comme IntelliJ IDEA qui mettent en garde contre de nombreux bugs de copier-coller et autres en indiquant par exemple des variables qui sont "écrites mais jamais lues". Cela m'a fait gagner beaucoup de temps.


1

Étonnamment, les trois points très importants suivants n'ont pas encore été mentionnés:

  • Utilisez les assertions généreusement. La question que vous devriez toujours vous poser n'est pas "devrais-je affirmer cela?" mais "y a-t-il quelque chose que j'ai oublié d'affirmer?"

  • Optez pour l'immuabilité. (Utilisez libéralement final / en lecture seule.) Moins vous avez d'état mutable, moins les choses peuvent mal tourner.

  • N'optimisez pas prématurément. De nombreux programmeurs sont confrontés à des problèmes de performances, ce qui les oblige à compliquer inutilement leur code et à bâtir leurs conceptions sans même savoir à l'avance si les performances vont être un problème. Tout d'abord, construisez votre produit logiciel de manière académique, sans tenir compte des performances; ensuite, voyez si cela fonctionne mal; (Ce ne sera probablement pas le cas.) S'il y a des problèmes de performances, allez trouver le ou les deux endroits où vous pouvez fournir des optimisations algorithmiques agréables et formelles qui permettront à votre produit de répondre à ses exigences de performances au lieu de modifier et de pirater l'intégralité de votre base de code pour presser des cycles d'horloge ici et là.

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.