Quelle est la meilleure pratique lorsqu'une exception non gérée se produit dans une application de bureau?
Je pensais à montrer un message à l'utilisateur, afin qu'il puisse contacter le support. Je recommanderais à l'utilisateur de redémarrer l'application, mais pas de la forcer. Semblable à ce qui est discuté ici: ux.stackexchange.com - Quelle est la meilleure façon de gérer les erreurs d'application inattendues?
Le projet est une application .NET WPF, donc la proposition décrite pourrait ressembler à ceci (Notez qu'il s'agit d'un exemple simplifié. Il serait probablement judicieux de masquer les détails de l'exception jusqu'à ce que l'utilisateur clique sur "Afficher les détails" et fournisse des fonctionnalités à signaler facilement l'erreur):
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += OnDispatcherUnhandledException;
}
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
LogError(e.Exception);
MessageBoxResult result = MessageBox.Show(
$"Please help us fix it and contact [email protected]. Exception details: {e.Exception}" +
"We recommend to restart the application. " +
"Do you want to stop the application now? (Warning: Unsaved data gets lost).",
"Unexpected error occured.", MessageBoxButton.YesNo);
// Setting 'Handled' to 'true' will prevent the application from terminating.
e.Handled = result == MessageBoxResult.No;
}
private void LogError(Exception ex)
{
// Log to a log file...
}
}
Dans l'implémentation (commandes de ViewModels ou gestionnaire d'événements d'événements externes), je ne capturais alors que l'exception exogène spécifique et je laissais toutes les autres exceptions (exceptionnelles et exceptionnelles) remonter jusqu'au "Gestionnaire de dernier recours" décrit ci-dessus. Pour une définition des exceptions à tête osée et exogènes, consultez: Eric Lippert - Vexing exceptions
Est-il judicieux de laisser l'utilisateur décider si l'application doit être terminée? Lorsque l'application est terminée, vous n'avez certainement aucun état incohérent ... D'un autre côté, l'utilisateur peut perdre des données non enregistrées ou n'est plus en mesure d'arrêter un processus externe démarré jusqu'à ce que l'application soit redémarrée.
Ou est-ce la décision si vous devez mettre fin à l'application sur des exceptions non gérées en fonction du type d'application que vous écrivez? Est-ce juste un compromis entre «robustesse» et «exactitude» comme décrit dans Code Complete, Second Edition
Pour vous donner un aperçu du type d'application dont nous parlons: L'application est principalement utilisée pour contrôler les instruments de laboratoire de chimie et afficher les résultats mesurés à l'utilisateur. Pour ce faire, les applications WPF communiquent avec certains services (services locaux et distants). L'application WPF ne communique pas directement avec les instruments.
la source
Réponses:
Vous devez vous attendre à ce que votre programme se termine pour plus de raisons qu'une simple exception non gérée de toute façon, comme une panne de courant ou un processus d'arrière-plan différent qui bloque tout le système. Par conséquent, je recommanderais de terminer et de redémarrer l'application, mais avec certaines mesures pour atténuer les conséquences d'un tel redémarrage et minimiser la perte de données possible .
Commencez par analyser les points suivants:
Quelle quantité de données peut-on réellement perdre en cas d'arrêt du programme?
Quelle est la gravité d'une telle perte pour l'utilisateur? Les données perdues peuvent-elles être reconstruites en moins de 5 minutes, ou parlons-nous de perdre une journée de travail?
Combien d'efforts est-ce pour mettre en œuvre une stratégie de «sauvegarde intermédiaire»? N'excluez pas cela parce que "l'utilisateur devrait entrer un motif de changement" lors d'une opération de sauvegarde régulière, comme vous l'avez écrit dans un commentaire. Mieux vaut penser à quelque chose comme un fichier temporaire ou un état, qui peut être rechargé automatiquement après un crash de programme. De nombreux types de logiciels de productivité le font (par exemple, MS Office et LibreOffice ont tous deux une fonction "sauvegarde automatique" et une récupération après incident).
Dans le cas où les données étaient erronées ou corrompues, l'utilisateur peut-il le voir facilement (peut-être après un redémarrage du programme)? Si oui, vous pouvez offrir une option pour permettre à l'utilisateur d'enregistrer les données (avec un peu de chance qu'elles soient corrompues), puis forcer un redémarrage, le recharger et laisser l'utilisateur vérifier si les données semblent correctes. Assurez-vous de ne pas écraser la dernière version qui a été enregistrée régulièrement (au lieu d'écrire dans un emplacement / fichier temporaire) pour éviter de corrompre l'ancienne version.
Si une telle stratégie de «sauvegarde intermédiaire» est une option sensée, cela dépend finalement de l'application et de son architecture, ainsi que de la nature et de la structure des données impliquées. Mais si l'utilisateur perd moins de 10 minutes de travail et qu'un tel crash se produit une fois par semaine ou même plus rarement, je n'y investirais probablement pas trop.
la source
Cela dépend dans une certaine mesure de l'application que vous développez, mais en général, je dirais que si votre application rencontre une exception non gérée, vous devez la terminer.
Pourquoi?
Parce que vous ne pouvez plus faire confiance à l'état de l'application.
Certainement, fournissez un message utile à l'utilisateur, mais vous devez finalement fermer l'application.
Compte tenu de votre contexte, je voudrais certainement que la demande se termine. Vous ne voulez pas qu'un logiciel exécuté dans un laboratoire produise une sortie corrompue et comme vous ne pensiez pas gérer l'exception, vous ne savez pas pourquoi il a été lancé et ce qui se passe.
la source
Étant donné que cela est destiné à un laboratoire de chimie et que votre application ne contrôle pas les instruments directement mais plutôt via d'autres services:
Forcer l'arrêt après avoir affiché le message. Après une exception non gérée, votre application est dans un état inconnu. Cela pourrait envoyer des commandes erronées. Il peut même invoquer des démons nasaux . Une commande erronée pourrait potentiellement gaspiller des réactifs coûteux ou mettre en danger l'équipement ou les personnes .
Mais vous pouvez faire autre chose: récupérer gracieusement après le redémarrage . Je suppose que votre application ne supprime pas ces services d'arrière-plan lorsqu'elle se bloque. Dans ce cas, vous pouvez facilement récupérer l'état d'eux. Ou, si vous avez plus d'état, pensez à l'enregistrer. Dans un stockage qui a des dispositions pour l'atomicité et l'intégrité des données (SQLite peut-être?).
Modifier:
Comme indiqué dans les commentaires, le processus que vous contrôlez peut nécessiter des modifications assez rapidement pour que l'utilisateur n'ait pas le temps de réagir. Dans ce cas, vous devriez envisager de redémarrer silencieusement l'application en plus de la récupération de l'état gracieux.
la source
Essayer de répondre généralement à cette question au niveau supérieur du programme n'est pas un jeu intelligent.
Si quelque chose s'est propagé tout au long du processus, et à aucun moment de l'architecture de l'application, personne n'a considéré ce cas, vous n'avez aucune généralisation à faire sur les actions qui sont ou ne peuvent pas être effectuées en toute sécurité.
Donc, non, ce n'est certainement pas une conception généralement acceptable pour permettre à l'utilisateur de choisir si l'application tente de récupérer ou non, car l'application et les développeurs n'ont manifestement pas fait la diligence nécessaire pour savoir si c'est possible ou même sage .
Cependant, si l'application a des parties à haute valeur de sa logique ou de son comportement qui ont été conçues avec ce type de récupération après défaillance à l'esprit, et qu'il est possible de les exploiter dans ce cas, alors par tous les moyens, faites-le - Dans ce cas , il peut être acceptable d'inviter l'utilisateur à voir s'il souhaite tenter une récupération, ou s'il souhaite simplement l'appeler quitter et recommencer.
Ce type de récupération n'est généralement pas nécessaire ni conseillé pour tous (ou même la plupart) des programmes, mais, si vous travaillez sur un programme pour lequel ce degré d'intégrité opérationnelle est requis, cela pourrait être une circonstance dans laquelle présenter ce type de programme demander à un utilisateur serait une chose sensée à faire.
À la lumière de toute logique spéciale de récupération après défaillance - Non, ne faites pas cela. Vous n'avez littéralement aucune idée de ce qui se passera, si vous l'aviez fait, vous auriez pris l'exception plus bas et l'auriez gérée.
la source
Le problème des "exceptions exceptionnelles", c'est-à-dire des exceptions que vous n'avez pas prévues, est que vous ne savez pas dans quel état se trouve le programme. Par exemple, essayer de sauvegarder les données de l'utilisateur pourrait en fait détruire encore plus de données .
Pour cette raison, vous devez mettre fin à l'application.
Il y a une idée très intéressante appelée Crash-only Software par George Candea et Armando Fox . L'idée est que si vous concevez votre logiciel de manière à ce que la seule façon de le fermer soit de le planter et la seule façon de le démarrer soit de récupérer d'un plantage, alors votre logiciel sera plus résistant et la récupération d'erreur les chemins de code seront testés et exercés de manière beaucoup plus approfondie.
Ils ont eu cette idée après avoir remarqué que certains systèmes démarraient plus rapidement après un crash qu'après un arrêt ordonné.
Un bon exemple, bien que n'étant plus pertinent, est certaines anciennes versions de Firefox qui non seulement démarrent plus rapidement lors de la récupération après un crash, mais ont également une meilleure expérience de démarrage de cette façon ! Dans ces versions, si vous fermez Firefox normalement, il fermerait tous les onglets ouverts et démarrerait avec un seul onglet vide. Alors que lors de la récupération d'un crash, il restaurerait les onglets ouverts au moment du crash. (Et c'était la seule façon de fermer Firefox sans perdre votre contexte de navigation actuel.) Alors, qu'ont fait les gens? Ils n'ont tout simplement jamais fermé Firefox et l'ont toujours
pkill -KILL firefox
édité.Il y a un bon article sur le logiciel crash-only de Valerie Aurora sur Linux Weekly News . Les commentaires méritent également d'être lus. Par exemple, quelqu'un dans les commentaires souligne à juste titre que ces idées ne sont pas nouvelles et sont en fait plus ou moins équivalentes aux principes de conception des applications basées sur Erlang / OTP. Et, bien sûr, en examinant cela aujourd'hui, 10 ans après celui de Valérie et 15 ans après l'article original, nous pourrions remarquer que le battage médiatique actuel des micro-services réinvente encore ces mêmes idées. La conception moderne d'un datacenter à l'échelle du cloud est également un exemple de granularité plus grossière. (Tout ordinateur peut se bloquer à tout moment sans affecter le système.)
Cependant, il ne suffit pas de laisser votre logiciel planter. Il doit être conçu pour cela. Idéalement, votre logiciel devrait être divisé en petits composants indépendants qui peuvent chacun se bloquer de manière indépendante. En outre, le «mécanisme de plantage» doit être en dehors du composant en cours de plantage.
la source
La bonne façon de gérer la plupart des exceptions devrait être d'invalider tout objet qui pourrait être dans un état corrompu en conséquence et de poursuivre l'exécution si les objets invalides ne l'empêchent pas. Par exemple, le paradigme sûr pour la mise à jour d'une ressource serait:
Si une exception inattendue se produit lors de la mise à jour de la ressource protégée, la ressource doit être présumée dans un état corrompu et le verrou invalidé, que l'exception soit d'un type qui serait autrement bénin.
Malheureusement, les gardes de ressources implémentés via
IDisposable
/using
seront libérés à chaque sortie du bloc gardé, sans aucun moyen de savoir si le bloc est sorti normalement ou anormalement. Ainsi, même s'il devrait y avoir des critères bien définis pour savoir quand continuer après une exception, il n'y a aucun moyen de savoir quand ils s'appliquent.la source
Vous pouvez utiliser l'approche suivie par chaque application iOS et MacOS: Une exception non capturée supprime immédiatement l'application. De plus, de nombreuses erreurs, comme un tableau hors limites ou simplement un débordement arithmétique dans les applications plus récentes, font de même. Pas d'avertissement.
D'après mon expérience, de nombreux utilisateurs n'y prennent pas garde, mais appuyez à nouveau sur l'icône de l'application.
De toute évidence, vous devez vous assurer qu'un tel crash ne conduit pas à une perte de données significative et ne conduit certainement pas à des erreurs coûteuses. Mais une alerte «Votre application va planter maintenant. Appelez l'assistance si cela vous dérange »n'aide personne.
la source