BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Pourquoi je n'utilise plus de Frameworks MVC

Pourquoi je n'utilise plus de Frameworks MVC

Merci à Jean-Jacques Dubray pour sa contribution à la traduction française de son article.

Le pire aspect de mon travail en ce moment est la construction d'API pour les développeurs des interfaces utilisateurs. La conversation est toujours la même :

Dev : Donc, l'écran nous présente les données x,y,z… Pourrais-tu s'il-te-plaît me créer une API avec le format {x: , y:, z: }

Moi : Ok

Je ne discute même plus. Les projets finissent avec un tas d'APIs liées aux écrans qui changent souvent, ce qui, par construction, implique de modifier les APIs et avant de vous en rendre compte, vous finissez avec une montagne d'APIs et pour chaque API des variantes par type d’écran, de plateforme, de versions d’applications… Sam Newman a même commencé à institutionnaliser cette approche avec le BFF pattern qui suggère qu'il est normal de développer des API propres à chaque type de terminal, de plateforme et bien sûr de version d’une application. Daniel Jacobson explique que Netflix en arrive à utiliser un nouveau qualificatif pour ce type d’API, ils appellent ce type d’APIs… éphémères. Arghh...

Il y a quelques mois, je me suis décidé à passer un peu de temps pour comprendre comment nous en étions arrivés là et ce que nous pourrions faire pour éviter ces architectures « Mikado ». Dans cet article, je souhaiterais partager mon parcours. Un parcours qui m’a permis de remettre en question le dogme le plus important de l’architecture applicative, le MVC, et de découvrir la programmation réactive et fonctionnelle que je connaissais peu. Un parcours où j’ai essayé de me concentrer sur une approche la plus simple possible et d’éviter les frameworks que notre industrie produit à la chaine. Je pense que vous devriez être intéressé par quelques-unes de mes découvertes.

Le pattern utilisé par toutes les interfaces utilisateurs est le pattern MVC - Modèle-Vue-Contrôleur. Le MVC fut inventé quand le web et l'architecture logicielle étaient, au mieux, des clients lourds parlant directement à des bases de données simples sur un réseau primitif. Et pourtant, des décennies plus tard, le MVC est toujours d'actualité, sans conteste, pour construire des applications omnicanal.

Avec la mise à disposition prochaine d'Angular2, il serait sans doute temps de réévaluer l'usage du pattern MVC et surtout la valeur que ces frameworks MVC apportent à l'Architecture Applicative.

J'ai utilisé pour la première fois le pattern MVC en 1990 lorsque NeXT lança Interface Builder (il est incroyable de penser que ce bout de logiciel est toujours pertinent aujourd'hui). A l'époque, Interface Builder et le MVC ressemblait à un véritable pas en avant. A la fin des années 90, le pattern MVC fut adapté pour fonctionner avec HTTP (vous vous souvenez de Struts?) et aujourd'hui le pattern MVC est la clef de voûte de toute architecture applicative.

Même Facebook avec React.js a dû employer un euphémisme en introduisant une librairie qui, pour une fois, paraissait remettre en cause le dogme MVC : “React c’est juste le V du MVC”.

En commençant à utiliser React l'année dernière, j'ai eu l'impression qu'il y avait quelque chose de vraiment différent : vous changez un bout de données quelque part et, immédiatement, sans interaction explicite entre la vue et le modèle, toute l'interface change (et pas uniquement les valeurs des champs ou des tables). Cela étant dit, je fus tout aussi rapidement déçu par le modèle de programmation de React, et il semble que je ne sois pas le seul. Je partage l'opinion d'Andre Medeiros :

React a fini par me décevoir de nombreuses manières, principalement a cause d’une API qui oblige les développeurs […] à mélanger différents aspects dans le corps des composants React.

De mon coté, en tant que concepteur d'API, je suis arrivé à la conclusion qu'il n'y avait pas de bonne manière de concevoir des appels d’APIs pour les clients React, précisément parce que React ne se concentre que sur la Vue et n'a pas vraiment de Contrôleur dans son modèle de programmation.

