Arquitectura limpia: ¿Qué es el modelo de vista?

13

En su libro 'Arquitectura limpia', el tío Bob dice que el presentador debe poner los datos que recibe en algo que él llama 'Ver modelo'.

ingrese la descripción de la imagen aquí

¿Es esto lo mismo que el 'ViewModel' del modelo de diseño Model-View-ViewModel (MVVM) o es un simple Objeto de transferencia de datos (DTO)?

Si es no un simple DTO, cómo se relaciona a la vista? ¿La vista recibe actualizaciones a través de una relación de observador?

Supongo que se parece más al ViewModel de MVVM, porque en el Capítulo 23 de su libro, Robert Martin dice:

El trabajo de [El presentador] es aceptar los datos de la aplicación y formatearlos para la presentación de modo que la Vista pueda simplemente moverlos a la pantalla. Por ejemplo, si la aplicación desea que se muestre una fecha en un campo, le dará al Presentador un objeto Fecha. El presentador formateará esos datos en una cadena apropiada y los colocará en una estructura de datos simple llamada modelo de vista, donde la vista puede encontrarlos.

Esto implica que la Vista está conectada de alguna manera al ViewModel, en lugar de simplemente recibirla como un argumento de función, por ejemplo (como sería el caso con un DTO).

Otra razón por la que creo que esto se debe a que si observa la imagen, el Presentador usa el Modelo de vista, pero no la Vista. Mientras que los usos del presentador tanto la salida de Límites y la salida de datos DTO.

Si no es un DTO ni el ViewModel de MVVM, explique qué es.

Fearnbuster
fuente
Creo que la respuesta es "depende". Si se trata de una aplicación web, un modelo de vista es básicamente un DTO porque finalmente se serializa como una cadena HTML. De lo contrario, un modelo de vista es solo un objeto especializado para mostrar los datos a la vista.
Greg Burghardt
En MVVM (WPF, aplicaciones de Winforms) ViewModeles envoltorio para Controller, Presentery ViewModelen la arquitectura limpia del tío Bob.
Fabio
@Greg Burghardt: cuando ViewModel es una estructura de datos especializada, ¿cómo se notifica la vista de los cambios?
Fearnbuster
@Fabio: si entiendo correctamente su significado, ¿está diciendo que en el patrón MVVM, ViewModel es equivalente a todos los componentes que están dentro del grupo más a la izquierda del diagrama? Si eso es cierto para la arquitectura del tío Bob, ¿por qué enumera el controlador y el presentador por separado?
Fearnbuster
Creo que separó los manejadores de entrada y salida a diferentes objetos / clases. En MVVM podría ser Controller-> ICommandy Presenter-> data-binding mechanism.
Fabio

Respuestas:

17

¿Es esto lo mismo que el 'ViewModel' del patrón de diseño Model-View-ViewModel (MVVM)

No

Eso sería esto :

ingrese la descripción de la imagen aquí

Eso tiene ciclos. El tío Bob ha estado evitando cuidadosamente los ciclos .

En cambio tienes esto:

ingrese la descripción de la imagen aquí

Que ciertamente no tiene ciclos. Pero te deja preguntándote cómo sabe la vista sobre una actualización. Llegaremos a eso en un momento.

o es un simple objeto de transferencia de datos (DTO)?

Para citar a Bob de la página anterior:

Puede usar estructuras básicas u objetos simples de transferencia de datos si lo desea. O puede empaquetarlo en un hashmap o construirlo en un objeto.

Arquitectura limpia p207

Entonces, claro, si quieres.

Pero sospecho fuertemente que lo que realmente te está molestando es esto :

ingrese la descripción de la imagen aquí

Este pequeño y lindo abuso de UML contrasta la dirección de la dependencia del código fuente con la dirección del flujo de control. Aquí es donde se puede encontrar la respuesta a su pregunta.

En una relación de uso:

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

el flujo de control va en la misma dirección que la dependencia del código fuente.

En una relación de implementación:

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

El flujo de control generalmente va en la dirección opuesta a la dependencia del código fuente.

Lo que significa que realmente estás viendo esto:

ingrese la descripción de la imagen aquí

