Je travaille sur un système qui permet aux administrateurs de définir des formulaires contenant des champs. Les formulaires définis sont ensuite utilisés pour saisir des données dans le système. Parfois, les formulaires sont remplis par un humain via une interface graphique, parfois le formulaire est rempli en fonction des valeurs rapportées par un autre système.
Pour chaque champ, l'administrateur peut définir une règle de validation qui limite les valeurs autorisées pour le champ. Les règles de validation peuvent aller de "la valeur entrée dans le champ doit être vraie ou fausse" à "la valeur entrée dans le champ doit exister dans la colonne A du tableau B dans la base de données". L'administrateur peut à tout moment modifier la règle de validation du champ.
Dans ce scénario, quel est, à votre avis, l'endroit le plus approprié pour valider que chaque champ est correctement rempli? J'ai actuellement deux approches principales en tête:
Option # 1: valider dans le modèle de domaine
Chaque objet Field contiendrait la règle de validation spécifiée par l'administrateur. Les objets Field auraient également une référence à un IValidator. Lorsqu'une tentative est effectuée pour définir la valeur du champ, le champ transmet la valeur donnée et la règle de validation à l'IValidator. Si la valeur donnée n'est pas valide, une ValidationException serait levée et gérée de manière appropriée dans l'interface graphique / l'interface vers l'autre système.
Avantages:
- Protection élevée contre les valeurs attribuées accidentellement aux champs qui violent la règle de validation
Les inconvénients:
La couche d'accès aux données doit pouvoir contourner la validation et construire des champs qui violent la règle de validation actuelle. Bien que l'administrateur ait modifié la règle de validation d'un champ, nous devons encore pouvoir construire des objets de champ sur la base des anciennes données, par exemple lors du rendu d'un formulaire rempli il y a des années. Cela pourrait potentiellement être résolu en stockant la règle de validation actuelle chaque fois que nous stockons le champ.
Dans cette conception, le modèle Field a un lien indirect avec la couche d'accès aux données / référentiel via IValidator. L'injection de services / référentiels aux modèles de domaine semble généralement mal vue .
Option # 2: Valider dans un service
Essayez de vous assurer que toutes les tentatives de définition de la valeur d'un champ passent par un service garantissant le respect de la règle de validation. Si la règle de validation est violée, lancez une ValidationException.
Bien entendu, la couche d'accès aux données n'utilisera pas le service lors de la création d'objets Field qui ont été précédemment conservés dans la base de données.
Avantages:
Ne viole pas la pensée "ne pas injecter de services / référentiels dans vos modèles de domaine".
Pas besoin de conserver la règle de validation actuelle lors de la persistance du champ. Le service peut simplement rechercher la règle de validation actuelle pour le champ; lorsque vous regardez les données d'historique, la valeur du champ ne sera pas modifiée.
Les inconvénients:
- Aucune garantie que toute logique devant utiliser le service pour définir la valeur du champ le fait réellement. Je vois cela comme un inconvénient majeur; tout ce qu'il semble prendre, c'est quelqu'un qui écrit "thisField.setValue (thatField.getValue ())" et la règle de validation de thisField peut être violée sans que personne ne soit plus sage. Cela pourrait potentiellement être atténué en s'assurant que la valeur du champ correspond à la règle de validation lorsque la couche d'accès aux données est sur le point de conserver le champ.
Je préfère actuellement l'option n ° 1 à l'option n ° 2, principalement parce que je considère cela comme une logique métier et je pense que l'option n ° 2 présente un plus grand risque d'introduire de mauvaises données dans le système. Quelle option préférez-vous ou existe-t-il une autre conception qui correspond mieux à ce scénario que les deux options décrites?
Edit (Complexité des validations)
Les cas de validation qui se sont présentés jusqu'à présent sont relativement simples; la valeur du champ doit être par exemple numérique, une date, une date avec une heure ou être une valeur existante dans une colonne de base de données. Cependant, je soupçonne la complexité d'augmenter progressivement avec le temps. Par exemple, la solution de validation doit être conçue en tenant compte de l'internationalisation - des éléments tels que les dates peuvent être saisis dans une syntaxe locale spécifique.
J'ai décidé de continuer avec l'option # 1 pour l'instant, en essayant de ne pas attribuer trop de responsabilités au modèle de domaine. Les personnes confrontées à une situation similaire peuvent également consulter les questions connexes Validation et autorisation dans l'architecture en couches et validation de la saisie de données - Où? Combien? .
Réponses:
Quelle est la complexité des validations? Souvent, les validations nécessitent une combinaison de champs et / ou de règles métier qui reposent sur des champs pour être évalués avec précision.
Plus les validations sont complexes, plus l'option 2 est difficile et moins performante.
Bien entendu, le niveau de données peut appeler le service de validation au moment de la persistance. Cela pourrait aider la situation étrange où les données sont dans un état non valide en raison d'un changement de règles.
L'autre élément qui mérite d'être commenté est la possibilité de modifier les règles de validation sans cycle qa quelconque. Mais c'est un sujet pour un fil différent.
Compte tenu des informations ci-dessus, l'option 1 semble la plus flexible en supposant que vous maintenez la discipline, en séparant la validation et la persistance.
la source
Il vous manque peut-être un calque. Sans connaître les détails de votre application (conditions requises, architecture, etc.), je ferais quelque chose comme Client (quel qu'il soit) -> Service d'application -> Modèle de domaine
La couche de service d'application est autorisée à interagir avec le référentiel et le modèle de domaine contenant la logique métier. Vous pouvez donc avoir quelque chose comme:
Si vous avez une relation entre un Field et ses FieldRules et utilisez un ORM comme Hibernate en Java, vous ne ferez que:
Parce que la requête ORM instancie le graphe des objets que vous demandez.
Concernant votre doute sur le fait que quelqu'un puisse faire
Quelqu'un pourrait également écrire: FieldRule alwaysReturnTrueRule = new FieldRule {isValid (newValue) {return true; }} field.updateValue ("uncheckedValue", alwaysReturnTrueRule) C'est un exemple obscur mais ce que j'essaie de dire, c'est que rien ne vous protège d'une mauvaise utilisation du code. Peut-être une bonne documentation et une bonne communication face à face. Je pense que rien ne vous protège d'une mauvaise utilisation du code.
la source