Architecture propre: qu'est-ce que le modèle de vue?

13

Dans son livre «Clean Architecture», l'oncle Bob dit que le présentateur devrait mettre les données qu'il reçoit dans quelque chose qu'il appelle le «View Model».

entrez la description de l'image ici

Est-ce la même chose que le «ViewModel» du modèle de conception Model-View-ViewModel (MVVM) ou est-ce un simple objet de transfert de données (DTO)?

S'il ne s'agit pas d' un simple DTO, comment est-il lié à la vue? La vue obtient-elle des mises à jour via une relation Observateur?

Je suppose que cela ressemble plus au ViewModel de MVVM, car au chapitre 23 de son livre, Robert Martin dit:

Le travail du présentateur consiste à accepter les données de l'application et à les formater pour la présentation afin que la vue puisse simplement les déplacer à l'écran. Par exemple, si l'application souhaite qu'une date s'affiche dans un champ, elle remettra au présentateur un objet Date. Le présentateur formatera ensuite ces données dans une chaîne appropriée et les placera dans une structure de données simple appelée le modèle de vue, où la vue pourra les trouver.

Cela implique que le View est en quelque sorte connecté au ViewModel, au lieu de simplement le recevoir comme argument de fonction par exemple (comme ce serait le cas avec un DTO).

Une autre raison pour laquelle je pense que c'est parce que si vous regardez l'image, le présentateur utilise le modèle de vue, mais pas la vue. Alors que le présentateur utilise à la fois la limite de sortie et le DTO des données de sortie.

S'il ne s'agit ni d'un DTO ni du ViewModel de MVVM, veuillez préciser de quoi il s'agit.

Fearnbuster
la source
Je pense que la réponse est "cela dépend". S'il s'agit d'une application Web, un modèle de vue est essentiellement un DTO car il est finalement sérialisé sous forme de chaîne HTML. Sinon, un modèle de vue n'est qu'un objet spécialisé pour afficher les données dans la vue.
Greg Burghardt
Dans MVVM (WPF, applications Winforms) ViewModelest un wrapper pour Controller, Presenteret ViewModeldans l'architecture propre de Uncle Bob.
Fabio
@Greg Burghardt - Lorsque le ViewModel est une structure de données spécialisée, comment la vue est-elle informée des modifications?
Fearnbuster
@Fabio - Si je comprends bien ce que vous dites dans le modèle MVVM, le ViewModel est équivalent à tous les composants qui se trouvent dans le groupe le plus à gauche du diagramme? Si cela est vrai pour l'architecture de l'oncle Bob, alors pourquoi énumère-t-il le contrôleur et le présentateur séparément?
Fearnbuster
Je pense qu'il a séparé les gestionnaires d'entrée et de sortie de différents objets / classes. Dans MVVM, cela pourrait être Controller-> ICommandet Presenter-> data-binding mechanism.
Fabio

Réponses:

17

Est-ce la même chose que le «ViewModel» du modèle de conception Model-View-ViewModel (MVVM)

Nan.

Ce serait ceci :

entrez la description de l'image ici

Cela a des cycles. L'oncle Bob a soigneusement évité les cycles .

Au lieu de cela, vous avez ceci:

entrez la description de l'image ici

Qui n'a certainement pas de cycles. Mais vous vous demandez comment la vue connaît une mise à jour. Nous y reviendrons dans un instant.

ou s'agit-il d'un simple objet de transfert de données (DTO)?

Pour citer Bob de la page précédente:

Vous pouvez utiliser des structures de base ou de simples objets de transfert de données si vous le souhaitez. Vous pouvez également l'intégrer dans une table de hachage ou la construire dans un objet.

Architecture propre p207

Alors, bien sûr, si vous le souhaitez.

Mais je soupçonne fortement ce qui vous dérange vraiment, c'est ceci :

entrez la description de l'image ici

Ce joli petit abus d'UML contraste la direction de la dépendance du code source avec la direction du flux de contrôle. C'est là que se trouve la réponse à votre question.

Dans une relation d'utilisation:

entrez la description de l'image ici entrez la description de l'image ici

le flux de contrôle va dans le même sens que la dépendance du code source.

Dans une relation de mise en œuvre:

entrez la description de l'image ici entrez la description de l'image ici

le flux de contrôle va généralement dans la direction opposée à la dépendance du code source.

Ce qui signifie que vous regardez vraiment ceci:

entrez la description de l'image ici

Vous devriez être en mesure de voir que le flux de contrôle ne va jamais passer du présentateur à la vue.

