Explication sur le concept de MVC

Bonjour,
Je suis un débutant dans le concept de MVC donc je sollicite un peu votre aide. J’ai discuté avec un collègue apropos de ce concept, et j’ai retenu ceci:

  • Controlleur s’occupe de tous les traitements (= controlle tous les actions en bref): routage, accès à la base de donnée, etc…
  • Model s’occupe seulement de représenter des données sous forme d’un objet (on recupere les données via un controlleur et on hydrate une classe modele)
  • Vue s’occupe des rendus (du html, json, xml, … tous ce qui est retourné aux clients)

J’ai lu ceci http://book.cakephp.org/2.0/fr/cakephp-overview/understanding-model-view-controller.html et la definition sur Wikipédia du MVC et apparement (sauf si j’ai mal compris) , l’accès aux bases n’est par exemple pas un controlleur mais un model.

Donc je suis un peu perdu entre les explications et les lectures donc est ce que vous pouvez m’éclairer un peu? Qui a tort ? Qui a raison? Ou c’est moi qui n’a rien compris?

Merci

1 « J'aime »

De mon point de vue une bonne manière de se représenter le modèle MVC est de réfléchir à comment fonctionne une entreprise ou une organisation quelconque.

Ensuite viennent les scenarios (user story, use case, workflow des fois je me mélange)
Exemples que j’ai à l’esprit :
aller a la préfecture déposer une demande pour faire faire son permis de conduire
(exemple bête mais parlant)

Un client (client) pousse les portes du bâtiment (application), adresse sa demande (formulaire soumis) au guichet d’accueil (routeur), puis selon le type de demande (roujours routeur), le guichet redirige le client vers le bureau compétent de 1er niveau (controller).
Ledit bureau prend en charge sa demande (document avec identifiant, photos, etc…) (POST params, files) , les valident (validateurs de formulaire) qui passe ensuite dans divers services internes (Services). Chaque travail de chaque service mis bout a bout permet de traiter la demande (accès DB via des Repositories, accès a des API) et lui renvoie le résultat attendu par la Poste (Service email et/ou API la Poste)

Qu’avons nous rencontré dans ce workflow ?

Controller :
c’est lui qui doit répondre a la requête du client. il ne doit pas contenir la logique applicative, car il n’a pas de “compétence métier”. Typiquement il n’a pas a savoir chercher de la data ou envoyer un mail.
C’est un orchestrateur qui décomposer le job : "ok alors pour répondre a la demande il y a ca + ca + ca a faire, donc je demande aux “autorités compétentes” que sont les Services.
Il sait ce qui doit etre fait, mais ne doit pas savoir comment ca doit etre faut.

Services :
chacun service “métier” fait un nombre de choses limitées, mais les fait très bien. Untel est capable d’interagir avec MailChimp, un autre gère facturation avec Stripe, un autre gère des stocks, un autre récupère des jeux de données en base, etc… etc…
Un service fait son job quelle que soit la nature de celui qui l’appelle (controller, autre service, commande console)
L’accès au données locales se fait généralement via des Repositories qui exposent des méthodes explices d’extraction de données (ex: ClientsRepo::getClientsBornIn( year ) )

Repositories :
ce sont les gardiens des données. Ils exposent des méthodes qui fournissent des jeux de données en fonction des besoins. Il les fournissent sous forme de collections de Models (et hydraté comme tu disais).
En gros ce sont des méthode qui traduisent le besoin de data en SQL.
Parfois la proximité entre Controller et Repository est si étroite que le Service semble faire double-emploi avec le Repository.
Je sais pas trop si une telle situation relève d’un bad pattern…

