IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Dotnet Discussion :

Les exceptions métiers


Sujet :

Dotnet

  1. #1
    Membre éclairé
    Inscrit en
    Avril 2006
    Messages
    346
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 346
    Par défaut Les exceptions métiers
    Bonsoir,

    vous allez encore dire "encore une question sur la bonne utilisation des exceptions". Ce n'est pas vraiment ça.
    Nous sommes partagés au sein de notre équipe sur la bonne utilisation des exceptions. J'aimerais avoir votre avis sur la question. Je considère pour ma part qu'une exception ne doit être lancé que lorsqu'une situation anormale se produit au sein de l'application: "Echec de connexion à la base de données", "Echec d'ouverture d'un fichier" ou "Arguments passés à une méthode publique non corrects".

    Je développe actuellement une application qui doit notamment valider l'épaisseur d'une feuille de papier enroulée en bobine. J'ai développé une méthode métier qui contrôle si l'épaisseur est dans la tolérance avant de la sauvegarder en base de données. L'un de mes collègues considère que ma méthode devrait retourner une exception métier "EpaisseurIncorrectException" alors que moi je pense que ma méthode devrait retourner un booleen: FALSE->Epaisseur incorrect, TRUE->Epaisseur correct.

    Autre exemple concret, une méthode d'authentification d'un utilisateur.
    Ce même collègue considère que cette méthode devrait lancer une exception "InvalidPasswordException" si le mot de passe est incorrect et une exception "InvalidUserException" si l'utilisateur n'existe pas.
    Moi je pense que la méthode devrait retourner un booleen: FALSE->Echec d'authentification, TRUE->Utilisateur authentifié.
    Il argumente en disant à juste titre: "Comment fais-tu avec ton booleen pour distinguer si l'utilisateur ou le mot de passe sont invalides ?"

    Et vous qu'en pensez-vous ?

    Merci de me faire profiter de votre expérience.
    ++

  2. #2
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    En général il faut éviter de lever des exceptions si ce n'est pas nécessaire, les cas que tu cites en font partis comme tu l'as compris.

    Une exception c'est pour les situations anormales que l'on ne peut pas gérer de manière simple :
    - connexion à un serveur (pas de réseau, lenteur réseau et donc timeout, ...)
    - suppression d'un fichier (le fichier peut être pris par un processus, l'utilisateur n'a pas les droits, ...)
    - ...

    Pour ce qui est du contrôle des données, un retour booléen vrai/faux qui indique si la donnée est correcte suffit largement. Eventuellement on peut imaginer renvoyer un booléen ainsi qu'une chaîne pour indiquer le problème le cas échéant (et l'afficher à l'utilisateur). Mais surtout pas d'exception, le contrôle de données saisies par l'utilisateur n'est pas quelque chose d'anormal.

    Pour la connexion de l'utilisateur pareil, la saisie d'un mot de passe invalide n'a rien d'une situation anormale, c'est même tout le contraire dans ce contexte. Il faut juste un objet dédié à la gestion de la connexion qui permettra d'avoir les informations nécessaires si besoin.

    On pourrait imaginer par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    LoginManager login = new LoginManager();
    if (!login.Login("toto", "motdepasse"))
    {
        switch(login.FailReason)
        {
            case FailReason.BadLogin:
                // Traitement si échec car login inexistant.
                break;
            case FailReason.BadPassword:
                // Traitement si échec car mot de passe incorrect.
                break;
            default:
                    throw new ArgumentException("On ne doit pas passer là. Exception pour le debug");
        }
    };
    C'est un exemple comme un autre. Pour l'exception c'est quelque chose que je fais en général sur un switch avec une énumération, lorsque je sais que l'énumération peut être amené à évoluer (et même lorsque ce n'est pas le cas, par habitude). Comme ça si j'oublie de modifier je me ferais rappeler à l'ordre pendant le développement ou les tests

    Au final tout le problème c'est de déterminer ce qu'est une situation normale/anormale, afin de savoir s'il faut ou non utiliser une exception. Et là, tout dépend du contexte.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    948
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 948
    Par défaut
    Je pense que les 2 approches se valent, le tout c'est d'etre homogène sur le programme pour ne pas avoir parfois des exceptions, parfois des valeurs de retour.

    Perso je pencherais plutot pour ton approche, en revanche il est vrai qu'un booléen c'est peu parlant. Je recommande plutot de retourner un objet qui peut comporter un entier (0=OK, puis a toi de mettre des numeros pour les differentes erreurs attendues) et une chaine de caractere qui décrit le probleme ("Utilisateur inconnu" par exemple), puis il se peut qu'il évolue en fonction des besoins. Cet objet peut-être programmé une fois et réutilisé à chaque fois qu'une fonction peut contenir des erreurs.

  4. #4
    Membre chevronné Avatar de MetalGeek
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    412
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 412
    Par défaut
    Salut,

    je pense pour ma part que les deux approches ne se valent pas du tout.

    Les "exceptions" portent bien leur nom : elles sont faites pour signaler que le programme exécute une opération qui ne doit pas être possible en fonctionnement normal. Par exemple, tester si l'épaisseur de papier est correcte, et signifier qu'elle ne l'est pas, fait partie du fonctionnement normal de l'application, et je pense à 100% de certitude qu'il ne faut pas lever d'exception à cet endroit.
    Pour ton second exemple, pas besoin d'exception non plus.
    Pour ce qui est de
    "Comment fais-tu avec ton booleen pour distinguer si l'utilisateur ou le mot de passe sont invalides ?"
    il n'y a pas que les booléens dans la vie, heureusement ! Tu créés soit une enum du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public enum AuthenticationState
    {
        UnknownError,
        InvalidUsername,
        InvalidPassword,
        Succeeded
    }
    si tu veux aller vite, sinon en mieux tu créés un type encapsulant un booléen pour "OK" ou "rejeté" + une enum spécifiant la raison de l'echec (c'st d'ailleurs le modèle choisi par Microsoft dans le système d'appartenance Membership dans ASP).

    Voilà, bon code...

  5. #5
    Membre éclairé
    Inscrit en
    Avril 2006
    Messages
    346
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 346
    Par défaut
    Super, vous me donnez raison.
    Merci pour vos réponses.
    Est-ce que d'autres ont un avis sur la question ?

    ++

  6. #6
    Membre averti
    Inscrit en
    Septembre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 22
    Par défaut
    Je trouve que gérer les erreurs avec des exception est plus pratique.
    Par exemple lors de la création d'un nouvel utilisateur :
    - dans la méthode de la page lié au clic sur le bouton, on catche les exceptions de type "ExceptionMetier" (dont vont hérité des exceptions du genre "MotDePasseTropCourtExcetpion" ou "LoginDejaPrisException").
    Dans ce cach on fait directement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    catch(ExceptionMetier em)
    {
    	afficherDansUnePopup(em.message);
    }
    De plus, la valeur de retour est souvent utile pour autre chose que l'erreur.
    Par exemple pour connaitre l'Id de l'utilisateur qui a été créé (utile pour les TU)

  7. #7
    Membre éclairé
    Inscrit en
    Avril 2006
    Messages
    346
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 346
    Par défaut
    Et bien ça relance le débat.

    Citation Envoyé par Kalagan64
    Je trouve que gérer les erreurs avec des exception est plus pratique.
    C'est un peu l'argument qu'avance mon collègue.

    Je ne sais pas quels sont vos niveaux d'expériences dans le développement. Je ne sais pas à quel saint me vouer.

    J'ai toujours cru comprendre que lancer des exceptions consommaient excessivement des ressources. Qu'en est-il ? Est-ce vrai ?

    En faveur de Kalagan64, j'ai lu sur la MSDN, la phrase suivante:

    Exceptions offer several advantages over other methods of error notification, such as return codes. Failures do not go unnoticed. Invalid values do not continue to propagate through the system. You do not have to check return codes. Exception-handling code can be easily added to increase program reliability. Finally, the runtime's exception handling is faster than Windows-based C++ error handling.
    Handling and Throwing Exceptions

    Petite parenthèse:
    Citation Envoyé par Kalagan64
    utile pour les TU
    Qu'est-ce qu'un TU ?

    Merci d'avance,
    ++

  8. #8
    Membre averti
    Inscrit en
    Septembre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 22
    Par défaut
    Citation Envoyé par zoaax Voir le message
    Qu'est-ce qu'un TU ?
    Test Unitaire.

    Pour l'exemple dont je parlais, récupérer l'Id de l'utilisateur créé n'a a priori pas vraiment d'utilité dans l'application. Mais dans le TU on pourrais ensuite, grâce a cet Id, vérifier que l'utilisateur créé a bien été créé et avec les bonnes infos.

  9. #9
    Membre Expert Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Par défaut
    J'imagine mal un cas où des exceptions métier seraient vraiment intéressantes. J'aurais donc tendance à dire qu'il faut éviter. On peut s'en sortir autrement, de façon plus élégante.

    Citation Envoyé par StormimOn Voir le message
    On pourrait imaginer par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    LoginManager login = new LoginManager();
    if (!login.Login("toto", "motdepasse"))
    {
        switch(login.FailReason)
        {
            case FailReason.BadLogin:
                // Traitement si échec car login inexistant.
                break;
            case FailReason.BadPassword:
                // Traitement si échec car mot de passe incorrect.
                break;
            default:
                    throw new ArgumentException("On ne doit pas passer là. Exception pour le debug");
        }
    };
    Personnellement, j'irais encore plus loin.
    Plus quelque chose du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UserAccount connectedUser = loginManager.Login(...);
    Avec un UserAccount spécial NotAUserAccount, héritant de UserAccount.

    Citation Envoyé par Kalagan64 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    catch(ExceptionMetier em)
    {
    	afficherDansUnePopup(em.message);
    }
    De la même façon, ici, c'est pas une bonne idée de lancer des exceptions dans la GUI ou la console, ou bref... peu importe : aussi près de l'utilisateur.
    A ce niveau là, on est plus dans le contexte où on aurait pu gérer l'exception proprement.

  10. #10
    Membre chevronné Avatar de MetalGeek
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    412
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 412
    Par défaut
    La citation de la MSDN est pourtant claire : il s'agit de notifier des erreurs. Or, je pense que le problème dans ce "mini-débat" est bien là : qu'est-ce qu'une erreur dans un programme ? Quand la MSDN parle d'"erreur" gérée par une exception, elle parle d'erreur programme, de quelque chose d'anormal. Un utilisateur qui rentre un mauvais mot de passe, ce n'est pas une erreur, c'est un cas d'utilisation normal - je dirais même plus, lorsque tu fais un site internet avec une zone restreinte aux membres enregistrés, selon le thème de ton site tu as beaucoup plus de demandes de connexions avec des mauvais mots de passe qu'avec les bons...
    Pour moi y'a pas photo, on ne doit pas gérer ce genre de cas avec des exceptions !

  11. #11
    Membre émérite
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    652
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 652
    Par défaut
    Citation Envoyé par MetalGeek Voir le message
    La citation de la MSDN est pourtant claire : il s'agit de notifier des erreurs. Or, je pense que le problème dans ce "mini-débat" est bien là : qu'est-ce qu'une erreur dans un programme ?
    Toujours dans MSDN :
    Citation Envoyé par MSDN
    Performance Considerations
    A significant amount of system resources and execution time are used when you throw or handle an exception. Throw exceptions only to handle truly extraordinary conditions, not to handle predictable events or flow control. For example, your application can reasonably throw an exception if a method argument is invalid because you expect to call your method with valid parameters. An invalid method argument means something extraordinary has occurred. Conversely, do not throw an exception if user input is invalid because you can expect users to occasionally enter invalid data. In such a case, provide a retry mechanism so users can enter valid input.

    Throw exceptions only for extraordinary conditions, then catch exceptions in a general purpose exception handler that applies to the majority of your application, not a handler that applies to a specific exception. The rationale for this approach is that most errors can be handled by validation and error handling code in proximity to the error; no exception needs to be thrown or caught. The general purpose exception handler catches truly unexpected exceptions thrown anywhere in the application.

    In addition, do not throw an exception when a return code is sufficient; do not convert a return code to an exception; and do not routinely catch an exception, ignore it, then continue processing.

  12. #12
    Membre éclairé
    Inscrit en
    Avril 2006
    Messages
    346
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 346
    Par défaut
    pas d'autres commentaires ?

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 97
    Par défaut
    Pour débugger les programmes, j'utilise à chaque fois que possible l'option de Visual Studio qui permet de d'interrompre l'exécution dès qu'une exception est levée. Cela permet de détecter et de corriger très vite les problèmes. Mais une telle approche ne peut marcher que si on respecte un principe simple mais strict : une exception doit être levée uniquement en cas d'erreur.

    De fait, je m'oppose fermement à l'utilisation d'exceptions pour toute raison autre. Lors d'une exécution "normale", un programme n'est pas censé lever d'exception.

Discussions similaires

  1. [Exception]Comment gérer les exceptions ?
    Par Gildas Huart dans le forum Général Java
    Réponses: 7
    Dernier message: 29/03/2005, 18h01
  2. imprimer les exception
    Par deeal dans le forum Général Python
    Réponses: 2
    Dernier message: 05/01/2005, 16h16
  3. Utiliser les exceptions pour un traitement particulier ?
    Par Blustuff dans le forum Assembleur
    Réponses: 11
    Dernier message: 01/12/2004, 02h21
  4. [Exceptions] Pb avec les exceptions
    Par joquetino dans le forum Langage
    Réponses: 11
    Dernier message: 22/09/2004, 17h08
  5. Intercepter les 'Exceptions'
    Par Teo dans le forum ASP
    Réponses: 3
    Dernier message: 05/01/2004, 19h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo