Avec plus de 4 ans de développement en Java, Une chose que je rencontre régulièrement est les exceptions (je crois que c’est la même chose pour les autres). Pour les développeurs, les exceptions ne sont pas vus rigoureusement et méthodiquement en général. On les traite quand on est obligé de faire ça (si c’est une “checked exception”) et souvent d’une façon passive (ajouter try/catch avec un System.out.println(), ajouter le “throws” dans la signature de la méthode, …), juste pour contourner le problème et faire compiler le programme. Ou bien il y a des gens qui ont choisi la solution d’ajouter les log/System.out.println() partout dans le programme, ce qui fait le code comme un spaghetti, haché, mélange de moutard, ketchup, mayonnaise, tartare, oignon,
banane, chocolat, thé, café, …

J’ai plusieurs fois réfléchi sur ce problème. Qu’est-ce qu’on peut faire pour mieux vivre avec les exceptions ? Une approche plus active, oui, mais comment ?
Il faut penser aux exceptions plut tôt dans le cycle de développement, à l’étape de design, c’est la responsabilité des architectes. Il faut aussi avoir une politique cohérente vis-à-vis le traitement des exceptions, ne pas laisser
chaque programmeur traiter les exceptions qu’il rencontre de sa façon, comme il veut, comme il peut, quand il veut – c’est la responsabilité des chefs de projets, des MOEs. Mais alors, les développeurs, qu’est-ce qu’ils peuvent faire ? N’oubliez pas que ce sont eux qui vont confronter directement avec les exceptions.
Même s’il y a des guides au niveau d’architecture, au niveau de gestion de projet, ça ne rend pas les développeurs plus actifs dans le traitement des exceptions si on ne change pas leur façon de penser, leur point de vue sur les exceptions.

Le langage Java nous fournit un bon moyen pour communiquer les exceptions – les “checked exceptions”. Ce sont les exceptions qu’on ne peut pas ignorer (à la différence des “unchecked exceptions”). On doit obligatoirement dans le code utiliser le try/catch pour traiter les exceptions ou ajouter le “throws” dans la signature de la méthode pour déléguer le traitement de l’exception.
Les exceptions font partie de l’interface publique de la méthode. Si elle est là, c’est-à-dire elle porte un message. Malheureusement ce message est souvent malcompris et mal-traité. Le problème est que même si on ne peut pas ignorer les “checked exceptions”, on peut les contourner. Une méthode déclare try/catch pour une exception, mais le bloc catch est vide, il n’y a pas de traitement! Dans la programmation ça s’appelle “avaler une exception” (swallow the exception) et c’est le pire des cas.

Normalement, quand il y a une exception, on pense à une anomalie. Ce n’est pas dans la logique du programme, c’est une chose anormale qui demande un traitement spécial. Ah non, il faut changer cette pensée.
Une exception peut signifier une anomalie qui demande un traitement spécial – souvent un intervient des hommes
(comme par exemple une coupure de réseau, la lecture d’un fichier qui n’existe pas, …). Mais une exception peut aussi signifier un cas normale parfaitement dans la logique du programme (quand on veut débiter une somme dans un compte mais le compte n’a pas suffisamment d’argent, ou le programme essaie de lire un fichier dont le chemin entré par l’utilisateur est incorrect, …) et dans ce cas, c’est à programmer de traiter l’exception.

J’ai trouvé un excellent article dédié au traitement des exceptions : Effective Java Exceptions

Un petit résumé de cet article

  • Java exceptions est une façon de communiquer d’une méthode, elles méritent notre attention tout comme le nom de la méthode ou ses paramètres.
  • La façon dont une équipe traite les exceptions parle beaucoup de leurs compétences.
  • Traiter passivement les exceptions ou ne pas les traiter du tout est une cause principale de désordre et retardement dans les projets.
  • Etablissement d’une convention au niveau d’architecture pour le traitement des exceptions devrait être une des premières décisions dans un projet.

Les exceptions se divisent en deux types: Contingence et Faute

