Question

Les erreurs qui se produisent au plus profond d'une couche d'accès aux données ou même plus haut (par exemple, dans les opérations ADO.net) ont rarement du sens pour un utilisateur final. Faire simplement remonter ces erreurs dans une interface utilisateur et les afficher ne produira généralement rien sauf la frustration d'un utilisateur final.

J'ai récemment utilisé une technique de base pour signaler les erreurs, par exemple en détectant l'erreur et en ajoutant au moins un texte convivial, afin qu'au moins l'utilisateur final comprenne ce qui a échoué.

Pour ce faire, j'attrape une exception dans chaque fonction spécifique (par exemple, une fonction d'extraction dans une couche d'accès aux données), puis une nouvelle erreur avec un texte convivial sur la fonction qui a échoué et probablement la cause, mais ensuite incorporer l'exception d'origine dans la nouvelle exception en tant que "exception interne" de cette nouvelle exception.

Cela peut ensuite se produire au niveau de chaque couche si nécessaire, chaque utilisateur de la fonction de niveau inférieur ajoutant son propre contexte au message d'erreur, de sorte que ce qui atteint l'interface utilisateur constitue un message d'erreur de plus en plus convivial.

Une fois que l'erreur atteint l'interface utilisateur - si nécessaire - elle peut ensuite parcourir les exceptions imbriquées afin d'afficher un message d'erreur qui indique d'abord à l'utilisateur quelle opération a échoué, mais fournit également un peu d'informations techniques sur les erreurs réellement survenues. .

par exemple.

  

" La liste des noms de clients de votre   demandé n'a pas pu être affiché. "

     

" Obtention de la liste de clients   vous avez demandé l'échec en raison d'une erreur dans la base de données. "

     

"Une erreur s'est produite lors de la connexion au   base de données lors de la récupération d'une liste de   clients "

     

"La connexion a échoué pour l'utilisateur xx"

.

Ma question est la suivante: est-ce horriblement inefficace (toutes ces exceptions imbriquées)? Je soupçonne que ce n’est pas une pratique exemplaire. Par conséquent, que devrais-je faire pour obtenir le même résultat - ou devrais-je réellement essayer de réaliser quelque chose de mieux?

Était-ce utile?

La solution

C’est un peu horrible.

Si vous montrez une erreur à l'utilisateur final, celui-ci est censé pouvoir agir à ce sujet. Dans " La liste des noms de clients que vous avez demandés n'a pas pu être affichée. & Quot; Dans ce cas, votre utilisateur se contentera de penser: "Et alors?" Sur tous ces cas, il suffit d'afficher un "Quelque chose de mauvais est arrivé" message. Vous n'avez même pas besoin d'attraper ces exceptions. En cas de problème, laissez une méthode globale (comme application_error) le gérer et afficher un message générique. Lorsque vous ou votre utilisateur pouvez faire quelque chose à propos de l'erreur, récupérez-la et faites-le ou avertissez-le.

Mais vous voudrez enregistrer toutes les erreurs que vous ne gérez pas.

En passant, l’affichage d’informations sur les erreurs pouvant survenir peut conduire à des failles de sécurité. Moins les attaquants en savent sur votre système, moins ils trouveront le moyen de le pirater (rappelez-vous des messages tels que "Erreur de syntaxe dans l'instruction SQL: Sélectionnez * Parmi les utilisateurs Où username = 'a'; base de données drp; - '. .. "attendus:" déposez "au lieu de" drp ". Ils ne font plus de sites comme ceux-ci).

Autres conseils

Il est techniquement coûteux de lancer de nouvelles exceptions, mais je ne ferai pas un grand débat à partir de cela car "coûteux". est relatif - si vous lancez 100 exceptions de ce type à la minute, vous ne verrez probablement pas le coût; Si vous lancez 1000 exceptions de ce type à la seconde, vous risquez fort de rencontrer des problèmes de performances (par conséquent, il ne vaut pas la peine de discuter ici - les performances sont votre priorité).

Je suppose que je dois demander pourquoi cette approche est utilisée. Est-il vraiment vrai que vous pouvez ajouter des informations d'exception significatives à tous les niveaux où une exception peut être levée et, dans l'affirmative, est-il également vrai que les informations seront:

  • Quelque chose que vous voulez réellement partager avec votre utilisateur?
  • Quelque chose que votre utilisateur pourra interpréter, comprendre et utiliser ?
  • Écrit de manière à ne pas nuire à la réutilisation ultérieure de composants de bas niveau dont l’utilité pourrait ne pas être connue au moment de leur écriture?

Je demande si vous souhaitez partager des informations avec votre utilisateur car, dans votre exemple, votre pile artificielle commence par informer l'utilisateur qu'un problème d'authentification s'est produit sur la base de données. Pour un pirate informatique potentiel, il s’agit d’un bon élément d’information qui expose les résultats de l’opération.

