Représentation des règles métier avec des exceptions

16

Je sais que c'est cher mais (OMI) je pense que c'est une très bonne pratique. Je parle de règles comme, par exemple, vous ne pouvez pas enregistrer une facture si vous n'êtes pas un vendeur ... donc dans ce cas, lever une exception disant `` vous n'êtes pas autorisé '' ou autre ...

Une autre approche serait d'avoir des objets avec un statut ou quelque chose comme ça

Y a-t-il une autre approche? comment te sens-tu à propos de ça?

sebagomez
la source

Réponses:

15

Si vous entendez représenter des contrôles de règles métier individuels avec des exceptions, je ne pense pas que ce soit une très bonne idée. Plusieurs fois, vous devez signaler plus d'une condition ayant échoué et ne pas vous arrêter sur la première.

D'un autre côté, je crois que la vérification de toutes les règles, puis la levée d'une exception avec le résumé est une bonne pratique.

matiash
la source
1
C'est exactement comme ça que je le gère dans mes applications. Utiliser FluentValidation pour me faciliter la vie et la méthode ValidateAndThrow me sauvent la journée.
Matteo Mosca
Dans une application d'interface utilisateur, je suis entièrement d'accord, mais dans une application de niveau de service, je générerais une exception si je recevais un objet non conforme aux règles métier. Si vous utilisez les deux en combinaison, vous ajoutez parfois une fonction de validation ou une erreur complexe, comme le décrit matiasha dans la dernière phrase.
Bill
8
Lancez une exception spécifique au domaine . Cela vous permet de séparer le nôtre et le non-nôtre plus haut.
@ Thorbjørn Ravn Andersen +1 grand ajout "spécifique au domaine"
Justin Ohms
1
@JamesPoulson, il peut être suffisant de créer en JamesPoulsonExceptiontant que sous-classe de RuntimeException, puis de fournir l'exception d'origine en tant que cause. Vous pouvez alors simplement dire if (exception instanceof JamesPoulsonException)... de différencier. Utilisez la getCause()méthode pour atteindre l'exception d'origine.
9

Dans l'exemple que vous nous avez donné, je pense que lever une exception est une mauvaise idée. Si vous savez que l'utilisateur n'est pas autorisé avant de commencer à travailler et que vous lui permettez de faire certaines fonctions, puis de lui donner un message APRÈS avoir terminé la tâche, c'est juste une mauvaise conception.

L'utilisation d'exceptions pour appliquer les règles métier n'est pas une bonne conception.