Comment est-ce possible? Qu'est-ce que ça veut dire?

Cela signifie que la vue a son propre thread (ce qui n'est pas si inhabituel) ou (comme le souligne @Euphoric) que le flux de contrôle entre dans la vue à partir d'autre chose non représenté ici.

S'il s'agit du même thread, la vue saura quand le modèle de vue sera prêt à être lu. Mais si c'est le cas et que la vue est une interface graphique, il sera difficile de repeindre l'écran lorsque l'utilisateur le déplace pendant qu'il attend la base de données.

Si la vue a son propre thread, elle a son propre flux de contrôle. Cela signifie que pour l'implémenter, la vue devra interroger le modèle de vue pour remarquer les changements.

Puisque le présentateur ne sait pas que la vue existe et que la vue ne sait pas que le présentateur existe, ils ne peuvent pas s’appeler du tout. Ils ne peuvent pas se lancer des événements. Tout ce qui peut arriver, c'est que le présentateur écrira sur le modèle de vue et que la vue lira le modèle de vue. Chaque fois que ça en a envie.

Selon ce diagramme, la seule chose que le partage View et Presenter est la connaissance du View-Model. Et ce n'est qu'une structure de données. Ne vous attendez donc pas à ce qu'il ait un comportement.

Cela peut sembler impossible, mais il peut être fait fonctionner même si le View-Model est complexe. Un petit champ mis à jour est tout ce que la vue devrait interroger pour détecter un changement.

Maintenant, bien sûr, vous pouvez insister pour utiliser le modèle d'observateur, ou demander à quelque chose de structuré de vous cacher ce problème, mais veuillez comprendre que vous n'êtes pas obligé de le faire.

Voici un peu de plaisir que j'ai eu pour illustrer le flux de contrôle:

entrez la description de l'image ici

Notez que chaque fois que vous voyez le flux aller à l'encontre des directions que j'ai définies précédemment, ce que vous voyez est un retour d'appel. Cette astuce ne nous aidera pas à accéder à la vue. Eh bien, sauf si nous revenons d'abord à ce qu'on appelle le contrôleur. Ou vous pouvez simplement changer la conception pour pouvoir accéder à la vue. Cela corrige également ce qui ressemble au début d'un problème de yo-yo avec Data Access et son interface.

La seule autre chose à apprendre ici, en plus de cela, est que l'interacteur de cas d'utilisation peut à peu près appeler les choses dans l'ordre qu'il veut tant qu'il appelle le présentateur en dernier.

candied_orange
la source
Merci beaucoup pour la réponse, j'ai vu vos réponses sur diverses autres questions sur l'architecture propre. Suggérez-vous que la vue vérifie constamment un indicateur, par exemple, dans le modèle de vue pour voir s'il y a eu des changements? La vue devrait-elle alors à nouveau afficher tout le modèle de vue, ou dois-je utiliser un ensemble d'indicateurs imbriqués pour indiquer les données qui ont été modifiées?
Fearnbuster
La vue n'a pas à interroger en permanence. Par exemple, Web 1.0 interroge uniquement lorsque l'utilisateur frappe le rechargement. L'interrogation constante est une décision de conception qui doit tenir compte des besoins réels des utilisateurs. Je dis juste que c'est possible. Le but d'un champ de mise à jour est de rendre la détection d'une mise à jour rapide. Nécessaire uniquement si le modèle d'affichage est complexe. Tenez également compte de ce qui se passe si la vue est lue alors que le présentateur est à mi-chemin d'une mise à jour.
candied_orange
D'accord, merci beaucoup pour l'aide. Si / quand vous suivez cette architecture, est-ce la technique que vous utilisez habituellement?
Fearnbuster
1
Je pense qu'il y a une grosse erreur que cette réponse regroupe la dépendance de conception et la dépendance d'exécution. Les deux peuvent être différents.
Euphoric
1
@ Euphoric Pourquoi merci. Je les lie ensemble parce que si vous n'avez pas de dépendance de code source sur quelque chose, vous ne pouvez pas utiliser de référence d'exécution pour quoi que ce soit car vous ne comprenez pas ce que c'est. Tout ce que vous pourriez faire, c'est de conserver la référence comme une collection. Si c'est une erreur, j'aimerais le comprendre.
candied_orange
2

Je trouve ce problème trop confus et cela prendrait beaucoup de texte et de temps pour expliquer correctement le problème car je pense que vous comprenez mal Martin's Clean Architecture et MVVM.

La première chose à noter est que le diagramme que vous avez publié est incomplet. Il ne montre que la «logique métier», mais il manque une sorte d '«orchestrateur» qui fait réellement bouger les pièces dans le bon ordre. entrez la description de l'image ici

Le code de l'orchestrateur serait aussi simple que

string Request(string request) // returns response
{
    Controller.Run(data);
    Presenter.Run();
    return View.Run();
}

Je crois avoir entendu Martin en parler dans l'un de ses discours sur l'architecture propre.

Une autre chose à souligner est que la remarque de candied_orange sur le manque de cycles est fausse. Oui, les cyclés n'existent pas (et ne devraient pas) dans l'architecture du code. Mais les cycles entre les instances d'exécution sont courants et conduisent souvent à une conception plus simple.

C'est le cas dans MVVM. Dans MVVM, View dépend de ViewModel, et ViewModel utilise des événements pour informer View de ses modifications. Cela signifie que dans la conception des classes, il n'y a que des dépendances entre les classes View et Model, mais pendant l'exécution, il y a une dépendance cyclique entre les instances de View et ViewModel. Pour cette raison, il n'y a pas besoin d'orchestrateur, car ViewModel fournira un moyen d'affichage pour savoir quand se mettre à jour. C'est pourquoi les "notifications" dans ce diagramme utilisent une ligne "squigly" et non une ligne directe. Cela signifie que View observe les changements dans ViewModel, et non que ViewModel dépend de View.

entrez la description de l'image ici

La chose la plus importante que vous devriez retenir de Martin's Clean Architecture n'est pas la conception elle-même, mais la façon dont vous gérez les dépendances. L'un des points critiques qu'il soulève dans ses exposés est que lorsqu'il y a une frontière, alors toutes les dépendances de code traversant cette frontière la traversent dans une seule direction. Dans le diagramme, cette frontière est représentée par une double ligne. Et il y a beaucoup d'inversion de dépendance via les interfaces ( InputBoundary, OutputBoundaryet DataAccessInterface) qui corrige le sens de dépendance du code.

En revanche, l' ViewModelarchitecture propre est tout simplement DTO sans logique. Cela est rendu évident par la <DS>balise. Et c'est la raison pour laquelle orchestratorest nécessaire, car Viewje ne saurai pas quand exécuter sa logique.

Si je devais "aplatir" le diagramme en quoi ressemblerait-il pendant l'exécution, il ressemblerait à ceci:

entrez la description de l'image ici

Ainsi, lors de l'exécution, les dépendances sont dans une "mauvaise" direction, mais c'est très bien.

Je recommande de regarder son discours sur l'architecture propre pour mieux comprendre son raisonnement.

Euphorique
la source
Votre «orchestrateur» ne devrait pas appeler le présentateur. L'interacteur de cas d'utilisation le fait.
candied_orange
@candied_orange C'est vrai, c'est une erreur.
Euphoric
Merci pour la réponse, il est toujours bon d'avoir des opinions différentes. J'ai voté pour les deux réponses de vos gars. L'un de vous sait-il si Robert Martin a une base de code quelque part dans laquelle il a implémenté une forme de son architecture? J'ai regardé son projet FitNess, mais je n'ai pas pu voir la forêt pour les arbres. Aussi, ai-je raison de spéculer que, même si l'image que j'ai publiée est le diagramme que l'oncle Bob utilise toujours dans ses discussions, ce n'est en fait qu'un exemple de ce à quoi votre architecture PEUT ressembler? Alors que cela peut sembler très différent tant que le flux de dépendance est correct?
Fearnbuster
@Fearnbuster À votre dernière question, oui. La direction des dépendances est plus importante que la structure. Je crois que «l'architecture propre», «l'architecture de l'oignon» et «l'architecture hexagonale» sont vraiment des implémentations de la même idée de «garder les dépendances sous contrôle».
Euphoric
@Euphoric Honnêtement, je dirais que c'est probablement le cas, car dans une image différente de son livre (figure 8.2 du chapitre 8), il montre une architecture qui semble différente. Dans ce diagramme, le contrôleur est en fait un intermédiaire entre l'interacteur et le présentateur. Il n'y a pas non plus de limite de sortie pour l'interacteur; il semble que l'interacteur reçoive des demandes via une interface, puis renvoie les réponses via la même interface (je suppose que cela se fait via une simple valeur de retour de fonction, car je ne peux penser à aucun autre mécanisme qui fonctionnerait de cette façon).
Fearnbuster