Models.
perso je préfère l’appellation “entité” qui m’est plus familière, mais “models” est plus normalisé.
Ce sont les classes qui représentent les tuples d’une table avec ses relations (s’il en a).
ils permettent de penser les tuples comme des objets avec des propriété et certaines facultés.
ex : un objet Produit n’est pas censé savoir s’auto persiste en base (enfin selon les patterns), mais par contre il est capable de calculer son prix HT et TTC.
Le monde objet et le monde SQL ne se comprennent pas très bien : c’est pour ca qu’un moteur ORM est la pour faire la passerelle entre les 2 mondes. Le requeteur auprès de la base c’est lui.
Donc Repositorie et ORM travaillent ensemble.
Par contre je vais pas détailler ici les diverses manières de requêter avec un ORM (raw vs DQL vs fluent)

NOTE : à la fois MVC est pas un pattern avec une nomenclature strict ET je n’ai pas parole d’évangile.
Donc si j’ai dit des trucs faux, hésitez pas a me le faire savoir.

1 « J'aime »

Donc avec ton explication, la connexion à une base de donnée se fait au niveau des services mais la manipulation se fait au niveau de repository, representation au niveau de entité (model) et le controlleur ne fait que organiser l’appel de tous ces elements.

Controller: oui.
Service : non il ne gère pas l’accès aux données. Il fait des traitements propres à son domaine de compétences.

L’accès au donnés fonctionne sur 3 niveaux :
Le Repository fournit des méthodes qui abstraient l’usage SQL. Il utilise le EntityManager qui permet de réqueter sur une table en SQL (ou DQL) et fournit en retour une collection de Models.
C’est aussi lui qui persiste les Models en base.

L’ORM se charge de transformer les tuples en objet, et inversement

Si les traitements métiers n’ont pas vocation à être réutilisé ailleurs, ni aujourd’hui ni plus tard, tu peux considéré de les mettre dans un controller.
Ça dépend la taille du projet, des directives de conception, etcc
Perso je préfère monter un Service même ultra léger.

La difficulté avec le MVC, c’est que le pattern a pas mal évolué avec le temps en fonction des besoins, en fonction de ce que les gens en ont fait. Au final, lorsqu’on parle de MVC aujourd’hui, on n’est plus dans le MVC tel que conçu et réfléchi initialement.

Ma vision est celle-ci : le pattern MVC est un pattern pour les interfaces graphiques, pour gérer les interactions avec l’utilisateur.
Le stockage du modèle (en base de données, en fichier, en mémoire, ou ailleurs) n’est pas du ressort de ce composant, il n’a pas à le gérer : ce doit être fait autre part dans ton système. La seule chose qui peut entrer dans le cadre de ton MVC c’est : l’utilisateur demande à persister les données, alors le MVC va “donner l’ordre” de se sauver, et cet ordre est donné programmatiquement à partir du contrôleur.
La logique de persistance est un détail d’implémentation, tu as une implémentation en mémoire de ton modèle, une implémentation en base de données, …

En résumé, la gestion de la persistance est une responsabilité, la gestion des interactions utilisateur est une autre responsabilité. Ne pas donner à un boulanger la responsabilité de couper la viande, vaut mieux laisser faire le boucher.

Voilà pour une vision très haut niveau, en espérant que ça puisse aider

@bouquetf : puisque tu parles de MVC pour l’interactivité UI, je présume que tu fais allusion au pattern MVC client-side, au sens Single Page App. Comme ca se fait avec Angular, Ember…
A moins que je fasse erreur.

De mon côté J’illustrais le pattern MVC coté server, comme avec Symfony ou d’autres.
Bref, je pense qu’il est nécessaire de le préciser à @captainkidd.

Oui. je m’interesse plutot pattern MVC coté serveur ou le MVC avec Java ou C++ (tel imaginé au début avec les langages objet). Coté client, c’est une autre histoire à mon avis.

Pour revenir aux services, le pattern MVC peut s’appliquer à la construction des services aussi? Ou c’est liée globalement au projet?

D’après les explications de mon collegue , au final on n’aura que 3 dossier: Controller pour tous logiques de traitement, model pour la representation (tes entités) et vue pour les rendus (json, html, etc…)