Walter
la source
Ce que je comprends de ce que vous avez dit, c'est que vous n'êtes pas d'accord avec l'interface utilisateur. Je suis d'accord avec ça. Je suis d'accord avec vous qu'une interface utilisateur beaucoup plus conviviale ne vous permettrait pas de mettre à jour quelque chose que vous n'êtes pas autorisé. Mais cela ne signifie pas que la validation et la vérification des exceptions dans le cœur de métier ne sont pas nécessaires. Au contraire, je pense qu'ils sont indispensables. Vous en avez besoin pour vous assurer qu'une interface utilisateur mal programmée ne permet pas une mauvaise utilisation de BL.
Fede
8
@Fede: c'est une question de séparation des préoccupations. L'interface utilisateur est chargée de recueillir les intentions de l'utilisateur et de signaler les commentaires de la couche métier. Le travail de la couche métier consiste à analyser les informations collectées par l'interface utilisateur, à les analyser et à faire rapport à l'interface utilisateur et / ou à demander à la couche de données de conserver certaines données. Il ne devrait y avoir qu'un couplage lâche entre ces couches. Les exceptions sont une mauvaise, mauvaise approche du couplage lâche. Cela signifie non seulement le partage de classes réelles entre les couches, mais également un mécanisme destiné à gérer les échecs inattendus.
Adam Crossland
@Adam - Bien dit et exactement au point.
Walter
1
@Adam - Ne vous suivez pas avec la séparation des problèmes. Je ne m'attends pas à ce que quiconque dans l'interface utilisateur gère une exception CustomerNameInLowercaseException (s'il vous plaît, j'espère également que cette exception n'existe même pas!). Vous pouvez simplement gérer une ValidationException générique. En outre, je suis à 100% avec vous que l'interface utilisateur ne devrait recueillir que des informations, et tout cela. Ce que j'ai dit auparavant, c'est que peu importe ce que vous faites dans l'interface utilisateur, le BL ne devrait pas supposer que chaque entrée est correcte. C'est juste une programmation défensive.
Fede
@Fede: c'est le travail du Business Layer de s'assurer que chaque entrée est OK. Si l'interface utilisateur le fait, elle met en œuvre la logique métier. Maintenant, si c'est le cas qu'un champ d'entrée est limité aux chiffres et la BL voit alpha caractères, par tous les moyens jettent une exception . Chaque fois qu'un composant reçoit des entrées non valides d'un autre composant, lever une exception est logique et correct. L'interface a été cassée et le système est cassé. Cependant, la validation des entrées est très différente de l'exécution de la logique métier. Deux choses très différentes.
Adam Crossland
5

Je ne vois pas quelle valeur donner une exception à la création d'une bonne logique métier. Il existe des dizaines d'approches de gestion de la logique métier qui n'impliquent pas l'utilisation d'un système destiné à faire face à des conditions inattendues dans le fonctionnement d'un système.

Il est prévu que dans la logique métier, les conditions ne seront pas remplies; c'est la raison de l'avoir en premier lieu, et vous ne voulez pas utiliser le même mécanisme qui gère les échecs d'E / S inattendus, les erreurs de mémoire et les références nulles. Ce sont des défaillances du système, mais la détection de conditions commerciales non satisfaites est le bon fonctionnement du système.

De plus, c'est un système mûr pour des conséquences imprévues. Puisqu'une exception doit être interceptée à un moment donné, vous courez le risque de voir une nouvelle exception de règle métier finie être interceptée quelque part où elle n'est pas prévue ou vous avez la chance d'avoir le code qui recherche des règles métier interceptant des exceptions qui ne sont pas réellement destinées pour ça. Oui, ces conditions peuvent être expliquées par de bonnes pratiques de codage, mais dans tout système non trivial sur lequel plusieurs développeurs travaillent, des erreurs se produiront et il suffit d'espérer qu'elles ne seront pas coûteuses.

Adam Crossland
la source
1
Je suis d'accord, les exceptions sont appelées exceptions parce qu'elles ne devraient pas se produire. D'un autre côté, appliquer des règles métier dans votre niveau de service avec une exception n'est pas nécessairement faux. Vous ne vous attendez pas à ce qu'il soit utilisé, vous vous attendez à ce que le client appelle uniquement des opérations et ne soumette que des données qui remplissent des conditions valides; mais vous souhaitez intégrer une couche de protection car vous savez que des erreurs peuvent également se produire dans le codage client. Un peu comme utiliser des contraintes de clé étrangère dans une base de données: vous vous attendez à ce que les gens insèrent et mettent à jour les données correctement, mais savent qu'ils pourraient échouer en raison d'une erreur de programmation.
Jeremy
2

exprimer des règles d'affaires est une chose, les mettre en œuvre en est une autre

pensez à l'expérience utilisateur; si l'utilisateur n'est pas un vendeur, pourquoi leur donner un bouton qui dit « créer facture » du tout ?

Steven A. Lowe
la source
1
Tout simplement parce que vous ne donnez pas de bouton, cela ne signifie pas qu'ils ne vous enverront pas le message de toute façon. Imaginez à quel point les règles de sécurité seraient faciles si c'était tout ce qu'il fallait ..
jmoreno
Si l'utilisateur n'est pas autorisé à faire X, ne lui donnez pas un bouton qui dit "Do X". La meilleure sécurité est l'ignorance - ne dites pas à l'utilisateur ce qu'il ne peut pas faire;)
Steven A. Lowe
1

Cela dépend entièrement de ce qui se fait.

Tout d'abord, quel est le comportement réel que vous souhaitez? Si quelqu'un entre ses propres informations, un rejet et une boîte de dialogue disant, "Vous ne pouvez pas faire cela" sont probablement corrects. S'il s'agit d'une personne chargée de la saisie de données, travaillant à partir d'une pile de formulaires, une boîte de dialogue est probablement également bonne, et la personne chargée de la saisie des données peut placer les formulaires invalides dans une pile spéciale. Si vous effectuez un traitement par lots, vous ne voulez pas interrompre les choses, mais signalez-le et passez au suivant.

Une fois que vous avez le comportement, vous devez décider comment vous allez l'implémenter. Avoir un vérificateur de règles métier qui lève une exception est probablement une bonne idée. Renvoyer un code retour et le faire passer est quelque chose d'autre qui peut mal tourner, et vous ne voulez certainement pas que les entrées erronées continuent.

Ne vous inquiétez pas des dépenses de performance. Dans le cas d'un individu saisissant des données, c'est trivial par rapport aux autres temps impliqués. Typiquement, l'humain prendra le plus de temps dans ce système. Dans le cas d'un travail par lots, si les exceptions sont un problème de performances, vous saisissez beaucoup trop de mauvais enregistrements, et en réalité, la gestion et la nouvelle saisie de tous ces problèmes seront plus problématiques que les exceptions.

David Thornley
la source
0

Il est très approprié d'avoir une API d'exception robuste et bien conçue qui soit cohérente. L'utiliser pour appliquer les règles métier peut également être approprié. En fait, d'après mon expérience, plus la règle commerciale est compliquée, plus elle est susceptible d'être traitée de cette façon. Il est souvent aussi simple, sinon plus facile, d'écrire un système dans lequel des exceptions sont attendues que d'écrire une logique de branchement faisant autorité.

Cela revient à dire que les règles simples qui peuvent être décrites en une seule phrase doivent généralement être mises en œuvre de manière préventive ou faisant autorité selon le cas. Cependant, si vous avez une règle qui est multidimensionnelle et nécessite plus de trois ou quatre facteurs (en particulier si la sélection de ces facteurs est basée sur un ou plusieurs des autres facteurs), le codage d'exception peut être plus facile à gérer. Souvent, dans ces cas, le chemin logique comporte de nombreuses exceptions de précurseurs qui doivent être levées (vérifie pourquoi l'action ne peut pas être effectuée), puis (ou vice versa), il y a une défaillance de la sécurité (pour vérifier que l'action est autorisée ), il y aura parfois une logique d'accumulation faisant autorité qui doit être vérifiée (disponibilité des descendants / ancêtres, états précurseurs dans lesquels les objets doivent être placés, etc.)

Un avantage qui dérive de ce type de levée d'exceptions est qu'il vous permet de séparer et de réutiliser les exceptions de précurseur dans plusieurs zones de votre projet. (C'est l'essence même de la programmation orientée aspect.) Ce faisant, vous encapsulez un aspect particulier de vos règles commerciales générales dans un composant autonome et maintenable. En général, ces composants correspondront 1-1 aux messages d'erreur lancés. (Bien que parfois vous ayez un composant qui lève plusieurs exceptions différentes, vous ne devriez presque jamais avoir la même exception levée à partir de plusieurs composants.)

À mon avis, il est plus difficile de concevoir des systèmes basés sur des exceptions et le temps de développement initial est plus long, car vous devez créer le processus d'exception à tous les N niveaux. Cependant, ces systèmes finissent généralement par être beaucoup plus stables. Bien qu'il ne soit jamais possible de concevoir un système qui «n'échouera pas», l'avantage de la conception basée sur les exceptions est que vous anticipez toujours une défaillance. Pour la plupart des gens, le processus peut être contre-intuitif. C'est comme demander des directions et demander à quelqu'un de vous dire toutes les rues que vous ne devriez pas activer.

Justin Ohms
la source