Il semble y avoir un certain accord sur le fait que les messages d'exception devraient contenir des détails utiles .
Pourquoi de nombreuses exceptions communes aux composants système ne contiennent-elles pas des informations utiles?
Quelques exemples:
- .NET
List
accès à l'indexArgumentOutOfRangeException
ne pas me dire la valeur de l' indice qui a été jugé et était invalide et ne me dire la plage autorisée. - Fondamentalement, tous les messages d’exception de la bibliothèque standard MSVC C ++ sont totalement inutiles (dans la même veine que ci-dessus).
- Exceptions Oracle dans .NET vous indiquant (paraphrasé) "TABLE OU VUE introuvable", mais pas laquelle .
Donc, il me semble que la plupart des messages d’exception ne contiennent pas suffisamment de détails pour être utiles. Mes attentes sont-elles hors de propos? Est-ce que j'utilise mal les exceptions et que je le remarque même? Ou peut - être mon impression est fausse: la majorité des exceptions ne fournissent réellement des détails utiles?
c#
c++
exceptions
Martin Ba
la source
la source
Réponses:
Les exceptions ne contiennent pas de détails utiles car le concept des exceptions n'a pas encore suffisamment mûri dans la discipline du génie logiciel, de sorte que de nombreux programmeurs ne les comprennent pas complètement et ne les traitent donc pas correctement.
Oui,
IndexOutOfRangeException
devrait contenir l'index précis qui était hors de portée, ainsi que la plage qui était valide au moment où il a été lancé, et il est méprisable pour le compte des créateurs du runtime .NET qu'il n'en a pas. Oui, l’table or view not found
exception d’Oracle doit contenir le nom de la table ou de la vue qui n’a pas été trouvée et, encore une fois, le fait qu’elle ne soit pas méprisable au nom de celui qui en est responsable.La confusion provient en grande partie de l'idée originale erronée selon laquelle les exceptions devraient contenir des messages lisibles par l'homme, ce qui découle d'un manque de compréhension de ce que sont les exceptions, il s'agit donc d'un cercle vicieux.
Puisque les gens pensent que l’exception devrait contenir un message lisible par l’homme, ils sont convaincus que toute information transportée par l’exception devrait également être formatée en un message lisible par l’homme, puis ils sont ennuyés d’écrire tout le message lisible par l’homme. code du bâtiment, ou craignent que cela ne divulgue une quantité déconseillée d'informations à tous les regards indiscrets qui pourraient voir le message. (Les problèmes de sécurité mentionnés par d'autres réponses.)
Mais la vérité est qu’ils ne devraient pas s’inquiéter de cela, car l’exception ne devrait pas contenir un message lisible par l’homme. Les exceptions sont des choses que seuls les programmeurs devraient voir et / ou traiter. S'il est toujours nécessaire de présenter des informations sur les défaillances à un utilisateur, vous devez le faire à un niveau très élevé, de manière sophistiquée et dans la langue de l'utilisateur, qui, statistiquement, a peu de chances d'être l'anglais.
Ainsi, pour nous programmeurs, le "message" de l'exception est le nom de la classe de l'exception , et toute autre information pertinente à l'exception doit être copiée dans les variables membres (final / en lecture seule) de l'objet exception. De préférence, chaque petit morceau imaginable. De cette façon, aucun message n’a besoin (ou ne devrait) être généré, et donc aucun regard ne peut le voir.
Pour répondre à la préoccupation exprimée par Thomas Owens dans un commentaire ci-dessous:
Oui, bien sûr, à un certain niveau, vous allez créer un message de journal au sujet de l'exception. Mais vous voyez déjà le problème avec ce que vous dites: d'un côté, un message de journal d'exception sans trace de pile est inutile, mais d'un autre côté, vous ne voulez pas que l'utilisateur voie l'intégralité du tracé de la pile des exceptions. Encore une fois, notre problème ici est que notre perspective est faussée par les pratiques traditionnelles. Les fichiers journaux sont traditionnellement en texte brut, ce qui était peut-être correct alors que notre discipline en était à ses balbutiements, mais peut-être plus maintenant: s'il existe un problème de sécurité, le fichier journal doit être binaire et / ou crypté.
Que ce soit en binaire ou en texte brut, le fichier journal doit être considéré comme un flux dans lequel l'application sérialise les informations de débogage. Un tel flux serait réservé aux yeux des programmeurs, et la tâche de générer des informations de débogage pour une exception devrait être aussi simple que la sérialisation de l'exception dans le flux de journal de débogage. De cette façon, en consultant le journal, vous voyez le nom de la classe d’exception (qui, comme je l’ai déjà dit, est à toutes fins pratiques "le message",) chacune des variables de membre d’exception qui décrivent tout ce qui est pertinent. et-pratique-à-inclure-dans-un-journal, et la trace entière de la pile. Notez que la mise en forme d'un message d'exception lisible par l'homme est visiblement absente de ce processus.
PS
Cette réponse contient quelques autres réflexions sur ce sujet: comment rédiger un bon message d’exception
PPS
Il semble que beaucoup de gens étaient cochés par ma suggestion sur les fichiers journaux binaires, donc je modifie la réponse une fois de plus pour le rendre encore plus clair que ce que je veux dire ici est pas que le fichier journal doit être binaire, mais le fichier journal peut être binaire, si besoin est.
la source
D'après mon expérience, il existe un certain nombre de raisons pour lesquelles les exceptions ne contiennent pas d'informations utiles. Je m'attends à ce que ces types de raisons s'appliquent également aux composants du système - mais je ne le sais pas avec certitude.
Kinda? Je veux dire, les exceptions devraient avoir des messages gentils, mais ce sont aussi des exceptions . Vous devriez passer votre temps à concevoir du code pour éviter des conditions exceptionnelles ou à l'écrire pour gérer des conditions exceptionnelles (en ignorant le message), sans les utiliser comme une sorte de mécanisme de retour d'informations interactif lors de la programmation. Il est inévitable de les utiliser à des fins de débogage, mais dans la plupart des situations, cela devrait être réduit au minimum. Le fait que vous remarquiez ce problème me fait craindre de ne pas le prévenir suffisamment.
la source
Je n'ai pas une expérience excessive de C #, ni du C ++ en particulier, mais je peux vous dire ceci: les exceptions écrites par le développeur sont 9 fois plus utiles que toute exception générique que vous trouverez jamais, point à la ligne.
Idéalement, une exception générique vous indiquera exactement pourquoi l'erreur s'est produite et vous pourrez y remédier facilement, mais de manière réaliste, dans les applications volumineuses avec plusieurs classes pouvant générer une grande variété d'exceptions, ou Même type d'exceptions, il est toujours plus utile d'écrire votre propre sortie pour le retour d'erreur que de s'en remettre au message par défaut.
C’est ce qui devrait être fait, car comme beaucoup de personnes l’ont souligné, certaines applications ne veulent pas envoyer de message d’erreur qu’elles ne veulent pas que l’utilisateur voie, pour des raisons de sécurité ou pour éviter toute confusion.
Au lieu de cela, vous devez anticiper dans votre conception les types d'erreur pouvant être générés dans votre application (il y aura toujours des erreurs) et rédiger des messages d'erreur qui vous aideront à identifier le problème.
Cela ne vous aidera pas toujours - car vous ne pouvez pas toujours anticiper quel message d'erreur sera utile - mais c'est la première étape pour mieux comprendre votre propre application à long terme.
la source
La question est précisément de savoir pourquoi tant d’exceptions levées par les "composants système" (ou classes de bibliothèque standard) ne contiennent pas de détails utiles.
Malheureusement, la plupart des développeurs n'écrivent pas les composants de base dans des bibliothèques standard, pas plus que les documents de conception détaillés ou autres motifs de conception ne sont nécessairement rendus publics. En d'autres termes, nous pouvons ne jamais savoir avec certitude.
Cependant, il convient de garder à l'esprit deux points essentiels pour lesquels des informations détaillées sur les exceptions pourraient ne pas être souhaitables ou importantes:
Une exception peut être utilisée en appelant du code de quelque manière que ce soit: une bibliothèque standard ne peut pas imposer de contraintes sur la manière dont l'exception est utilisée. Plus précisément, il peut être affiché à l'utilisateur. Considérons un index de tableau hors limites: ceci peut fournir des informations utiles à un attaquant. Le concepteur de langage n'a aucune idée de la manière dont une application utilisera l'exception levée ni même du type d'application (par exemple, une application Web ou un poste de travail). Par conséquent, la suppression d'informations peut être plus sûre du point de vue de la sécurité.
Les exceptions ne doivent pas être affichées à l'utilisateur. Au lieu de cela, affichez un message d'erreur convivial et enregistrez l'exception à un emplacement auquel un attaquant n'a pas accès (le cas échéant). Une fois que l'erreur est identifiée, le développeur doit déboguer le code, en inspectant les cadres de pile et les chemins logiques. À ce stade, le développeur dispose de plus d'informations qu'une exception ne pourrait jamais espérer en avoir.
la source
Tout d’abord, permettez-moi de faire éclater une bulle en affirmant que, même si le message diag est chargé avec des informations qui vous amènent à la ligne de code exacte et à la sous-commande en 4 secondes, il est probable que les utilisateurs ne l’écriront jamais ou ne le transmettra pas au support technique. et on vous dira "Eh bien, il est dit quelque chose à propos d'une violation ... Je ne sais pas si ça avait l'air compliqué!"
J'écris des logiciels et j'appuie les résultats d'autres logiciels depuis plus de 30 ans maintenant. Personnellement, la qualité actuelle d'un message d'exception n'a pratiquement rien à voir avec la sécurité, quelle que soit la manière dont les résultats finaux sont apparus. l'univers, beaucoup plus à voir avec le fait que tant de personnes de notre secteur étaient autodidactes à l'origine et qu'elles n'incluaient jamais de leçons de communication. Peut-être que si nous obligions tous les nouveaux codeurs à occuper un poste de maintenance pendant deux ou trois ans, afin de pouvoir déterminer ce qui n'allait pas, ils comprendraient au moins l'importance d'une certaine précision.
Récemment, dans une application en cours de reconstruction, il a été décidé que les codes de retour appartiendraient à l'un des trois groupes suivants:
(100 a été laissé pour une raison quelconque)
Dans un flux de travail particulier, nous pensions être réutilisés ou le code générique utiliserait les retours génériques (> 199) pour les erreurs fatales, nous laissant ainsi 100 erreurs fatales possibles pour un flux de travail. Avec des données légèrement différenciantes dans le message, les erreurs telles que le fichier non trouvé peuvent toutes utiliser le même code et se différencier des messages.
Lorsque le code a été renvoyé par les sous-traitants, vous ne croiriez pas notre surprise lorsque pratiquement TOUTES LES ERREURS FATALES SIMPLES étaient le code de retour 101.
Tout ce qui a été pris en compte, je pense que la réponse à votre question est que les messages n’ont aucune signification, car lors de leur création, ils devaient constituer des espaces réservés auxquels personne ne revenait. Finalement, les gens ont compris comment résoudre les problèmes non pas à cause des messages, mais de les DISPITER.
Depuis ce temps, les autodidactes n'ont tout simplement jamais eu un bon exemple de ce qu'une exception devrait contenir. Ajoutez à cela plus d'utilisateurs ne lisent pas les messages, encore moins d'essayer de les transmettre au support (j'ai vu des messages d'erreur copiés et collés par les utilisateurs utilisés qui ont ensuite été expurgés avant d'être envoyés avec le commentaire ultérieur semblait être une mine d’informations et je ne pouvais absolument pas tout vouloir, alors ils en ont retiré au hasard un tas.
Et regardons les choses en face, avec beaucoup trop (pas trop, beaucoup) de la prochaine génération de codeurs, si cela demande plus de travail et n’ajoute pas de flash, cela ne vaut tout simplement pas la peine ...
Dernière remarque: si un message d'erreur inclut un code d'erreur / de retour, il me semble que quelque part dans les modules exécutés, il devrait exister une ligne se lisant comme "if condition return code-value" et que condition devrait vous expliquer pourquoi le code de retour eu lieu. Cela semble être une approche logique simple, mais pour la vie, essayez simplement de demander à Microsoft de vous dire ce qui s’est passé lorsqu’une mise à niveau de Windows a échoué avec le CODE 80241013 ou un autre identifiant très unique. Un peu triste, n'est-ce pas?
la source
chances are the users will never write it down... and you will be told "Well it said something about a violation..."
C'est pourquoi vous utilisez un outil de journalisation des exceptions pour générer automatiquement le rapport d'erreur contenant la trace de pile et éventuellement même l'envoyer à votre serveur. J'ai eu un utilisateur une fois qui n'était pas très technique. Chaque fois qu'elle envoyait un message à partir du journal des erreurs, le message "Je ne suis pas sûr de ce que j'ai mal fait, mais ..." peu importe le nombre de fois où j'ai expliqué que cette erreur signifiait que le bogue était de mon côté . Mais j'ai toujours eu les rapports d'erreur d'elle!Bien que je convienne que les exceptions devraient contenir autant d’informations que possible, ou du moins être moins génériques. Dans le cas table non trouvée, le nom de la table serait bien.
Mais vous en savez plus sur ce que vous tentiez de faire à la place du code où vous avez reçu l'exception. Bien que, souvent, vous ne puissiez vraiment rien faire pour rectifier la situation lorsque quelque chose ne va pas dans une bibliothèque en dehors de votre contrôle, vous pouvez ajouter des informations beaucoup plus utiles sur la situation dans laquelle une chose a mal tourné.
Dans le cas d'une table non trouvée, cela ne vous aidera pas beaucoup si on vous dit que la table introuvable est appelée ÉTUDIANTS, car vous n'avez pas une telle table et que cette chaîne ne figure nulle part dans votre code.
Mais si vous attrapez l'exception et la relancez avec l'instruction SQL que vous avez essayé d'exécuter, vous serez mieux loti, car il s'avère que vous avez essayé d'insérer un enregistrement dont le champ de nom est Robert '); DROP TABLE ÉTUDIANTS; (Il y a toujours un xkcd!)
Donc, pour lutter contre les exceptions moins qu'informatives: essayez-rattraper-relancer avec plus d'informations spécifiques à ce que vous tentiez de faire.
Je devrais probablement ajouter, pour que cela réponde davantage au pourquoi de la question, qu’une raison probable pour laquelle les responsables des bibliothèques n’ont pas cherché à améliorer les messages relatifs aux exceptions, c’est qu’ils ne savent pas pourquoi quelque chose a été essayé qui a échoué, cette logique est dans le code appelant.
la source
throw_with_nested
beaucoup.Pour donner une réponse légèrement différente: Le code incriminé a probablement été créé pour spécifier:
Ajoutez la pression qui vous incite à respecter exactement les spécifications (par crainte d’être rejetée lors des révisions / tests) en un temps minimum et avec un minimum de complications, vous disposez alors de votre recette pour une exception de bibliothèque entièrement conforme et inutile.
la source
Les exceptions ont un coût spécifique à la langue et à la mise en œuvre.
Par exemple, des exceptions C ++ sont nécessaires pour détruire toutes les données actives entre la projection d'une trame d'appel et la capture d'une trame d'appel, ce qui est coûteux. Par conséquent, les programmeurs ne souhaitent pas utiliser beaucoup les exceptions.
Dans Ocaml, le lancement d'une exception est presque aussi rapide qu'un C
setjmp
(son coût ne dépend pas du nombre de trames d'appel traversées), ce qui permet aux développeurs de l'utiliser beaucoup (même dans des cas non exceptionnels et très courants). En revanche, les exceptions C ++ sont suffisamment lourdes pour que vous ne les utilisiez probablement pas beaucoup comme vous le feriez dans Ocaml.Un exemple typique est une recherche ou une exploration récursive qui peut être "arrêtée" dans une récursion assez profonde (par exemple, trouver une feuille dans un arbre ou une fonction d'unification). Dans certaines langues, il est plus rapide (donc plus idiomatique) de propager cette condition à chaque appelant. Dans d'autres langues, le lancement d'une exception est plus rapide.
Ainsi, en fonction de la langue (et des habitudes des développeurs qui l’utilisent), une exception pourrait contenir beaucoup de détails utiles ou, au contraire, être utilisée comme un saut rapide non local et ne porter que les données très utiles.
la source
Qu'est-ce qui vous fait penser que la valeur d'index ou la plage requise ou le nom de la table est un détail utile, pour une exception?
Les exceptions ne sont pas un mécanisme de traitement des erreurs; ils sont un mécanisme de récupération .
Le point d'exception est de remonter jusqu'au niveau de code pouvant gérer l'exception. Où que ce soit, vous avez les informations nécessaires ou elles ne sont pas pertinentes. Si vous avez besoin d'informations sans y avoir accès immédiatement , vous ne gérez pas l'exception au niveau approprié.
La seule fois où je peux penser à des informations supplémentaires qui pourraient être utiles est au plus haut niveau absolu de votre application où vous plantez et émettez un vidage d’erreurs; mais ce n’est pas le travail de l’exception d’accéder, de compiler et de stocker ces informations.
Je ne dis pas que vous pouvez simplement mettre "lancer une nouvelle exception" partout et l'appeler "bon", il est possible d'écrire de mauvaises exceptions. Mais inclure des informations non pertinentes n’est pas nécessaire de les utiliser correctement.
la source