Facebook, pour le moment, refuse de résoudre ce problème au niveau de la structure des composants. L'équipe React a d'abord introduit le pattern Flux qui était également décevant, et récemment, Dan Abramov a commencé à promouvoir un nouveau pattern, Redux, qui va a peu près dans la bonne direction, mais qui n'offre pas les moyens de relier convenablement les APIs aux composants de la vue à cause de la structure fonctionnelle du réducteur (reducer), comme je le montrerai plus loin. React est avant tout une librairie « client » ou le serveur ne joue pas vraiment de rôle.

Vous pourriez penser qu'entre GWT, le SDK Android et Angular, les ingénieurs de Google auraient une bonne idée de ce qui pourrait être la meilleure architecture des clients, mais lorsque vous lisez quelques-uns des commentaires sur le design d'Angular2, vous n'éprouvez pas forcément ce sentiment, qui laisserait penser que même chez Google, les développeurs ont la moindre idée d’une bonne architecture client :

Angular1 n’avait pas été construit autour du concept de composant. A la place, on connectait des contrôleurs à plusieurs [éléments] de la page avec notre logique métier. Les scopes étaient attachés ou passés, sur la base de la structure de nos directives (il fallait isoler les scopes, non ?).

Est-ce qu'un composant basé sur Angular2 serait plus simple ? Pas vraiment. Le package principal d'Angular2 à lui seul est composé de 180 classes, et le framework complet en a environ 500, et tout cela, en supplément d’HTML5 et CSS3. Qui a le temps d'apprendre et maîtriser ce type de framework pour construire des applications Web ? Que se passera-t-il à la sortie d’Angular3 ?

Après avoir utilisé React et avoir vu ce qui arrivait avec Angular2, je me suis senti un peu déprimé : ces frameworks m'obligent à utiliser systématiquement le modèle “Screen Scrapping” (gratteur d'écran) où chaque API côté serveur est liée aux données représentées à l'écran (en entrée ou en sortie).

Je me suis dis à ce moment là qu’il doit forcément y avoir une meilleure solution. Je me suis alors mis a construire une application Web sans React, sans Angular, sans framework MVC quel qu'il soit, pour voir si je pouvais trouver une articulation plus intéressante entre la Vue et les APIs serveurs. Voici le récit de mon parcours.

Ce que j'aime vraiment avec React, c’est la relation entre le modèle et la vue : on ne peut faire qu’une chose, c’est de passer des données à la vue. React n’a pas de concept de « templates » (DSL) et la vue n'a pas la possibilité d’émettre des requêtes par elle-même.

Quand vous regardez React de près, vous comprenez que le seul objectif de React est de décomposer la vue en une série de fonctions (pures) et la syntaxe JSX :

         <V params={M}/>

ne présente aucune différence avec :

          V = f( M )

Par exemple, le site web d'un des projets sur lesquels je travaille en ce moment, Gliiph, est construit avec de telles fonctions :

(Cliquez sur l'image pour l'agrandir)

fig 1. Cette fonction est responsable de la génération du code HTML sur le composant slider du site.

Cette fonction est alimentée par le modèle :

(Cliquez sur l'image pour l'agrandir)

fig 2. Le modèle des sliders

Quand vous comprenez qu'une bonne vieille fonction JavaScript peut très bien faire le travail de React, la question qui se pose est "Pourquoi utiliser React tout court ?".

Le DOM virtuel ? Si vous en avez besoin (et je ne suis pas certain cela soit souvent le cas), il y a déjà plusieurs options et je pense que d'autres seront publiées prochainement.

GraphQL ? Pas vraiment. Ne vous laissez pas tromper par l'argument que si Facebook en fait un usage excessif, c'est forcément bon pour vous. GraphQL n'est rien de plus qu'une manière déclarative de créer des Vue-Modèle. Être obligé d’adapter le modèle pour qu’il puisse s’aligner précisément avec la vue est le problème, pas la solution. Comment l'équipe de React (qui se veut être un framework réactif) peut-elle penser qu'il est bien d’acheminer des données avec des "requêtes spécifiques à la vue” :

