Je suis en train de passer en revue le code et l'une des choses que je remarque est le nombre d'exceptions où le message d'exception semble juste répéter où cette exception s'est produite. par exemple
throw new Exception("BulletListControl: CreateChildControls failed.");
Les trois éléments de ce message peuvent être résolus à partir du reste de l'exception. Je connais la classe et la méthode de la trace de pile et je sais que cela a échoué (car j'ai une exception).
Cela m'a fait réfléchir à quel message j'ai mis dans les messages d'exception. Je crée d'abord une classe d'exception, s'il n'en existe pas déjà, pour la raison générale (par exemple PropertyNotFoundException
, le pourquoi ), puis, lorsque je la lance, le message indique ce qui ne va pas (par exemple, "Impossible de trouver la propriété 'IDontExist' sur le nœud 1234 "- le quoi ). Le où est dans le StackTrace
. Le quand peut se retrouver dans le journal (le cas échéant). Le comment est pour le développeur de travailler (et de réparer)
Avez-vous d'autres conseils pour lancer des exceptions? Spécifiquement en ce qui concerne la création de nouveaux types et le message d'exception.
la source
Réponses:
Je réponds davantage à ce qui vient après une exception: à quoi cela sert-il et comment le logiciel doit-il se comporter, que doivent faire vos utilisateurs avec l'exception? Au début de ma carrière, une technique géniale a été de signaler les problèmes et les erreurs en 3 parties: contexte, problème et solution. L'utilisation de cette procédure change énormément le traitement des erreurs et améliore considérablement le logiciel pour les opérateurs.
Voici quelques exemples.
Dans ce cas, l'opérateur sait exactement quoi faire et dans quel fichier doit être affecté. Ils savent également que les modifications apportées au regroupement des connexions n'ont pas pris et doivent être répétées.
J'écris des systèmes côté serveur et mes opérateurs bénéficient généralement d'un support technique de premier niveau. J'écrirais les messages différemment pour les logiciels de bureau qui s'adressent à un public différent mais qui incluent la même information.
Plusieurs choses merveilleuses se produisent si l'on utilise cette technique. Le développeur de logiciel est souvent le mieux placé pour savoir comment résoudre les problèmes dans son propre code. Encoder ainsi des solutions de cette manière est extrêmement avantageux pour les utilisateurs finaux désavantagés, car ils manquent souvent des informations sur qu'est-ce que le logiciel faisait exactement. Quiconque a déjà lu un message d'erreur Oracle saura ce que je veux dire.
La deuxième chose merveilleuse qui me vient à l’esprit est que vous essayez de décrire une solution dans votre exception et que vous écrivez «Check X and if A, B else C». Ceci est un signe très clair et évident que votre exception est vérifiée au mauvais endroit. En tant que programmeur, vous avez la capacité de comparer des éléments dans un code. Par conséquent, "si" les instructions doivent être exécutées dans un code, pourquoi impliquer l'utilisateur dans quelque chose qui peut être automatisé? Il y a des chances qu'il est de plus profond dans le code et quelqu'un a fait la chose paresseux et jeté IOException de tout nombre de méthodes et pris les erreurs potentielles de tous dans un bloc de code d' appel qui ne peut pas décrire adéquatement ce qui a mal tourné, ce que le particulierle contexte est et comment y remédier. Cela vous encourage à rédiger des erreurs de grain plus fines, à les capturer et à les manipuler au bon endroit dans votre code afin de pouvoir articuler correctement les étapes que l'opérateur doit suivre.
Dans une entreprise, nous avions des opérateurs de premier plan qui connaissaient très bien le logiciel et conservaient leur propre "livre de travail" qui augmentait nos rapports d'erreurs et nos solutions suggérées. Pour reconnaître cela, le logiciel a commencé à inclure des liens wiki vers le livre d'exécution dans les exceptions afin qu'une explication de base soit disponible, ainsi que des liens vers des discussions et des observations plus avancées par les opérateurs au fil du temps.
Si vous avez eu la dicipline d'essayer cette technique, il devient beaucoup plus évident de nommer vos exceptions dans le code lors de la création de vos propres. NonRecoverableConfigurationReadFailedException devient un raccourci pour ce que vous êtes sur le point de décrire plus en détail à l'opérateur. J'aime être bavard et je pense que ce sera plus facile à interpréter pour le prochain développeur qui manipule mon code.
la source
FileNotFound
ouConnectException
vous savez quoi faire))Dans cette question plus récente, j'ai souligné que les exceptions ne devraient contenir aucun message. À mon avis, le fait qu’ils le fassent est une idée fausse très répandue. Ce que je propose, c'est que
Une exception doit contenir dans ses propres variables membres autant de détails que possible sur ce qui s'est passé précisément. Par exemple, un
IndexOutOfRangeException
doit contenir la valeur d'index jugée non valide, ainsi que les valeurs supérieure et inférieure valides au moment où l'exception a été levée. De cette façon, en utilisant la réflexion, vous pouvez avoir un message automatiquement construit qui se lit comme ceci:IndexOutOfRangeException: index = -1; min=0; max=5
et ceci, avec la trace de la pile, devrait être toutes les informations objectives dont vous avez besoin pour résoudre le problème. Le mettre en forme dans un joli message du type "index -1 n'était pas compris entre 0 et 5" n'ajoute aucune valeur.Dans votre exemple particulier, la
NodePropertyNotFoundException
classe contiendrait le nom de la propriété non trouvée et une référence au nœud qui ne contiendrait pas la propriété. Ceci est important: il ne doit pas contenir le nom du noeud; il devrait contenir une référence au nœud réel. Dans votre cas particulier, cela peut ne pas être nécessaire, mais c'est une question de principe et une façon de penser préférée: la principale préoccupation lors de la construction d'une exception est qu'elle doit être utilisable par un code susceptible de l'intercepter. L'utilisabilité par l'homme est une préoccupation importante, mais seulement secondaire.Cela résout la situation très frustrante à laquelle vous avez peut-être été témoin à un moment donné de votre carrière, où vous avez peut-être attrapé une exception contenant des informations vitales sur ce qui s'est passé dans le texte du message, mais pas dans ses variables de membre. Nous avons dû analyser le texte par des chaînes afin de comprendre ce qui s'est passé, en espérant que le texte du message reste le même dans les futures versions du calque sous-jacent, et en priant que le texte du message ne soit pas dans une langue étrangère lorsque votre programme est courir dans d'autres pays.
Bien sûr, étant donné que le nom de classe de l’exception est le message de l’exception (et que les variables membres de l’exception correspondent aux détails spécifiques), cela signifie que vous avez besoin de nombreuses exceptions pour transmettre tous les différents messages, et c'est bon.
Maintenant, parfois, alors que nous écrivons du code, nous rencontrons une situation erronée pour laquelle nous voulons simplement coder rapidement une
throw
instruction et continuer à écrire notre code au lieu de devoir interrompre ce que nous faisons pour créer une nouvelle classe d'exceptions afin de pouvoir jetez-le là. Pour ces cas, j'ai uneGenericException
classe qui accepte effectivement un message de chaîne en tant que paramètre de construction, mais le constructeur de cette classe d'exception est orné d'un grand grandFIXME XXX TODO
commentaire violet clair indiquant que chaque instanciation de cette classe doit être remplacé par une instanciation d'une classe d'exception plus spécialisée avant la publication du système logiciel, de préférence avant la validation du code.la source
node
objet est protégé par une clause using-Disposable (en C #) ou try-with-resources (en Java): l’objet stocké avec l’exception serait supprimé / fermé, le rendant illégal. pour y accéder afin d’obtenir des informations utiles à l’endroit où l’exception est traitée. Je suppose que dans ces cas, une sorte de résumé de l'objet devrait être stocké dans l'exception, au lieu de l'objet lui-même. Je ne peux pas penser à un moyen infaillible de gérer cela de manière générique dans tous les cas.En règle générale, une exception devrait aider les développeurs à identifier la cause en fournissant des informations utiles (valeurs attendues, valeur réelle, causes possibles / solutions, etc.).
De nouveaux types d'exception doivent être créés lorsqu'aucun des types intégrés n'a de sens . Un type spécifique permet aux autres développeurs d'attraper une exception spécifique et de la gérer. Si le développeur sait comment gérer votre exception mais que le type est
Exception
, il ne pourra pas le gérer correctement.la source
Dans .NET ne jamais
throw new Exception("...")
(comme l’a montré l’auteur de la question). L'exception est le type d'exception racine et n'est pas censée être lancée directement. Lancez plutôt l'un des types d'exception .NET dérivés ou créez votre propre exception personnalisée dérivée de Exception (ou d'un autre type d'exception).Pourquoi ne pas lancer une exception? Parce que lancer Exception ne décrit en rien votre exception et oblige votre code d'appel à écrire du code comme si
catch(Exception ex) { ... }
ce n'était généralement pas une bonne chose! :-)la source
Les éléments que vous souhaitez "ajouter" à l'exception sont les éléments de données qui ne sont pas inhérents à l'exception ou à la trace de la pile. C’est une question intéressante de savoir si ces éléments font partie du "message" ou doivent être joints quand ils sont connectés.
Comme vous l'avez déjà noté, l'exception vous indique probablement quoi, le stacktrace vous indique probablement où mais le "pourquoi" peut être plus impliqué (devrait l'être, on peut l'espérer) que d'aller simplement regarder une ligne ou deux et dire " doh! Bien sur ". C’est encore plus vrai lorsque nous enregistrons des erreurs dans le code de production - j’ai trop souvent été piqué par de mauvaises données qui se sont retrouvées dans un système réel qui n’existe pas dans nos systèmes de test. Une simple simple idée de savoir quel est l'identifiant de l'enregistrement dans la base de données qui cause (ou contribue) à l'erreur peut faire gagner un temps considérable.
Alors ... Soit la liste ou, pour .NET, ajoutée à la collecte de données sur les exceptions consignées (cf @Plip!):
Certaines choses, bien sûr, vous ne saurez pas ce dont vous avez besoin tant que vous ne les aurez pas dans votre rapport / journal d’erreur initial. Certaines choses que vous ne réalisez pas que vous pouvez obtenir jusqu'à ce que vous trouviez que vous en avez besoin.
la source
Quelles sont les exceptions pour ?
(1) Dire à l'utilisateur que quelque chose s'est mal passé?
Cela devrait être un dernier recours, parce que votre code devrait intercéder et leur montrer quelque chose de "plus beau" qu'une exception.
Le message "erreur" doit indiquer clairement et succinctement ce qui ne va pas et ce que l'utilisateur peut éventuellement faire pour remédier à la situation.
par exemple "S'il vous plaît, n'appuyez plus sur ce bouton"
(2) Dire à un développeur quand il a mal tourné?
C’est le genre de chose que vous enregistrez dans un fichier pour une analyse ultérieure.
La trace de pile indiquera au développeur où le code a été cassé; le message devrait, encore une fois, indiquer ce qui a mal tourné.
(3) Dire à un gestionnaire d'exception (un code) que quelque chose s'est mal passé?
Le type de l'exception déterminera quel gestionnaire d'exception pourra l'examiner et les propriétés définies sur l'objet exception permettront au gestionnaire de s'en occuper.
Le message de l'exception est totalement hors de propos .
la source
Ne créez pas de nouveaux types si vous pouvez y contribuer. Ils peuvent provoquer une confusion et une complexité supplémentaires et entraîner davantage de code à maintenir. Ils peuvent obliger votre code à s'étendre. La conception d'une hiérarchie d'exceptions nécessite beaucoup de tests et de tests. Ce n'est pas une pensée après. Il est souvent préférable d'utiliser la hiérarchie des exceptions de langage intégrée.
Le contenu du message d'exception dépend du destinataire du message - vous devez donc vous mettre à la place de cette personne.
Un ingénieur du support technique devra être capable d'identifier la source de l'erreur le plus rapidement possible. Incluez une courte chaîne descriptive ainsi que toutes les données pouvant aider à résoudre le problème. Toujours inclure la trace de la pile - si vous le pouvez - ce sera la seule véritable source d’information.
La présentation des erreurs aux utilisateurs généraux de votre système dépend du type d'erreur: si l'utilisateur peut résoudre le problème, en fournissant une entrée différente, un message descriptif concis est requis. Si l'utilisateur ne peut pas résoudre le problème, il est préférable de signaler qu'une erreur s'est produite et de connecter / envoyer une erreur au support (en suivant les instructions ci-dessus).
De plus, ne lancez pas une grosse "HALT ERROR!" icône. C'est une erreur - ce n'est pas la fin du monde.
En résumé, réfléchissez aux acteurs et aux cas d'utilisation de votre système. Mettez-vous à la place de l'utilisateur. Soit utile. Sois gentil. Pensez-y dès le départ dans la conception de votre système. Du point de vue de vos utilisateurs - ces cas exceptionnels et la façon dont le système les gère sont tout aussi importants que les cas normaux de votre système.
la source