J'écris un petit programme simple pour transmettre du MIDI sur un réseau. Je sais que le programme rencontrera des problèmes de transmission et / ou d'autres situations d'exception que je ne pourrai pas prévoir.
Pour la gestion des exceptions, je vois deux approches. Dois-je écrire le programme pour qu'il:
- échoue avec un bang quand quelque chose ne va pas ou
- Faut-il simplement ignorer l'erreur et continuer, au détriment de l'intégrité des données?
À quelle approche un utilisateur pourrait-il raisonnablement s'attendre?
Existe-t-il une meilleure façon de gérer les exceptions?
De plus, ma décision concernant la gestion des exceptions devrait-elle être affectée par le fait que je traite ou non avec une connexion réseau (c'est-à-dire quelque chose où je peux raisonnablement m'attendre à des problèmes)?
exception-handling
Arlen Beiler
la source
la source
Réponses:
Vous ne devez jamais ignorer une erreur que votre programme rencontre. Au strict minimum, vous devez le connecter à un fichier ou à un autre mécanisme pour notification. Il peut y avoir des situations occasionnelles où vous voudrez ignorer une erreur mais la documenter! N'écrivez pas un
catch
bloc vide sans aucun commentaire expliquant pourquoi il est vide.Que le programme échoue ou non dépend beaucoup du contexte. Si vous pouvez gérer l'erreur avec élégance, allez-y. S'il s'agit d'une erreur inattendue, votre programme se bloquera. C'est à peu près la base de la gestion des exceptions.
la source
Vous ne devez jamais ignorer les erreurs en silence, car votre programme est construit sur une série d'actions qui dépendent implicitement de tout ce qui s'est passé avant qu'elles ne se déroulent correctement. Si quelque chose se passe mal à l'étape 3 et que vous essayez de passer à l'étape 4, l'étape 4 commencera sur la base d'hypothèses non valides, ce qui rend plus probable qu'elle finira également par générer une erreur. (Et si vous l'ignorez également, l'étape 5 génère une erreur et les choses commencent à faire boule de neige à partir de là.)
Le fait est que, au fur et à mesure que les erreurs s'accumulent, vous finirez par rencontrer une erreur si grande que vous ne pouvez pas l'ignorer, car elle consistera en quelque chose donné à l'utilisateur, et que quelque chose sera complètement faux. Ensuite, des utilisateurs se plaignent que votre programme ne fonctionne pas correctement et vous devez le corriger. Et si la partie "donner quelque chose à l'utilisateur" se trouve à l'étape 28, et vous ne savez pas que l'erreur d'origine qui cause tout ce gâchis était à l'étape 3 parce que vous avez ignoré l'erreur à l'étape 3, vous allez avoir un diable d'un temps de débogage du problème!
D'un autre côté, si cette erreur de l'étape 3 fait tout exploser au visage de l'utilisateur et génère une erreur disant
SOMETHING WENT BADLY WRONG IN STEP 3!
(ou son équivalent technique, une trace de pile), alors le résultat est le même - l'utilisateur se plaignant de vous le programme ne fonctionne pas correctement - mais cette fois, vous savez exactement où commencer à chercher lorsque vous allez le réparer .EDIT: En réponse aux commentaires, si quelque chose se passe mal que vous aviez prévu et savez comment gérer, c'est différent. Par exemple, en cas de réception d'un message mal formé, ce n'est pas une erreur de programme; c'est "l'utilisateur a fourni une mauvaise entrée qui a échoué à la validation". La réponse appropriée est de dire à l'utilisateur qu'il vous donne une entrée non valide, ce qui ressemble à ce que vous faites. Pas besoin de planter et de générer une trace de pile dans un cas comme celui-ci.
la source
Il existe d'autres options entre "exploser" et "ignorer".
Si l'erreur est prévisible et évitable, modifiez votre conception ou refactorisez votre code pour l'éviter.
Si l'erreur est prévisible mais non évitable, mais que vous savez quoi faire lorsqu'elle se produit, détectez l'erreur et gérez la situation. Mais évitez d'utiliser des exceptions comme contrôle de flux. Et vous souhaiterez peut-être enregistrer un avertissement à ce stade, et peut-être informer l'utilisateur s'il peut prendre des mesures pour éviter cette situation à l'avenir.
Si l'erreur est prévisible, inévitable, et lorsque cela se produit, vous ne pouvez rien faire qui garantisse l'intégrité des données, vous devez enregistrer l'erreur et revenir à un état sûr (ce qui, comme d'autres l'ont dit, peut signifier un crash).
Si l'erreur n'est pas quelque chose que vous avez anticipée, vous ne pouvez vraiment pas être sûr que vous pouvez même revenir à un état sûr, il est donc préférable de simplement vous connecter et planter.
En règle générale, ne détectez aucune exception à laquelle vous ne pouvez rien faire, sauf si vous prévoyez simplement de vous connecter et de la relancer. Et dans les rares cas où un try-catch-ignore est inévitable, ajoutez au moins un commentaire dans votre bloc catch pour expliquer pourquoi.
Voir l'excellent article d' Eric Lippert sur la gestion des exceptions pour plus de suggestions sur la catégorisation et la gestion des exceptions.
la source
Voici mes vues sur la question:
Un bon principe de départ est d'échouer rapidement. Plus précisément, vous ne devez jamais écrire de code de gestion des erreurs pour toute défaillance dont vous ne connaissez pas la cause exacte.
Après avoir appliqué ce principe, vous pouvez ajouter du code de récupération pour les conditions d'erreur spécifiques que vous rencontrez. Vous pouvez également introduire plusieurs "états sûrs" pour revenir. L'abandon d'un programme est généralement sûr, mais parfois vous voudrez peut-être revenir à un autre bon état connu. Un exemple est de savoir comment un système d'exploitation moderne gère un programme incriminé. Il arrête uniquement le programme, pas l'ensemble du système d'exploitation.
En échouant rapidement et lentement à couvrir des conditions d'erreur de plus en plus spécifiques, vous ne compromettez jamais l'intégrité des données et vous vous dirigez régulièrement vers un programme plus stable.
Avaler des erreurs, c'est-à-dire essayer de planifier des erreurs dont vous ne connaissez pas la cause exacte et par conséquent n'avez pas de stratégie de récupération spécifique, ne fait que conduire à une quantité croissante de code pour ignorer et contourner les erreurs dans votre programme. Puisqu'on ne peut pas croire que les données précédentes ont été correctement traitées, vous commencerez à voir des contrôles étalés pour les données incorrectes ou manquantes. Votre complexité cyclomatique va déraper et vous vous retrouverez avec une grosse boule de boue.
Que vous soyez ou non au courant des cas d'échec est moins important. Mais si, par exemple, vous traitez avec une connexion réseau pour laquelle vous connaissez un certain nombre d'états d'erreur, retardez l'ajout de la gestion des erreurs jusqu'à ce que vous ajoutiez également un code de récupération. Cela est conforme aux principes énoncés ci-dessus.
la source
Vous ne devez jamais ignorer silencieusement les erreurs. Et surtout pas au détriment de l'intégrité des données .
Le programme essaie de faire quelque chose. Si cela échoue, vous devez faire face au fait et faire quelque chose . La nature de ce quelque chose dépend de beaucoup de choses.
En fin de compte, l'utilisateur a demandé au programme de faire quelque chose et le programme devrait leur dire qu'il n'a pas réussi. Il y a plusieurs façons de le faire. Il peut s'arrêter immédiatement, il peut même annuler les étapes déjà terminées ou d'un autre côté, il peut continuer et terminer toutes les étapes qu'il peut et dire à l'utilisateur que ces étapes ont réussi et que les autres ont échoué.
La façon dont vous choisissez dépend de la façon dont les étapes sont liées et s'il est probable que l'erreur se reproduira pour toutes les étapes futures, ce qui pourrait à son tour dépendre de l'erreur exacte. Si une forte intégrité des données est requise, vous devez revenir au dernier état cohérent. Si vous copiez simplement des fichiers, vous pouvez en ignorer certains et simplement dire à l'utilisateur à la fin que ces fichiers n'ont pas pu être copiés. Vous ne devez pas ignorer les fichiers en silence et ne rien dire à l'utilisateur.
La modification des annonces, la seule différence qui fait que vous devriez envisager de réessayer un certain nombre de fois avant d'abandonner et de dire à l'utilisateur que cela ne fonctionne pas, car le réseau est susceptible d'avoir des erreurs transitoires qui ne se reproduiront pas si vous essayez à nouveau.
la source
Il existe une catégorie de cas où ignorer les erreurs est la bonne chose à faire: lorsqu'il n'y a rien qui puisse être fait à propos de la situation et que des résultats médiocres et éventuellement incorrects valent mieux que pas de résultats.
Le cas du décodage du flux HDMI à des fins d'affichage en est un. Si le flux est mauvais, c'est mauvais, crier dessus ne le réparera pas comme par magie. Vous faites ce que vous pouvez pour l'afficher et laissez le spectateur décider s'il est tolérable ou non.
la source
Je ne crois pas qu'un programme devrait ignorer silencieusement ou causer des ravages chaque fois qu'il rencontre un problème.
Ce que je fais avec les logiciels internes que j'écris pour mon entreprise ...
Cela dépend de l'erreur, disons que s'il s'agit d'une fonction critique qui entre des données dans MySQL, elle doit informer l'utilisateur qu'elle a échoué. Le gestionnaire d'erreurs doit essayer de collecter autant d'informations et fournir à l'utilisateur une idée de la façon de corriger l'erreur lui-même afin qu'il puisse enregistrer les données. J'aime également fournir un moyen de nous envoyer silencieusement les informations qu'ils essaient de sauvegarder, donc si le pire vient au pire, nous pouvons les entrer manuellement après la correction du bogue.
Si ce n'est pas une fonction critique, quelque chose qui peut générer des erreurs et ne pas affecter le résultat final de ce qu'ils essaient de réaliser, je ne leur montrerai peut-être pas de message d'erreur, mais je leur ferai envoyer un e-mail qui l'insérera automatiquement dans notre logiciel de suivi des bogues. ou un groupe de distribution d'e-mails qui alerte tous les programmeurs de l'entreprise afin que nous soyons conscients de l'erreur, même si l'utilisateur ne l'est pas. Cela nous permet de fixer le back-end tandis que sur le front-end, personne ne sait ce qui se passe.
L'une des plus grandes choses que j'essaie d'éviter est de faire planter le programme après l'erreur - de ne pas pouvoir récupérer. J'essaie toujours de donner à l'utilisateur la possibilité de continuer sans fermer l'application.
Je crois que si personne ne connaît le bug - il ne sera jamais corrigé. Je suis également un fervent partisan de la gestion des erreurs qui permet à l'application de continuer à fonctionner une fois qu'un bogue est découvert.
Si l'erreur est liée au réseau - pourquoi ne pas demander aux fonctions d'effectuer un test de communication réseau simple avant d'exécuter la fonction pour éviter l'erreur en premier lieu? Ensuite, simplement pour alerter l'utilisateur qu'une connexion n'est pas disponible, veuillez vérifier votre Internet, etc., etc. et réessayer?
la source
Ma propre stratégie consiste à distinguer les erreurs de codage (bogues) des erreurs d'exécution et, dans la mesure du possible, à rendre les erreurs de codage difficiles à créer.
Les bogues doivent être corrigés dès que possible, donc une approche de conception par contrat est appropriée. En C ++, j'aime vérifier toutes mes conditions préalables (entrées) avec des assertions en haut de la fonction afin de détecter le bogue dès que possible et de faciliter la connexion d'un débogueur et la correction du bogue. Si le développeur ou le testeur choisit à la place d'essayer de continuer à exécuter le programme, toute perte d'intégrité des données devient alors son problème.
Et trouvez des moyens d'empêcher le bogue en premier lieu. Être strict avec const-correctness et choisir les types de données appropriés pour les données qu'ils contiendront sont deux façons de rendre difficile la création de bogues. Fail-Fast est également bon en dehors du code critique de sécurité qui a besoin d'un moyen de récupération.
Pour les erreurs d'exécution susceptibles de se produire avec un code sans bogue, telles que des échecs de communication réseau ou série ou des fichiers manquants ou corrompus:
la source
L'échec est la bonne option lorsque vous avez des raisons de penser que l'état général du programme est instable et que quelque chose de grave peut se produire si vous le laissez s'exécuter à partir de maintenant. Un peu "l'ignorer" (c'est-à-dire, comme d'autres l'ont fait remarquer, l'enregistrer quelque part ou afficher un message d'erreur à l'utilisateur, puis continuer) est correct lorsque vous savez que, bien sûr, l'opération en cours ne peut pas être effectuée, mais le programme peut continuer à courir.
la source