S'agissant de la restitution d'une pile d'exceptions personnalisée complète, je ne pense pas que ce soit utile pour la plupart des utilisateurs (honnêtes). Si je ne parviens pas à obtenir une liste de noms de clients, par exemple, est-ce que cela va m'aider (en tant qu'utilisateur) à savoir qu'il y a eu un problème d'authentification avec la base de données? Sauf si vous utilisez l'authentification intégrée et que chacun de vos utilisateurs possède un compte et la possibilité de contacter un administrateur système pour savoir pourquoi son compte manque de privilèges, probablement pas.

Je commencerai par décider s’il existe réellement une différence sémantique entre l’exception levée du cadre et le message d’exception que vous souhaitez transmettre à l’utilisateur. Si tel est le cas, utilisez une exception personnalisée au niveau le plus bas ("login failed" dans votre exemple). Les étapes qui suivent, jusqu'à la présentation réelle de l'exception, ne nécessitent pas d'exception personnalisée. L'exception qui vous intéresse a déjà été générée (la connexion a échoué) - continuer à envelopper le message à tous les niveaux de la pile d'appels n'a pas d'autre objectif que d'exposer votre pile d'appels à vos utilisateurs. Pour ceux " middle " étapes, en supposant que tous les blocs try / catch sont en place, une simple stratégie de "journalisation et de lancement" fonctionnerait correctement.

En réalité, cette stratégie présente un autre défaut potentiel: elle oblige le développeur à maintenir la norme d'exception personnalisée mise en œuvre. Comme il est impossible de connaître toutes les permutations de la hiérarchie des appels lors de l’écriture de types de bas niveau (leurs "clients" n’ont peut-être même pas encore été écrits), il semble peu probable que tous les développeurs - ou même un développeur - se souviennent de personnalisez toute condition d'erreur dans chaque bloc de code.

Au lieu de travailler de bas en haut, je m'inquiète généralement de l'affichage des exceptions levées aussi tard que possible dans le processus (c'est-à-dire aussi près que possible du "sommet" de la pile d'appels). Normalement, je n'essaie pas de remplacer les messages dans les exceptions générées à des niveaux bas de mes applications - en particulier du fait que l'utilisation de ces membres de bas niveau a tendance à devenir de plus en plus abstraite à mesure que l'appel devient profond. J'ai tendance à intercepter et à consigner les exceptions dans les couches métier et inférieure, puis à les afficher de manière compréhensible dans le niveau présentation.

Voici quelques articles intéressants sur les meilleures pratiques de gestion des exceptions:

http://www.codeproject.com/KB/architecture/exceptionbestpractices.aspx

http://aspalliance.com/1119

Jeez cela a mot ... excuses à l'avance.

Oui, les exceptions coûtant cher, il est donc coûteux de capturer, de rediffuser ou de lancer une exception plus utile.

Mais attendez une minute! Si le code d'infrastructure ou la bibliothèque que vous utilisez lève une exception, cela se produit déjà. Avez-vous des exigences non fonctionnelles concernant la rapidité avec laquelle un message d'erreur est propagé à la suite d'une exception? J'en doute. Est-ce vraiment un gros problème? Quelque chose d'imprévu et d'exceptionnel s'est produit. L'essentiel est de présenter des informations sensibles et utiles à l'utilisateur.

Je pense que vous êtes sur la bonne voie avec ce que vous faites.

Bien sûr que c'est horriblement inefficace. Mais au moment où une exception survient suffisamment importante pour être montrée à l'utilisateur final, vous ne devriez pas vous en soucier.

Là où je travaille, nous n’avons que quelques raisons d’attraper des exceptions. Nous ne le faisons que lorsque ...

  1. Nous pouvons faire quelque chose à ce sujet - par exemple, nous savons que cela peut arriver parfois et nous pouvons le corriger dans le code au fur et à mesure (très rarement).

  2. Nous voulons savoir ce qui se passe et où (nous revenons à l'exception).

  3. Nous souhaitons ajouter un message convivial. Dans ce cas, nous encapsulons l'exception d'origine dans une nouvelle copie dérivée de l'exception d'application, nous y ajoutons un message convivial, puis nous la laissons bouillir sans changement à partir de ce point.

Dans votre exemple, nous nous contenterions probablement d'afficher "Une erreur de connexion s'est produite". anbd en reste là tout en enregistrant la véritable erreur et en fournissant un pourquoi à l'utilisateur qui veut explorer l'exception s'il le souhaite également. (Peut-être un bouton sur le formulaire d'erreur).

  1. Nous voulons supprimer complètement l'exception et continuer. Il va sans dire que nous ne le faisons que pour les types d'exceptions attendus et uniquement lorsqu'il n'existe aucun autre moyen de détecter la condition qui génère l'exception.

Généralement, lorsque vous faites face à des exceptions, performances et efficacité sont le moindre de vos soucis. Vous devriez être plus inquiet à l'idée de faire quelque chose pour aider l'utilisateur à résoudre le problème. En cas de problème lors de l'écriture d'un certain enregistrement dans la base de données, annulez les modifications ou au moins videz les informations sur les lignes afin que l'utilisateur ne les perde pas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top