GraphQL est orienté essentiellement par les besoins des vues et des développeurs d’interface utilisateur qui les construisent. […] Une requête GraphQL, renvoie exactement ce que le client demande et pas plus (sic).

Ce que l'équipe de GraphQL semble ne pas avoir remarqué c’est que derrière la syntaxe JSX, le changement subtile qui vient de s’opérer est que les fonctions permettent d’isoler le modèle de la vue. Contrairement aux templates ou aux "requêtes écrites par les développeurs d’interface utilisateur", les fonctions n'ont pas besoin que le modèle soit capable d’alimenter la vue directement.

Quand la vue est créée par une fonction (par opposition à un template ou lorsqu’elle émet une requête), vous pouvez transformer les données du modèle pour représenter au mieux la vue sans ajout de contraintes artificielles sur la forme du modèle.

Par exemple, si la vue présente une valeur v et un indicateur qui représente l’état de cette valeur (excellent, bon ou mauvais), il n'y a pas de raison d'avoir la valeur de cet indicateur dans votre modèle : la fonction du composant devrait simplement calculer la valeur de l'indicateur d'après v fournit par le modèle.

Ce n'est, bien sûr, pas une bonne idée d'inclure ces calculs directement dans la vue, mais il n'est pas compliqué d’écrire une fonction pure qui se charge de ces calculs (vue-modèle), et dès lors, il n'y a pas beaucoup de raisons d'utiliser GraphQL :

   V = f( vm(M) )

En tant que vétéran du MDE (Model-Driven-Engineering), je peux vous assurer qu’il est infiniment plus facile d’écrire du code que des méta-données, que ce soit un template ou des langages de requêtes comme GraphQL.

Cette relation fonctionnelle entre la vue et le modèle a plusieurs avantages. D'abord, comme avec React, elle vous permet de décomposer vos vues en composants. L'interface naturelle créée par les fonctions vous permet de créer des thèmes interchangeables pour votre application ou votre site Web, ou de servir la vue en utilisant d’autres technologies (natives par exemple). Ces fonctions ne présentent aucune difficulté pour implémenter du « responsive design ».

Je ne serais pas surpris, par exemple, si dans les mois à venir, certains designers commencent à livrer des thèmes HTML5 sous forme de composants basés sur des fonctions JavaScript. C'est la manière dont je livre tous les projets de site web actuellement : je choisis un template HTML5 et je le transforme immédiatement en une série de fonctions JavaScript. Je n'utilise plus WordPress. Je peux utiliser le meilleur d’HTML5 et de CSS3, avec à peu près le même niveau de travail (dans certains cas, moins).

Cette approche permet un nouveau type de relations entre designers et développeurs. Tout le monde peut écrire ces fonctions JavaScript, en particulier les designers de templates. Il n'y a aucune syntaxe spécialisée à connaitre, pas de JSX, ni de template Angular, juste de bonnes vieilles fonctions JavaScript.

Il est à noter que, dans une perspective de flux réactif, ces fonctions peuvent se déployer là où cela a le plus de sens : sur le serveur ou sur le client. Créer du « JavaScript Isomorphic » est trivial avec SAM.

Cette approche permet aussi à la vue de déclarer un contrat minimum avec le modèle, et laisse la décision au modèle de la meilleure manière d’acheminer les données vers la vue. Les aspects comme la gestion du cache, le « lazy loading », l'orchestration, la consistance sont complètement sous la responsabilité du modèle. Contrairement aux templates ou à GraphQL, il n'y a jamais de nécessité de répondre à une requête sur la base des données contenues dans une vue.

Maintenant que nous avons trouvé une manière de découpler la vue du modèle, la question suivante est : comment créer un modèle programmatif complet ? A quoi peut ressembler par exemple le "contrôleur" ? Pour répondre à cette question, retournons au pattern MVC.

Apple s'y connaît un peu en MVC, puisqu'ils ont "volé" le concept à Xerox PARC au début des années 80 et l'ont implémenté religieusement depuis :