Debería poder ver que el flujo de control nunca va a llegar del Presentador a la Vista.

¿Como puede ser? Qué significa eso?

Significa que la vista tiene su propio hilo (que no es tan inusual) o (como señala @Euphoric) el flujo de control está llegando a la vista desde otra cosa que no se muestra aquí.

Si es el mismo hilo, entonces la Vista sabrá cuándo el Modelo de Vista está listo para ser leído. Pero si ese es el caso y la vista es una GUI, tendrá dificultades para volver a pintar la pantalla cuando el usuario la mueva mientras espera la base de datos.

Si la vista tiene su propio hilo, entonces tiene su propio flujo de control. Eso significa que para implementar esto, la vista tendrá que sondear el modelo de vista para notar los cambios.

Como el Presentador no sabe que existe la Vista y la Vista no sabe que existe el Presentador, no pueden llamarse entre sí. No pueden lanzar eventos entre ellos. Todo lo que puede suceder es que el presentador escribirá en el modelo de vista y la vista leerá el modelo de vista. Siempre que lo desee.

Según este diagrama, lo único que comparten la Vista y el Presentador es el conocimiento del Modelo de vista. Y es solo una estructura de datos. Así que no esperes que tenga ningún comportamiento.

Esto puede parecer imposible, pero puede hacerse funcionar incluso si View-Model es complejo. Un pequeño campo actualizado es todo lo que la vista tendría que sondear para detectar un cambio.

Ahora, por supuesto, puede insistir en usar el patrón de observador, o hacer que algo del marco le oculte este problema, pero comprenda que no tiene que hacerlo.

Aquí hay un poco de diversión que ilustraba el flujo de control:

ingrese la descripción de la imagen aquí

Tenga en cuenta que cada vez que ve que el flujo va en contra de las direcciones que definí antes, lo que está viendo es una llamada que regresa. Ese truco no nos ayudará a llegar a la Vista. Bueno, a menos que primero regresemos a lo que se llama Controlador. O simplemente podría cambiar el diseño para poder acceder a la vista. Eso también soluciona lo que parece el comienzo de un problema de yoyo con el acceso a datos y su interfaz.

La única otra cosa que aprender aquí además de eso es que Use Case Interactor puede llamar a las cosas en el orden que quiera, siempre que llame al presentador en último lugar.

naranja confitada
fuente
Muchas gracias por responder, he visto sus respuestas en varias otras preguntas sobre la Arquitectura Limpia. ¿Sugiere que la Vista verifique constantemente un indicador, por ejemplo, dentro del Modelo de vista para ver si hubo algún cambio? ¿Tendría la vista que volver a mostrar todo el Modelo de vista nuevamente, o debería usar un conjunto de indicadores anidados para indicar qué datos se han cambiado?
Fearnbuster
La vista no tiene que sondear constantemente. Por ejemplo, web 1.0 solo sondea cuando el usuario presiona recargar. El sondeo constante es una decisión de diseño que debe considerar las necesidades reales de los usuarios. Solo digo que es posible. El objetivo de un campo de actualización es hacer que la detección de una actualización sea rápida. Solo es necesario si el Modelo de vista es complejo. También considere lo que sucede si la vista se lee mientras el presentador está a la mitad de una actualización.
candied_orange
Bien, muchas gracias por la ayuda. Si / cuando sigues esta arquitectura, ¿es esta la técnica que usas habitualmente?
Fearnbuster
1
Creo que hay un gran error en que esta respuesta agrupa la dependencia del diseño y la dependencia del tiempo de ejecución. Los dos pueden ser diferentes.
Eufórico el
1
@Euphoric ¿Por qué gracias? Los estoy uniendo porque si no tienes una dependencia del código fuente de algo, no puedes usar una referencia de tiempo de ejecución para nada, ya que no entiendes lo que es. Todo lo que podrá hacer es mantener la referencia como lo hace una colección. Si eso es un error, me gustaría entenderlo.
candied_orange
2

Encuentro este problema demasiado confuso y tomaría mucho texto y tiempo explicarlo adecuadamente, ya que creo que no entiendes tanto Martin's Clean Architecture como MVVM.