Contingence (Contingency)
“An expected condition demanding an alternative response from a method that can be expressed in terms of the method’s intended purpose. The caller of the method expects these kinds of conditions and has a strategy for coping with them.”
(Une condition attendue qui demande une réponse alternative de la méthode et peut être représentée comme un des résultats prévus de la méthode. L’utilisateur de la méthode doit prendre conscience de ce type de conditions et avoir une stratégie pour les faire face.)

Faute (Fault)
“An unplanned condition that prevents a method from achieving its intended purpose that cannot be described without reference to the method’s internal implementation.”
(Une condition inattendue qui empêche une méthode de retourner ses résultat prévus et qui ne peut pas être décrite sans référencier à l’implémentation interne de la méthode.)

Contingency_Fault

Les “Java checked exceptions” jouent parfaitement le rôle des contingences. Et parce que les contingences font partie au contrat sémantique de la méthode, c’est logique d’utiliser l’aide du compilateur pour garantir le traitement de ces conditions.

Les fautes ne font pas partie de la logique du programme. Elles doivent être résolues par les hommes. C’est pourquoi les “Java unchecked exceptions” peuvent être utiliser pour représenter les fautes.

Traitement des fautes dans l’application

Quatre objectifs pour un framework de traitement de faute:

  • Minimizer l’encombrement du code
  • Capturer et préserver les diagnostics
  • Avertir la bonne personne
  • Arrêter doucement les activités

Utiliser les “unchecked exceptions” pour les fautes

On peut reconnaitre qu’il existe les méthodes dans la librairie Java ou autres APIs qui utilisent “checked exceptions” pour représenter ce qui est une faute dans le contexte de notre application. Dans ce cas, on peut capturer l’exception, la traiter comme une faute et puis rejeter un “unchecked exception” pour alerter une faute et capturer les informations diagnostiques. Ce choix doit être conventionné et cohérent dans l’équipe.

Utiliser plusieurs type de “unchecked exception” pour les fautes peut être redondant. Parce que les fautes sont traitées toujours de même façon (intervient de l’homme). Par contre, un bon message de faute est utile et suffit dans la plupart des cas. On peut utiliser RuntimeException si notre environnement est Java 1.4 ou supérieur. Avec le support “exception chaining”, on peut remonter jusqu’à l’exception source du problème.

Etablir une barrière de faute (fault barrier)

Le but est de libérer les parties fonctionnelles de la responsabilité de traitement des fautes.

Dans le pattern de barrière de faute, tous les composants de l’application peuvent jeter une exception faute, mais seulement le composant qui joue le rôle de “barrière de faute” capture les fautes.

Les travaux d’une barrière de faute:

  • enregistrer les informations contenues dans la faute pour les actions futures. La bonne place pour ces informations est le log de l’application.
  • fermer l’opération d’une manière contrôllée.

Quand il existe une barrière de faute et les développeurs la connaissent, les tentations de traiter les fautes individuellement diminuent nettement. Résultat: le code est plus claire, plus propre et plus maintenable.

Traitement des contingences dans l’application

On peut utiliser les “checked exceptions” pour les contingences.

Si la sémantique de la méthode est suffisamment simple, on peut utiliser les valeurs retournées pour les contingences. Cela enlève les lourdeurs qui viennent avec les exceptions mais elle enlève aussi l’obligation de traiter les contingences posée par le compilateur.

Bien logger l’application

Les logs pour les fautes sont utils et nécessaires parce qu’elles demandent des intervients des hommes. Mais ce n’est pas le cas pour les contingences.

Trop logger les contingences ne fait qu’encombrer le code et le log pour peu de bénéfice. Si une contingence représente un événement vraiment significatif, on peut logger l’événement avant de jeter une exception.

Voici l’image qui résume le pattern de barrière de faute

Fault barrier pattern

Et pour nourrir encore le cerveau, voici l’idée de Bruce Eckel, l’auteur de “Penser en Java”: Does Java need Checked Exceptions?

Advertisements