fig.3. le Modèle MVC

La difficulté fondamentale ici est, comme l'explique Andre Staltz avec éloquence, que le modèle MVC est “interactif” (en opposition à Réactif). Dans le MVC classique, l'action appelle une méthode du contrôleur pour mettre à jour le modèle et en cas de succès (ou d’erreur) décide de la mise à jour de la vue. Comme André le souligne, il n'est pas nécessaire de procéder de la sorte, il y a un autre chemin tout aussi viable, le chemin Réactif. Si vous imaginez que les actions devraient être seulement responsables pour proposer des valeurs au modèle, sans considération du résultat, on peut alors se demander comment pourrions-nous intégrer ces actions dans un flux réactif ?

Si vous voulez comprendre la nature des Actions, vous devriez vous intéresser à la spécification TLA+. TLA signifie “Temporal Logic of Actions” (Logique Temporelle des Actions), un formalisme inventé par Dr. Lamport qui a été récompensé par un Turing award. En TLA+, les actions sont des fonctions pures :

         data’ = A (data)

J’aime beaucoup la notation « apostrophe » de TLA+ car elle renforce le fait que les fonctions sont de simples transformations d'un ensemble de données.

Dans ce contexte, un MVC réactif ressemblerait sans doute à cela :

         V = f( M.present( A(data) ) ) 

Cette expression stipule que lorsqu’une action est déclenchée, elle calcule un jeu de données d'après les paramètres d’entrée(par exemple venant de l'utilisateur), qui est ensuite envoyé au modèle au moyen d’une méthode unique (present), qui décide alors si, et comment, se mettre à jour. Une fois la mise à jour faite, la fonction état calcule la représentation de l’état du modèle et met à jour l’interface utilisateur. La boucle réactive est fermée. La manière dont les paramètres du modèle sont persistés n’a pas d’incidence sur le flux réactif, et ne devrait jamais, vraiment jamais, être "écrite par des développeurs d’interface utilisateur".

Les Actions sont des fonctions pures, sans effets de bord (par rapport au modèle, en n’excluant pas les logs, par exemple).

Un modèle MVC Réactif est intéressant parce qu’à l’exception du modèle (bien sûr), le pattern n’est composé que de fonctions. Pour être fair-play, Redux est très proche de cette architecture, mais avec les « cérémonies » inutiles de React et un couplage trop fort entre le modèle (qui accepte) et les actions (qui proposent) dans le réducteur (reducer).

Cela dit, le modèle MVC Réactif, tel qu'il est, est incomplet, et ne permet pas de construire des applications sophistiquées, comme Dan aime à le dire. Prenons un exemple simple pour l'illustrer.

Supposons que nous ayons besoin d'implémenter une application qui contrôle le lancement d'une fusée : une fois le compte à rebours lancé, le système décrémente le compteur jusqu'à zéro, et si toutes les propriétés du modèle ont une valeur nominale, le lancement de la fusée est initiée.

Cette application est une simple machine à états finis :

fig 4. La machine à état du lanceur de fusée

Les actions décrémenter et lancer sont "automatiques", c'est à dire qu'à chaque fois que nous entrons (ou ré- entrons) l'état du compte à rebours, les conditions de transition sont évaluées et tant que la valeur du compteur est supérieure à zéro, l'action décrémenter sera appelée, et lorsque la valeur atteint zéro, l'action lancer sera à son tour appelée. Une action annuler peut être appelée à n'importe quel moment, qui opérera la transition du système de contrôle vers l'état abandonné.

En MVC, ce type de logique serait implémenté dans le contrôleur, probablement déclenché par un compteur dans la vue.

Nous avons vu qu’en TLA+, les actions n'ont pas d'effets de bord, et l'état résultant est calculé une fois que le modèle a traité les valeurs proposées par l'action et qu'il s'est mis à jour. C'est une différence fondamentale par rapport à la structure classique des machines à états-finis où les actions déterminent l'état de sortie, c'est-à-dire que l'état d'arrivée est alors indépendant du modèle et des valeurs de ses propriétés. Lorsqu’on prend une base TLA+ pour exprimer une machine à états-finis, elle ne s’exprime pas avec des triplets qui connectent deux états (S1, A, S2), mais sont plutôt des relations de la forme (Sk, Ak1, Ak2,…) qui précisent toutes les actions disponibles d'après qu’un état Sk ait été atteint, l'état résultant n’étant calculé que lorsqu'une action a été appliquée au système, et que le modèle a traité les mises à jour.

