85 votes

Quelle est la place de la "couche logique métier" dans une application MVC ?

D'abord, avant que quelqu'un ne crie au dupe, j'ai eu du mal à le résumer en un simple titre. Un autre titre aurait pu être "Quelle est la différence entre un modèle de domaine et un modèle MVC ?" ou "Qu'est-ce qu'un modèle ?".

D'un point de vue conceptuel, je comprends qu'un modèle est constitué des données utilisées par les vues et le contrôleur. Au-delà de cela, il semble y avoir beaucoup d'opinions divergentes sur ce qui constitue le modèle. Qu'est-ce qu'un modèle de domaine, par rapport à un modèle d'application, par rapport à un modèle de vue, par rapport à un modèle de service, etc.

Par exemple, dans une question récente que j'ai posée sur le modèle de référentiel, on m'a répondu sans ambages que le référentiel faisait partie du modèle. Cependant, j'ai lu d'autres opinions selon lesquelles le modèle devrait être séparé du modèle de persistance et de la couche de logique métier. Après tout, le modèle de référentiel n'est-il pas censé découpler la méthode de persistance concrète du modèle ? D'autres personnes disent qu'il y a une différence entre le modèle de domaine et le modèle MVC.

Prenons un exemple simple. Le AccountController qui est inclus dans le projet MVC par défaut. J'ai lu plusieurs avis selon lesquels le code Compte inclus est de mauvaise conception, viole le SRP, etc. etc. Si l'on devait concevoir un modèle d'adhésion "correct" pour une application MVC, quel serait-il ?

Comment séparer les services ASP.NET (fournisseur de membres, fournisseur de rôles, etc.) du modèle ? Ou le feriez-vous tout court ?

Selon moi, le modèle doit être "pur", peut-être avec une logique de validation, mais il doit être séparé des règles métier (autres que la validation). Par exemple, disons que vous avez une règle de gestion qui dit que quelqu'un doit être envoyé par e-mail quand un nouveau compte est créé. À mon avis, cela n'a pas vraiment sa place dans le modèle. Alors où doit-elle se trouver ?

Quelqu'un peut-il nous éclairer sur cette question ?

69voto

Josh Points 6036

La façon dont j'ai procédé - et je ne dis pas que c'est bien ou mal - est d'avoir ma vue et ensuite un modèle qui s'applique à ma vue. Ce modèle ne contient que ce qui est pertinent pour ma vue - y compris les annotations de données et les règles de validation. Le contrôleur ne contient que la logique de construction du modèle. J'ai une couche de service qui abrite toute la logique commerciale. Mes contrôleurs appellent ma couche de service. Au-delà de celle-ci se trouve ma couche de référentiel.

Mes objets de domaine sont hébergés séparément (dans leur propre projet, en fait). Ils ont leurs propres annotations de données et règles de validation. Mon référentiel valide les objets de mon domaine avant de les enregistrer dans la base de données. Comme chaque objet de mon domaine hérite d'une classe de base dans laquelle la validation est intégrée, mon référentiel est générique et valide tout (et exige qu'il hérite de la classe de base).

Vous pourriez penser que le fait d'avoir deux ensembles de modèles constitue une duplication du code, et c'est le cas dans une certaine mesure. Mais il existe des cas parfaitement raisonnables où l'objet du domaine n'est pas approprié pour la vue.

Par exemple, lorsque je travaille avec des cartes de crédit, je dois exiger une cvv lors du traitement d'un paiement, mais je ne peux pas stocker la cvv (une amende de 50 000 dollars est prévue pour cela). Mais je veux aussi que vous puissiez modifier votre carte de crédit - changement d'adresse, de nom ou de date d'expiration. Mais vous n'allez pas me donner le numéro ou la cvv pour la modifier, et je ne vais certainement pas mettre votre numéro de carte de crédit en clair sur la page. Mon domaine possède ces valeurs nécessaires à l'enregistrement d'une nouvelle carte de crédit parce que vous me les donnez, mais mon modèle d'édition n'inclut même pas le numéro de carte ou le cvv.

Un autre avantage d'un tel nombre de couches est que, si l'architecture est correcte, vous pouvez utiliser structuremap ou un autre conteneur IoC et échanger des pièces sans que cela n'affecte votre application.

A mon avis, le code du contrôleur ne devrait être que du code ciblé sur la vue. Montrer ceci, cacher cela, etc. La couche de service doit héberger la logique métier de votre application. J'aime avoir toute cette logique à un seul endroit pour qu'il soit facile de changer ou de modifier une règle de gestion. La couche référentiel doit être relativement muette - dépourvue de logique métier et se contenter d'interroger vos données et de renvoyer vos objets de domaine. En séparant les modèles de vue du modèle de domaine, vous disposez d'une plus grande souplesse en ce qui concerne les règles de validation personnalisées. Cela signifie également que vous n'avez pas à déverser chaque élément de données dans votre vue dans des champs cachés et à les faire circuler entre le client et le serveur (ou à les reconstruire en arrière-plan). Votre modèle de vue n'hébergera alors que les informations pertinentes pour la vue - et il peut être personnalisé pour avoir des bools pour la logique de la vue ou des comptes ou des enums afin que la vue elle-même ne soit pas encombrée d'instructions logiques compliquées du type

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