Lo primero que debe tener en cuenta es que el diagrama que publicó está incompleto. Solo muestra "lógica de negocios", pero le falta algún tipo de "orquestador" que realmente haga que las partes se muevan en el orden correcto. ingrese la descripción de la imagen aquí

El código del orquestador sería tan simple como

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

Creo que escuché a Martin hablar de esto en una de sus charlas sobre Arquitectura limpia.

Otra cosa a destacar es que el comentario de candied_orange sobre la falta de ciclos es incorrecto. Sí, los ciclos no existen (y no deberían) en la arquitectura del código. Pero los ciclos entre instancias de tiempo de ejecución son comunes y a menudo conducen a un diseño más simple.

Ese es el caso en MVVM. En MVVM View depende de ViewModel, y ViewModel usa eventos para notificar a View sobre sus cambios. Esto significa que en el diseño de las clases, solo hay dependencia de las clases View a Model, pero durante el tiempo de ejecución, hay una dependencia cíclica entre las instancias View y ViewModel. Debido a esto, no hay necesidad de orquestador, ya que ViewModel proporcionará una forma de Ver para averiguar cuándo actualizarse. Esta es la razón por la cual las "notificaciones" en este diagrama usan la línea "squigly" y no la línea directa. Significa que View observa los cambios en ViewModel, no que ViewModel dependa de View.

ingrese la descripción de la imagen aquí

Lo más importante que debe tomar de la arquitectura limpia de Martin no es el diseño en sí, sino cómo maneja las dependencias. Uno de los puntos críticos que señala en sus conversaciones es que cuando hay un límite, todas las dependencias de código que cruzan ese límite lo cruzan en una sola dirección. En el diagrama, este límite está representado por una doble línea. Y hay mucha inversión de dependencia a través de interfaces ( InputBoundary, OutputBoundaryy DataAccessInterface) que corrige la dirección de dependencia del código.

Por el contrario, ViewModelen Clean Architecture es simplemente DTO sin lógica. Esto se hace obvio por <DS>etiqueta. Y esta es la razón por la cual orchestratores necesario, ya Viewque no sabrá cuándo ejecutar su lógica.

Si tuviera que "aplanar" el diagrama en cómo se verá durante el tiempo de ejecución, se vería así:

ingrese la descripción de la imagen aquí

Entonces, durante el tiempo de ejecución, las dependencias están en la dirección "incorrecta", pero eso está bien.

Recomiendo ver su charla sobre Arquitectura limpia para comprender mejor su razonamiento.

Eufórico
fuente
Su "orquestador" no debería llamar al presentador. Use Case Interactor lo hace.
candied_orange
@candied_orange Cierto, eso es un error.
Eufórico el
Gracias por la respuesta, siempre es bueno obtener algunas opiniones diferentes. Voté las respuestas de los dos. ¿Alguno de ustedes sabe si Robert Martin tiene una base de código en algún lugar en el que implementó una forma de su Arquitectura? Miré su proyecto FitNess, pero no pude ver el bosque por los árboles. Además, ¿estoy en lo cierto al especular que, aunque la imagen que publiqué es el diagrama que el tío Bob siempre usa en sus charlas, en realidad es solo un ejemplo de cómo podría verse su arquitectura? ¿Mientras que puede verse muy diferente siempre que el flujo de dependencia sea correcto?
Fearnbuster
@Fearnbuster A su última pregunta, sí. La dirección de las dependencias es más importante que la estructura. Creo que "Arquitectura limpia", "Arquitectura de cebolla" y "Arquitectura hexagonal" son realmente implementaciones de la misma idea de "Mantener bajo control las dependencias".
Eufórico el
@Euphoric Honestamente, diría que este es probablemente el caso, porque en una imagen diferente de su libro (Figura 8.2 del Capítulo 8), muestra una arquitectura que se ve diferente. En ese diagrama, el Controlador es en realidad un intermediario entre el Interactor y el Presentador. Tampoco hay límite de salida para el interactor; parece que el Interactor recibe solicitudes a través de una interfaz y luego devuelve las respuestas a través de la misma interfaz (supongo que esto se hace a través de un valor de retorno de función simple, ya que no puedo pensar en ningún otro mecanismo que funcione de esa manera).
Fearnbuster