La sémantique TLA+ permet une meilleure conceptualisation d'un système en introduisant une fonction "état", distincte des actions, du modèle et de la vue (qui permet de calculer, en particulier, la représentation de l’état du modèle).

Le modèle dans notre exemple ressemble à ceci :

model = {

counter:  ,

started:  ,

aborted:  ,

launched:   }

Les quatre états du système sont associés aux valeurs suivantes du modèle :

ready = {counter: 10, started: false, aborted: false, launched: false }

counting = {counter: [0..10], started: true, aborted: false, launched: false }

launched = {counter: 0, started: true, aborted: false, launched: true}

aborted = {counter: [0..10], started: true, aborted: true, launched: false}

Le modèle est décrit par toutes les propriétés du système et leurs valeurs potentielles, tandis que les états précisent les actions disponibles, en fonction d’un ensemble de valeurs des propriétés du modèle. Ce type de logique métier doit être implémenté quelque part car nous ne pouvons pas faire confiance à l'utilisateur pour savoir quelles actions sont possibles ou non dans un état donné. Pourtant, ce type de logique est difficile à écrire, débuguer et maintenir, surtout quand vous n'avez pas de structure pour la décrire, comme en MVC.

Regardons le code de notre exemple de lanceur de fusée. La fonction qui calcule les actions automatiques à exécuter dans un état donné suit logiquement le calcul de la représentation de l'état. Cette fonction s’appelle le « prédicat d'action suivante » (next-action predicate), elle détermine l’action à exécuter, le cas échéant. A son tour cette action, présentera ses données au modèle qui initiera la représentation du nouvel état, et ainsi de suite.

(Cliquez sur l'image pour l'agrandir)

fig 5. Implémentation du lanceur de fusée

Notez que dans une architecture client/serveur, nous aurions besoin d'un protocole comme WebSocket (ou de polling quand WebSocket n'est pas disponible) pour obtenir une représentation correcte de l’état de l’application après qu'une action automatique ait été déclenchée.

J'ai écrit une bibliothèque open-source Java et JavaScript qui structure les machines à états-finis sur une base TLA+. Vous trouverez des exemples qui utilisent WebSocket, Polling et Queuing. Comme vous pouvez le constater dans l'exemple du lanceur de fusée, vous ne devriez pas vous sentir obligé d'utiliser cette bibliothèque. L'implémentation de la fonction « d’état » est relativement facile à coder avec des if-then-else une fois que vous comprenez son rôle.

Je crois que nous avons maintenant tous les éléments pour introduire formellement un nouveau modèle, une alternative au MVC, le pattern SAM (State-Action-Model - Etat-Action-Modèle), un pattern réactif, fonctionnel qui s’inspire de React.js et TLA+.

Le pattern SAM peut être représenté par l'expression suivante :

= SvmM.presentA(data) ) ), nap(M))

qui stipule comment la vue V du système est calculée, après l'application d'une action A.

La structure de SAM impose que : A (l'action), vm (la vue-modèle), nap (le prédicat d'action suivante) et S (la fonction d’état) doivent être des fonctions pures (par rapport au modèle). Dans le contexte deSAM, les valeurs des propriétés du système sont entièrement confinées dans le modèle et la logique qui les modifie n'est pas accessible en dehors du modèle lui-même.

Vous noterez que le prédicat de l’action suivante, nap(), est un call-back appelé une fois que la représentation de l'état a été calculée, et, prête à être présentée à l'utilisateur.

fig.6. Le pattern State-Action-Model (SAM)

Le pattern est indépendant de tout protocole (et peut être implémenté sans difficulté avec HTTP) et toute topologie de client/serveur.