Oui les services se retrouvent dans MVC. C’est une facon de mieux découper la logique applicative, voila tout
Ce n’est pas parce que ya pas S de Service dans MVC qu’il n’en fait pas partie.
Meme chose pour le R de Routeur :)

non pas de logique de taitement dans le controlleur :
en gros c comme si tu demandais un directeur de projet (ou COO) de coder une feature. Ba non Il sait ce qui est demandé par le client et connait le plan d’action et qui doit intervenir et a quel moment, mais c’est le consultant fonctionnel qui sait specifier le besoin, le CdP qui planifie, le dev qui sait réaliser la feature, etc…

exemple concret :
Quand tu as besoin de gérer des clients (ou des stocks, factu…), il est quasi assuré que plusieurs de tes controlleurs vont faire appels aux mêmes jeux de fonctions (clients de telle localités, meilleurs acheteurs, ceux ayant publié des avis, ceux ayant acheté tel produit, qui ont tel age).
Si tu place ta logique de traitements (les fonctions ci-dessus) dans un controller A, comment tes autres controlleurs B, C, ou D vont pouvoir accéder a ces fonctions si elles sont dans controller A?

La tu vas me dire :
1- soit je copie/colle le traitement de A dans B
2- soit j’expose ces fonctions en API publique puis injecte controllerA dans controller B.

sauf que :

  1. duplication de code, codé éparpillé,
  2. un controller est pas fait pour ca, il prend en charge la demande mais ne la traite pas : il la delegue a un ensemble de services métier. Un bon controlleur contient assez peu de code pour chacun de ses fonctions

La bonne chose a faire sera de créer un Manager d’entité de clients (ou un Repository) qui propose ces différentes fonctions sur la gestion clients, ET exposé sous forme d’un Service injectable et réutilisable dans tes controllers A B C D.

Je ne parle ni de côté serveur ou côté client, mais du pattern MVC “en théorie”, sans m’intéresser à l’implémentation.

Le modèle c’est la modélisation des données métier. On s’en fout que ce soit du client, du serveur, de la base de données, du fichier. La seule chose que l’on sait, c’est que c’est les données dans le langage de l’expert métier.

Le contrôleur manipule les données et les arange pour qu’elles soient structurées de la façon la plus adéquate possible pour la vue. Ici encore, que ce soit client, serveur, en lien avec une base de données, avec des fichier, sur une autre machine, on s’on fout. C’est juste manipuler les données pour leur donner une forme pour que la vue n’ait aucune logique à implémenter.

La vue, c’est simplement la représentation de ces données et les points d’entrées pour les actions de l’utilisateur. Ça peut être du web, du client lourd, du json/xml/… pour une API (via templating par exemple), c’est un détail d’implémetation. L’important c’est comment c’est rendu à l’utilisateur et comment récupérer ses informations.

Les livres/articles/vidéos d’oncle bob (Robert C. Martin) sur ce qu’il appelle “clean architecture” pourrait aider

1 « J'aime »

Juste un aparté

Si vous vous lancez dans un nouveau projet d’envergure, et si vous en avez la possibilité, prenez peut être conseil auprès de quelqu’un de confirmer pour vous aidez à poser votre architecture initiale. Cela vous coutera peut être un à deux jours de mise en place … mais au moins vous aurez une base solide pour poser votre applicatif. les erreurs de conception initiale risque de vous coutez chez par la suite.

Après, si c’est pour une appli qui n’a pas vocation à trop grandir, faites vous plaisir ^^ et bonne mise en place d’archi

Ok tu es focalisé sur la théorique. Moi je suis versé implémentation dans mes propos.
Bon sur ce j’espère qu’on a un peu aidé @captainkidd

Merci à vous tous. Ca aide.

Merci beaucoup pour l’explication @Joris

Human Coders - Le centre de formation recommandé par les développeur·se·s pour les développeur·se·s