Lors de la conception d'exceptions, dois-je écrire des messages qu'un utilisateur ou un développeur doit comprendre? Qui devrait réellement être le lecteur des messages d'exception?
Je trouve que les messages d'exception ne sont pas du tout utiles et j'ai toujours du mal à les écrire. Par convention, le type de l'exception devrait déjà nous dire pourquoi quelque chose n'a pas fonctionné et les propriétés personnalisées peuvent ajouter encore plus d'informations comme les noms de fichiers, les index, les clés, etc. alors pourquoi le répéter dans le message lui-même? Un message généré automatiquement pourrait également faire et tout ce qu'il devait contenir est le nom de l'exception avec une liste de propriétés supplémentaires. Ce serait exactement aussi utile qu'un texte manuscrit.
Ne serait-il pas préférable de ne pas écrire de messages du tout, mais d'avoir des rendus d'exception spéciaux qui s'occupent de créer des messages significatifs peut-être dans différentes langues plutôt que de les coder en dur dans le code?
On m'a demandé si l'une de ces questions répondait à ma question:
- Comment écrire un bon message d'exception
- Pourquoi de nombreux messages d'exception ne contiennent-ils pas de détails utiles?
Je les ai lus tous les deux et je n'étais pas satisfait de leurs réponses. Ils parlent des utilisateurs en général et se concentrent sur le contenu du message lui-même plutôt que sur le destinataire et il s'avère qu'il peut y en avoir au moins deux: l'utilisateur final et le développeur. Je ne sais jamais à qui je dois parler lorsque j'écris des messages d'exception.
Je pense même que le célèbre message n'a aucune valeur réelle car il ne fait que répéter le nom du type d'exception dans des mots différents, alors pourquoi prendre la peine de les écrire? Je peux parfaitement les générer automatiquement.
Pour moi, le message d'exception manque de différenciation de ses lecteurs. Une exception parfaite devrait fournir au moins deux versions du message: une pour l'utilisateur final et une pour le développeur. L'appeler simplement un message est trop générique. Un message de développeur doit ensuite être écrit en anglais, mais le message de l'utilisateur final peut devoir être traduit dans d'autres langues. Il n'est pas possible de réaliser tout cela avec un seul message, donc une exception devrait fournir un identifiant au message de l'utilisateur final qui, comme je viens de le dire, pourrait être disponible dans différentes langues.
Lorsque je lis toutes les autres questions liées, j'ai l'impression qu'un message d'exception est en effet destiné à être lu par un utilisateur final et non un développeur ... un seul message, c'est comme avoir un gâteau et le manger aussi.
la source
Réponses:
Ces messages sont destinés aux autres développeurs
Ces messages devraient être lus par les développeurs pour les aider à déboguer l'application. Cela peut prendre deux formes:
Débogage actif. Vous exécutez en fait un débogueur tout en écrivant du code et en essayant de comprendre ce qui se passe. Dans ce contexte, une exception utile vous guidera en facilitant la compréhension de ce qui ne va pas ou en suggérant éventuellement une solution de contournement (bien que cela soit facultatif).
Débogage passif. Le code s'exécute en production et échoue. L'exception est enregistrée, mais vous obtenez uniquement le message et la trace de pile. Dans ce contexte, un message d'exception utile vous aidera à localiser rapidement le bogue.
Étant donné que ces messages sont souvent enregistrés, cela signifie également que vous ne devez pas y inclure d'informations sensibles (telles que des clés privées ou des mots de passe, même si cela peut être utile pour déboguer l'application).
Par exemple, le
IOSecurityException
type d'une exception levée lors de l'écriture d'un fichier n'est pas très explicite sur le problème: est-ce parce que nous n'avons pas les autorisations d'accès à un fichier? Ou peut-être pouvons-nous le lire, mais pas l'écrire? Ou peut-être que le fichier n'existe pas et que nous n'avons pas les autorisations pour y créer des fichiers? Ou peut-être qu'il est verrouillé (espérons que le type de l'exception sera différent dans ce cas, mais dans la pratique, les types peuvent parfois être cryptiques). Ou peut-être que la sécurité d'accès au code nous empêche d'effectuer des opérations d'E / S?Au lieu:
est beaucoup plus explicite. Ici, nous savons immédiatement que les autorisations sur le répertoire sont définies correctement (sinon, nous ne pourrons pas savoir que le fichier existe), mais les autorisations au niveau du fichier sont problématiques.
Cela signifie également que si vous ne pouvez pas fournir d'informations supplémentaires qui ne sont pas déjà dans le type de l'exception, vous pouvez laisser le message vide.
DivisionByZeroException
est un bon exemple où le message est redondant. D'un autre côté, le fait que la plupart des langues vous permettent de lever une exception sans spécifier son message se fait pour une raison différente: soit parce que le message par défaut est déjà disponible, soit parce qu'il sera généré plus tard si nécessaire (et la génération de ce message est inclus dans le type d'exception, ce qui est parfaitement logique, "OOPly" parlant).Notez que pour des raisons techniques (souvent de performances), certains messages finissent par être beaucoup plus cryptés qu'ils ne devraient l'être. .NET
NullReferenceException
:est un excellent exemple d'un message qui n'est pas utile. Un message utile serait:
Ces messages ne sont pas destinés aux utilisateurs finaux!
Les utilisateurs finaux ne devraient pas voir les messages d'exception. Jamais. Bien que certains développeurs finissent par montrer ces messages aux utilisateurs, cela entraîne une mauvaise expérience utilisateur et de la frustration. Messages tels que:
ne signifie absolument rien pour un utilisateur final et doit être évité à tout prix.
Le pire des cas est d'avoir un try / catch global qui lève l'exception à l'utilisateur et quitte l'application. Une application soucieuse de ses utilisateurs:
Gère les exceptions en premier lieu. La plupart d'entre eux peuvent être manipulés sans déranger l'utilisateur. Le réseau est en panne? Pourquoi ne pas attendre quelques secondes et réessayer?
Empêche un utilisateur de diriger l'application vers un cas exceptionnel. Si vous demandez à l'utilisateur d'entrer deux nombres et de diviser le premier par le second, pourquoi laisseriez-vous l'utilisateur entrer zéro dans le deuxième cas afin de le blâmer quelques secondes plus tard? Qu'en est-il de surligner la zone de texte en rouge (avec une info-bulle utile indiquant que le nombre doit être différent de zéro) et de désactiver le bouton de validation jusqu'à ce que le champ reste rouge?
Invite un utilisateur à effectuer une action dans un formulaire qui n'est pas une erreur. Il n'y a pas suffisamment d'autorisations pour accéder à un fichier? Pourquoi ne pas demander à l'utilisateur d'accorder des autorisations administratives ou de choisir un autre fichier?
Si rien d'autre ne fonctionne, affiche une erreur utile et conviviale qui est spécifiquement écrite pour réduire la frustration de l'utilisateur, aider l'utilisateur à comprendre ce qui s'est mal passé et éventuellement résoudre le problème, et également l'aider à prévenir l'erreur à l'avenir (le cas échéant).
Dans votre question, vous avez suggéré d'avoir deux messages dans une exception: un message technique pour les développeurs et un pour les utilisateurs finaux. Bien qu'il s'agisse d'une suggestion valable dans certains cas mineurs, la plupart des exceptions sont produites à un niveau où il est impossible de produire un message significatif pour les utilisateurs. Prenez
DivisionByZeroException
et imaginez que nous ne pouvions pas empêcher l'exception de se produire et que nous ne pouvons pas la gérer nous-mêmes. Lorsque la division se produit, le framework (puisque c'est le framework, et non le code métier, qui lève l'exception) sait-il quel sera un message utile pour un utilisateur? Absolument pas:Au lieu de cela, on peut le laisser lever l'exception, puis l'attraper à un niveau supérieur où nous connaissions le contexte commercial et pourrions agir en conséquence afin d'aider réellement l'utilisateur final, montrant ainsi quelque chose comme:
ou peut-être:
Ces messages ne sont pas destinés à l'analyse
Les messages d'exception ne devraient pas non plus être analysés ni utilisés par programme. Si vous pensez que l'appelant peut avoir besoin d'informations supplémentaires, incluez-les dans l'exception côte à côte avec le message. Ceci est important, car le message peut être modifié sans préavis. Le type fait partie de l'interface, mais le message ne l'est pas: ne vous y fiez jamais pour la gestion des exceptions.
Imaginez le message d'exception:
Vous souhaitez extraire les valeurs «500», «6», «4» et «377». Réfléchissez un peu à l'approche que vous utiliserez pour effectuer l'analyse, puis poursuivez la lecture.
Vous avez l'idée? Génial.
Maintenant, le développeur d'origine a découvert une faute de frappe:
devrait être:
De plus, le développeur considère que le mois / semaine / une heure ne sont pas particulièrement pertinents, il fait donc également un changement supplémentaire:
Que se passe-t-il avec votre analyse?
Au lieu d'analyser, vous pouvez utiliser des propriétés d'exception (qui peuvent contenir tout ce que vous voulez, dès que les données peuvent être sérialisées):
Est-il facile d'utiliser ces données maintenant?
Parfois (comme dans .NET), le message peut même être traduit dans la langue de l'utilisateur (à mon humble avis, traduire ces messages est absolument faux, car tout développeur devrait être capable de lire en anglais). L'analyse de tels messages est presque impossible.
la source
La réponse à cela dépend entièrement de l'exception.
La question la plus importante à poser est "qui peut résoudre le problème?" Si l'exception est causée par une erreur de système de fichiers lors de l'ouverture d'un fichier, il peut être judicieux de transmettre ce message à l'utilisateur final. Le message peut contenir plus d'informations sur la façon de corriger l'erreur. Je peux penser à un cas définitif dans mon travail où j'avais un système de plugins qui chargeait des DLL. Si un utilisateur a fait une faute de frappe sur la ligne de commande pour charger le mauvais plugin, le message d'erreur système sous-jacent contenait en fait des informations utiles pour lui permettre de corriger le problème.
Cependant, la plupart du temps, une exception non interceptée ne peut pas être corrigée par l'utilisateur. La plupart d'entre eux impliquent d'apporter des modifications au code. Dans ces cas, le consommateur du message est clairement un développeur.
Le cas des exceptions interceptées est plus compliqué car vous avez la possibilité de traiter correctement l'exception et d'en lancer une plus conviviale. Un langage de script que j'ai écrit a levé des exceptions dont le message était très clairement destiné à un développeur. Cependant, lorsque la pile s'est déroulée, j'ai ajouté des traces de pile lisibles par l'utilisateur à partir du langage de script. Mes utilisateurs pouvaient très rarement bloquer le message, mais ils pouvaient regarder la trace de la pile dans leur script et comprendre ce qui s'était passé 95% du temps. Pour les 5% restants, quand ils m'ont appelé, nous avions non seulement une trace de pile, mais un message prêt à l'emploi pour m'aider à comprendre ce qui n'allait pas.
En tout, je traite le message d'exception comme un contenu inconnu. Quelqu'un plus en amont, qui en savait plus sur les implémentations, a accordé une exception à mon logiciel. Parfois, j'ai l'impression qu'un contenu inconnu sera utile à un utilisateur final, parfois ce n'est pas le cas.
la source