Il est important de noter que SAM n'implique pas que vous utilisiez systématiquement la structure d'une machine à états-finis pour calculer le contenu de la vue. Vous remarquerez aussi que lorsque les actions sont uniquement déclenchées par la vue, le prédicat d'action suivante est une fonction nulle. Une bonne pratique, cependant, consisterait à relier les états du systèmes à des phases particulières de l’interface utilisateur .

D'un autre côté, si la machine à états-finis du système exige des actions automatiques, ni vos actions, ni votre modèle ne pourraient rester purs sans le prédicat d'action suivante (nap) : soit certaines actions auront des états (stateful) ou le modèle devra déclencher les actions, ce qui n'est pas son rôle. La fonction état est une fonction pure qui calcule la vue et le prédicat d'action suivante, à partir des valeurs des propriétés du modèle.

L'avantage principal de ce pattern est qu'il distingue clairement les opérations CRUD des Actions. Le Modèle est responsable de sa persistance, qui sera implémentée avec des opérations CRUD, inaccessible à la vue ou aux actions. En particulier, la vue ne sera jamais en capacité de faire une requête de données, les seules choses qu'elle puisse faire sont de demander la représentation de l'état actuel du système et d'initier un flux réactif qui déclenche des actions.

Les Actions représentent le comportement autorisé à opérer des modifications au modèle. Elles n'ont aucun effet de bord (sur le modèle), elles ne font que présenter de nouvelles valeurs au modèle. Quand cela est nécessaire, les actions peuvent appeler des API tierces (encore une fois, sans effet de bord sur le modèle), par exemple, une action de changement d'adresse pourra appeler un service de validation d'adresse postale et présenter au modèle l'adresse renvoyée par l’appel du service.

Voici la représentation d'une action "changement d'adresse", appelant une API de validation d'adresse :

(Cliquez sur l'image pour l'agrandir)

fig.7. Implémentation du "Changement d'adresse"

Les éléments du pattern : actions et modèles, peuvent être composés de la manière suivante :

Composition de Fonction

        data’ = A(B(data))

Composition d’instances (le même ensemble de données présenté à deux modèles)

        M1.present(data’)

        M2.present(data’)

Composition Parent-Enfant (l’instance du pattern parent contrôle l'ensemble de données présenté à l'instance enfant)

M1.present(data’,M2)

_function_ present(datachild) {

            // perform updates

            …

            // synch models

            child.present(c(data))

}

Composition Pub/Sub

M1.on(“topic”, present )

M2.on(“topic”, present )

OU

M1.on(“data”, present )

M2.on(“data”, present )

Pour les architectes qui pensent en termes de "systèmes d’enregistrement" et "systèmes d'engagement", le modèle permet de clarifier l'interface entre ces deux couches de l’architecture (fig. 8), le modèle étant responsable de toutes les interactions avec le "systèmes d’enregistrement".

fig 8. Modèle de composition SAM

Le pattern lui-même peut être composé et vous pouvez implémenter une instance SAM tournant sur un navigateur pour supporter un comportement de type "wizard" (par exemple une application ToDo) interagissant avec une instance SAM serveur :

fig. 9 Composition d'une instance SAM

Vous noterez que l'instance SAM interne est déployée dans la représentation de l’état calculée par l'instance externe.

La gestion des sessions utilisateurs doit se faire avant l’exécution d'une action (fig. 10). SAM permet aussi un mode de composition intéressant, où la vue peut appeler une action tierce en fournissant un token et un call-back pointant vers une action du système qui autorisera et validera la présentation des données au modèle grâce au token.

fig. 10 Gestion de Session avec SAM

Si l’on considère l'approche CQRS, le modèle du pattern SAM ne fait pas de distinction particulière entre les Requêtes et les Commandes, bien que l'implémentation sous-jacente doive la faire (CRUD). Une recherche ou requête "action" passe simplement un ensemble de paramètres au modèle qui permettrons d’interroger la base de données.