Même si tout semble étalé et superposé, il y a une raison pour laquelle l'architecture a été conçue de cette façon. Est-ce parfait ? Pas vraiment. Mais je la préfère à certaines conceptions antérieures qui consistaient à appeler les référentiels depuis le contrôleur et à mélanger la logique métier dans le contrôleur, le référentiel et le modèle.

17voto

Bozho Points 273663

Moi aussi, je me suis souvent demandé comment les éléments MVC s'intègrent exactement dans une structure d'application web traditionnelle, où il y a des vues (pages), des contrôleurs, des services et des objets de données (modèle). Comme vous l'avez dit, il existe de nombreuses versions de cette structure.

Je pense que la confusion existe à cause de l'architecture largement acceptée mentionnée ci-dessus, qui utilise le "modèle de domaine anémique" (présumé)-anti pattern. Je n'entrerai pas dans les détails de l'"anti-modèle" du modèle de données anémique (vous pouvez consulter une de mes tentatives d'explication). ici (basé sur Java, mais pertinent pour tout langage)). En résumé, cela signifie que notre modèle ne contient que des données et que la logique commerciale est placée dans les services/gestionnaires.

Mais supposons que nous avons architecture axée sur le domaine et nos objets de domaine sont tels qu'ils sont censés être, c'est-à-dire qu'ils possèdent à la fois un état et une logique commerciale. Et dans cette perspective axée sur le domaine, les choses se mettent en place :

  • la vue est l'interface utilisateur
  • le contrôleur recueille les entrées de l'interface utilisateur, invoque des méthodes sur le modèle et renvoie une réponse à l'interface utilisateur.
  • le modèle est notre composant métier - il contient les données, mais aussi la logique métier.

Je suppose que cela répond à vos principales questions. Les choses se compliquent lorsque nous ajoutons d'autres couches, comme celle du référentiel. Il est souvent suggéré qu'elle soit invoquée par la logique métier placée dans le modèle (et donc que chaque objet du domaine ait une référence à un référentiel). Dans l'article dont j'ai donné le lien, je soutiens que ce n'est pas tout à fait une bonne pratique. Et qu'en fait, ce n'est pas une mauvaise chose d'avoir une couche de services. D'ailleurs, la conception orientée domaine n'exclut pas la couche de service, mais elle est censée être "fine" et ne coordonner que des objets de domaine (donc pas de logique métier).

Pour le paradigme du modèle de données anémique, qui est largement adopté (pour le meilleur ou pour le pire), le modèle serait à la fois la couche de service et vos objets de données.

3voto

alliswell Points 3064

A mon avis,

Modèle -

Il ne doit pas contenir de logique d'entreprise, il doit être enfichable (scénario de type WCF). Il est utilisé pour se lier à la vue, il doit donc avoir des propriétés.

Logique d'entreprise -

Il devrait être placé à "Domain Services Layer", c'est une couche distincte. De plus, nous ajouterons une couche supplémentaire ici "Services d'application".

Les services d'application communiquent avec la couche des services de domaine pour appliquer la logique d'entreprise et, enfin, renvoyer le modèle.

Donc, Le contrôleur demandera le modèle au service d'application et le flux sera le suivant,

    Controller->Application Services(using domain services)->Model

2voto

jfar Points 19380

Le modèle MVC et le cadre Asp.net ne font aucune distinction sur ce que doit être le modèle.

Les propres exemples de MS incluent des classes de persistance dans le modèle. Votre question sur l'appartenance au modèle. Cela dépend. Les classes de votre modèle appartiennent-elles à quelque chose ? Existe-t-il un lien entre les personnes qui se connectent et les données affichées ? Le filtrage des données fait-il partie d'un système de permissions qui est modifiable ? La personne qui a mis à jour ou modifié en dernier un objet fait-elle partie de votre domaine, c'est-à-dire que quelqu'un d'autre doit le voir ou quelque chose pour le support backend ?

L'exemple de l'email est également dépendant. Connaissez-vous l'événementiel de domaine ou l'événementiel en particulier ? Disposez-vous d'un service distinct pour envoyer des e-mails ? L'envoi d'un courriel fait-il partie de votre domaine ou s'agit-il d'une préoccupation au niveau de l'application, hors du champ d'application de votre système ? L'interface utilisateur doit-elle savoir si un courriel a été envoyé avec succès ou non ? Les e-mails dont l'envoi échoue doivent-ils être réessayés ? Le contenu de l'e-mail envoyé doit-il être stocké pour les besoins de l'assistance ou du service clientèle ?

Ce type de questions est trop vaste et subjectif, mais je réponds pour que vous et tous ceux qui ont voté pour vous puissent comprendre.

Vos exigences, vos délais et vos ressources se répercutent sur l'architecture de votre système. Même le modèle de revenus peut avoir un effet. Vous devez également tenir compte du modèle que vous visez. DDD est très différent des applications de type "persistance en tant que modèle" et toutes les variantes intermédiaires sont également valables pour certaines applications. Visez-vous à tester l'application ? Tout cela a un effet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X