Christophe m’a demandé de préciser ce que j’avais contre le MVC & le n-tiers etc etc.
Alors, MVC, sur le principe, c’est très bien. J’en suis même, en théorie, un ardent défenseur. Le principe, c’est « pour une appli, on a des données (model), on veut les voir (view), et on veut y appliquer des traitements (controler). Et on découple tout ça de manière à ce que (par exemple) si on change l’algorithme de traitement, il y ait normalement pas besoin de changer ni la visualisation des données ni le modèle de données. Très bien.
Là où ça se gâte, c’est que le cloisonnement du modèle MVC, bien souvent, il est dur. Ça veut dire que pour appeler un truc du côté contrôleur quand on est côté vue, faut se manger des callbacks pas possibles et, bien souvent, c’est pénible ET long. Pour l’exemple, la dernière fois que j’ai dû aller rechercher une fonction à la noix de ce type là, ça m’a pris 4 ou 5 heures pour mettre en place ledit callback. On me rétorquera que 1/ c’est que je suis une buse 2/ c’est qu’y’a ptêt un problème avec le framework que j’utilise ; ça n’empêche que par rapport à appeler bêtement une fonction, c’est long.
En pratique, le problème, et tout particulièrement quand on travaille à plusieurs sur du code, c’est que les choses ne sont jamais aussi claires que ça. Déjà, il va en général y avoir du code qu’on aimerait bien avoir des deux côtés (côté contrôleur (on dit aussi métier) et côté vue (on dit aussi présentation)). Techniquement, on est bien d’accord, ça veut dire que quelque part, on sait pas trop où va le code, qu’il faudrait réfléchir, éventuellement le déplacer d’un côté à l’autre et/ou faire les choses plus proprement qu’elles ne sont faites.
Maintenant, considérons la situation suivante. On livre en intégration demain. Il est 16h. J’ai une fonction qui traîne, avec le code kivabien dedans, mais elle est pas du bon côté. J’ai pas de mapping pour faire mon callback. Faire le mapping, ça va relativement vite, sauf qu’il faut recompiler pour mettre le mapping au bon endroit (et ça, c’est long), et que pour mapper, il faut que les paramètres de la fonction soient sérialisables, sinon ça passe pas (et oui, un Boolean, c’est sérializable, un boolean, ça l’est pas. Astuce.) (oui, je fais du Java.) Et, comme dit plus haut, avec toutes ces emm… diverses, faire le mapping proprement, ça peut prendre 4h (avec les divers bugs et autres ennuis) (bon, ça peut aussi prendre un quart d’heure si on s’en tire bien, hein, soyons honnête !!), donc… bin on duplique le code. Moche.
On pourrait contourner ça en ayant une partie de code « commune » qui serait compilée à la fois avec la partie métier et avec la partie présentation. Il faudrait bien sûr faire super gaffe en y mettant quoi que ce soit (c’est un coup à exploser complètement le modèle, donc pas très beau), MAIS quelques fois ça serait intéressant. Je pense en particulier à tout un tas d’utilitaires à la noix qui peuvent très bien servir des deux côtés, traitement de chaînes, tris, etc. Sauf que, évidemment, simplicité et développement à l’arrache obligent, on finirait toujours par y trouver « la fonction qui récupère la liste des gens à qui envoyer un mail pour telle opération » (mbof) et/ou par ne pas y trouver « le petit utilitaire de trois lignes qui appelle le Tokenizer pour parser m chaîne, là ».
En-dehors du code potentiellement duplicable, ya aussi le problème du code qui est « juste pas au bon endroit, du moins il me semble ». Pour moi, une fonction qui envoie un mail à un utilisateur avec des informations sur une instance particulière du modèle, ça va côté présentation (parce que je crée mon mail et je le présente à l’utilisateur). Bon, pour la personne qui a fait la fonction, ça va côté métier. Et là, c’est la lutte. Je sais pas qui a raison (enfin, si, moi 😉 ) mais, techniquement, non, j’ai pas le temps d’en discuter et j’ai pas le temps de corriger quoi que ce soit (rappel : il est 18h et je livre demain en intégration). Donc, on lutte. Pis là on se rend compte qu’il y a deux fichiers de ressources pour les chaînes. Gargl, le fichier en question est côté présentation, il faut donc que je crée le mail côté présentation et que je l’envoie côté métier. Ouiménon, en fait, les chaînes elles étaient dans l’autre fichier. Damned, il est 22h.
Bref, voilà. Le modèle MVC, conceptuellement, c’est très joli. En pratique, entre le code qu’on sait pas où mettre, le code qu’est pas au bon endroit, le code qu’on voudrait bien des deux côtés, le tout dans un environnement d’équipe et à l’arrache, le modèle MVC, ça te pourrit la vie d’une manière monstrueuse.
Quant à l’archi n-tiers… bin mon code métier et mon code présentation, ils sont sur deux serveurs Websphere différents. Il faut lancer le serveur métier avant le serveur présentation, sinon ça plante. Relancer les deux serveurs, ça me prend au moins 10 minutes à chaque fois. La trace d’exécution, elle se fait sur deux serveurs et c’est donc le bordel (d’un côté, ta trace s’arrête sur l’appel au callback, de l’autre, faut déjà voir si elle commence (aka si t’as pas foiré ledit callback)). Debugger du n-tiers, c’est pas marrant.
Voilà. Ceci était mon billet argumenté sur le hurlement primaire de l’autre jour.
Je reprécise donc que dans un environnement parfait où tout le monde sait ce qu’il fait, où personne ne fait de bugs et où on n’a pas (trop) de contrainte de délais, le MVC et le n-tiers, c’est probablement fantastique.
<p>
Il y a quelques points que tu relèves qui sont effectivement problématiques avec certains framework MVC.
</p>
<p>
L’envoi de mail par exemple, encore que c’est essentiellement dû au fait que le framework ne le prend pas en compte. En fait un envoi de mail touche à la fois le V et le C, il faut juste que l’action demandée à ton contrôleur puiss accéder à la fois à la partie présentation (X)HTML classique mais également à une autre partie présentation qui elle gère non pas une réponse HTTP mais un envoi SMTP.</p>
<p>
Dans le cas de ton exemple « une fonction qui envoie un mail à un utilisateur avec des informations sur une instance particulière du modèle », dans ton contrôleur tu devrais avoir la récupération de l’instance faite par le modèle, ainsi que l’utilisateur auquel envoyer le mail. Ensuite tu devrais avoir dans une couche « présentation mail » une vue qui permet de calculer le champs To: et intégrer les informations de l’instance dans le Body et enfin envoyer le mail (normalement ce devrait être une méthode d’une classe héritée d’une classe Mailer disposant d’accesseurs pour les headers et d’un moteur de templating pour le Body).<br />
A part ce point un peu délicat où tu fais du MVVC (VV pour deux vues), j’ai surtout l’impression que tes problêmes viennent du fait que tes vues font trop de choses qui devraient être prises en charge par le contrôleur. Il faut vraiment être propre dans la séparation V/C sinon effectivement on s’arrache les cheveux. Quand tu regardes le code de ta vue tu dois pouvoir te dire: « c’est tout plat, il n’y a pas de logique ni d’instanciation de modèle, ce n’est que du remplissage de trous ».</p>
<p>
Tout cela dépend bien sûr de ce que t’offre ton framework, par exemple j’utilise Ruby on Rails et ce que je décris plus haut est facile à faire avec. Par contre je ne suis pas très content de la gestion des messages d’erreurs des contrôles de surface des modèles. Justement parce que je considère que la présentation devrait au final choisir le message d’erreur précis alors que c’est le modèle qui, profitant du fait qu’il sait quelle est la raison de son « invalidité » fait tout le boulot au lieu de rendre juste un « descripteur de message » à faire traiter par la vue. Cela pose bien évidemment des problèmes, par exemple le modèle n’a pas accès à l’utilisateur courant, ce qui rend la traduction des messages assez inélégante (Rails profite d’aspects techniques du framework qui n’ont rien à voir avec MVC pour résoudre le problème, mais ce n’est guère propre).
</p>
Merci pour la description, je suis bien content de ne pas faire de Java. Ça vaut bien SAP par certains côté, tiens… Le coup des majuscules qui jouent ([B|b]oolean) j’ai du mal à y croire 🙂 Pour te consoler, il y a le même problème de « où je place ma logique » à plein d’endroits : les contraintes et la logique d’une base de données, ça va où ? Parce que c’est « métier » aussi, ça. (SAP mélange tout allègrement, lui) Le code, les conversions.. on se les fait dans des packages ou fonctions base (ça marche très bien et ça booste !) ou dans un module extérieur (PHP…) ? Mes agrégats, je fait ça dans l’alimentation du Datawarehouse ou je laisse l’affichage Business Objects s’en charger ? (Et c’est bien la Dedibox, finalement ?) (Et dotclear 2 ? J’ai l’impression que tous les blogs DC2 que je vois sont plus moches que la v1). (Et je fais comment des paragraphes avec ce truc ????????)
Pour le boolean/Boolean, c’est parce que t’en as un t’as un type natif et l’autre c’est un objet. Java est pas très propre de ce côté (puisqu’il y a encore des types natifs et que tout n’est pas objet). Cela dit je crois que Java 5 améliore ça. Je suis très contente de ma dedibox moi. J’y héberge un assez gros site, pas mal de trucs perso, et j’ai quasimment pas de downtime (la machine est up depuis son installation, et j’ai dû voir passer 1/2h de non dispo réseau en 8 mois, sans être sûre que ça vienne pas de chez moi). Dotclear 2, c’est pas mal, c’est apparemment bien plus configurable que le DC 1. Par contre c’est vrai que j’ai eu du mal à trouver un thème et que celui-là me convient pas encore tout à fait (mais je suis très fière de mon détourage de muffin à l’œuf).