Nous pourrions adopter une convention (par exemple le préfixe underscore) pour différencier les requêtes des commandes, ou utiliser deux méthodes distinctes pour présenter les résultats d’une action au modèle :

 { _name : ‘/^[a]$/i’ } // Names that start with A or a

 { _customerId: ‘123’ } // customer with id = 123

Le modèle réalisera les opérations CRUD requises pour réaliser l’action correspondante, mettre à jour le contenu et déclencher le rendu de la vue. Un ensemble de conventions similaires pourrait servir à créer, mettre à jour et supprimer des éléments du modèle. Il y a plusieurs façons d'implémenter l’interaction entre les actions et le modèle (jeu de données, évènements, actions...). Il y a des avantages et des inconvénients pour chacune de ces approches, et in fine ce n’est qu’une question de préférence. Pour ma part, je préfère les jeux de données.

Dans le cas du traitement des conditions d’erreur, comme avec React, il est entendu que le modèle devra contenir des propriétés qui représenteront les erreurs concernées. Ces valeurs serviront à calculer correctement la représentation de l'état du système.

SAM offre une option innovante de cache au niveau de représentation de l'état. Intuitivement, le fait de déclencher le mécanisme de cache au niveau du composant de la vue plutôt qu'au niveau action/réponse du modèle devrait augmenter la probabilité d’utilisation du cache.

La structure réactive et fonctionnelle du pattern permet de simplifier la gestion des tests unitaires.

Le pattern SAM change complètement l'architecture des interfaces utilisateurs car, contrairement aux pattern MVC ou MVI, la logique métier peut maintenant être clairement décomposée en :

  • Actions (fonction pures)
  • Modèle (opérations CRUD)
  • Etat (fonction qui contrôle l’exécution des actions automatiques)

Du point de vue d’un concepteur d'API, le pattern rend la responsabilité de la conception des APIs au serveur, avec un contrat aussi réduit que possible entre la vue et le Modèle, qui plus est, découplé par la fonction Etat.

Les Actions, en tant que fonctions pures, peuvent être réutilisées d’un modèle à un autre tant que le modèle peut accepter le résultat de l'action. Nous pouvons nous attendre à ce que des bibliothèques d'actions, thèmes (représentations d'état) et peut-être de modèles apparaissent, maintenant qu'ils peuvent être composés indépendamment.

Avec SAM, les microservices s'intègrent naturellement avec le modèle. Des frameworks tels que Hivepod.io peuvent être connectés, tels quels, à ce niveau.

Ce qui est encore plus remarquable, c’est que le pattern, comme React, ne nécessite pas l’utilisation de templates ou de lien vue-données (databinding).

Il est probable qu’à terme un pattern comme SAM contribue à faire du virtual-dom une fonctionnalité permanente du navigateur et à ce que les représentations de l’état soient directement traitées par une API dédiée.

Voilà, je vous ai retracé mon parcours. En quelques semaines, j’ai oublié des années de programmation orientée objet. Aujourd’hui, je ne peux penser qu'en termes de programmation réactive et fonctionnelle. Le type de projets que j'ai pu construire avec SAM et la vitesse à laquelle je l'ai fait sont sans précédent. Encore une chose : je peux maintenant me concentrer sur la conception d'APIs et de Services qui ne sont plus contraints par les données de la vue et le fameux "screen scrapping pattern".

Je tiens à remercier les personnes ayant accepté de relire cet article : Prof. Jean Bezivin, Prof. Joëlle Coutaz, Braulio Diez, Adron Hall, Edwin Khodabackchian, Guillaume Laforge, Pedro Molina, Arnon Rotem-Gal-Oz.

A propos de l'Auteur

Jean-Jacques Dubray est le fondateur d'xgen.io et de gliiph. C’est un spécialiste des Architectures Orientées Services et des plateformes d'API sur lesquelles il travaille depuis une quinzaine d’années. Au début de sa carrière, il a été chercheur au HRL. Il a obtenu son diplôme de Docteur-Ingénieur à la Faculté des Sciences de Luminy, où le langage Prolog a été inventé. Il est l'inventeur de la méthode BOLT.

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT