Model View View-Model fue desarrollado por Microsoft para apuntar a plataformas de desarrollo de interfaz de usuario que admitan programación basada en eventos, específicamente Windows Presentation Foundation (WPF) y Silverlight en las plataformas .NET que utilizan los lenguajes XAML y .NET. En los años posteriores, muchos marcos Javascript como Angular, Knockout y ExtJS han adoptado el patrón.
Como la mayoría de los patrones de software, MVVM tiene sus usos apropiados y sus abusos. ¿En qué condiciones es apropiado el uso de MVVM? ¿Cuándo es desaconsejado?
Respuestas:
MVVM está destinado a ser utilizado donde se necesitan interacciones complejas de los usuarios con UI de alta fidelidad (es decir, WPF ).
Para las IU donde no se necesita este tipo de interacción, MVVM puede ser excesivo; MVP puede ser una opción más natural. Para aplicaciones web, MVC se adapta mejor. Para aplicaciones muy pequeñas que nunca crecerán (como las pequeñas utilidades Winforms), el código subyacente es adecuado.
fuente
A veces MVVM puede ser una trampa. Desde mi experiencia, favorece las aplicaciones tipo CRUD (formularios sobre datos) frente a las IU más orientadas a tareas. No digo que implique una mala arquitectura para el back-end / otras capas en la aplicación, pero he visto muchas aplicaciones MVVM que vienen con arquitectura "DDD light". No sé por qué exactamente, tal vez porque el enlace es muy fácil y es muy simple configurar una aplicación con un ORM y MVVM / Enlace usando objetos de dominio POCO / Anemic.
fuente
MVVM es una curita para capas de enlace de datos mal diseñadas. En particular, se ha visto mucho uso en el mundo WPF / silverlight / WP7 debido a las limitaciones en el enlace de datos en WPF / XAML.
De ahora en adelante, voy a asumir que estamos hablando de WPF / XAML ya que esto aclarará las cosas. Veamos algunas de las deficiencias que MVVM se propone resolver en WPF / XAML.
Forma de datos vs forma de IU
La 'VM' en MVVM crea un conjunto de objetos definidos en C # que se asignan a un conjunto de objetos de presentación definidos en XAML. Estos objetos de C # generalmente están conectados a XAML a través de las propiedades de DataContext en los objetos de presentación.
Como resultado, el gráfico del objeto viewmodel necesita mapearse en el gráfico del objeto de presentación de su aplicación. Eso no quiere decir que la asignación debe ser uno a uno, pero si un control de lista está contenido por un control de ventana, entonces debe haber una manera de pasar del objeto DataContext de la ventana a un objeto que describa los datos de esa lista.
El gráfico de objeto de modelo de vista desacopla el gráfico de objeto de modelo del gráfico de objeto de interfaz de usuario con éxito, pero a expensas de una capa de modelo de vista adicional que debe construirse y mantenerse.
Si quiero mover algunos datos de la pantalla A a la pantalla B, necesito jugar con los modelos de vista. En la mente de un hombre de negocios, este es un cambio de interfaz de usuario. Se debe tener lugar exclusivamente en el mundo de XAML. Lamentablemente, rara vez puede. Peor aún, dependiendo de cómo estén estructurados los modelos de vista y de cuán activamente cambien los datos, podría requerirse un poco de enrutamiento de datos para lograr este cambio.
Trabajando alrededor del enlace de datos no expresivo
Los enlaces WPF / XAML son insuficientemente expresivos. Básicamente, puede proporcionar una forma de llegar a un objeto, una ruta de propiedad para atravesar y convertir convertidores para adaptar el valor de la propiedad de datos a lo que requiere el objeto de presentación.
Si necesita vincular una propiedad en C # a algo más complejo que eso, básicamente no tiene suerte. Nunca he visto una aplicación WPF sin un convertidor vinculante que se haya convertido en verdadero / falso en Visible / Contraído. Muchas aplicaciones WPF también tienden a tener algo llamado NegatingVisibilityConverter o similar que cambia la polaridad. Esto debería estar activando las alarmas.
MVVM le brinda pautas para estructurar su código C # que puede usarse para suavizar esta limitación. Puede exponer una propiedad en su modelo de vista llamada SomeButtonVisibility y simplemente vincularla a la visibilidad de ese botón. Su XAML es agradable y bonito ahora ... pero se ha convertido en un empleado; ahora tiene que exponer + actualizar enlaces en dos lugares (la interfaz de usuario y el código en C #) cuando su interfaz de usuario evoluciona. Si necesita el mismo botón para estar en otra pantalla, debe exponer una propiedad similar en un modelo de vista al que pueda acceder esa pantalla. Peor aún, no puedo simplemente mirar el XAML y ver cuándo el botón ya estará visible. Tan pronto como los enlaces se vuelvan un poco triviales, tengo que hacer un trabajo de detective en el código C #.
El acceso a los datos tiene un alcance agresivo
Dado que los datos generalmente ingresan a la interfaz de usuario a través de las propiedades de DataContext, es difícil representar datos globales o de sesión de manera consistente en toda la aplicación.
La idea del "usuario actualmente conectado" es un gran ejemplo: a menudo es algo realmente global en una instancia de su aplicación. En WPF / XAML es muy difícil garantizar el acceso global al usuario actual de manera consistente.
Lo que me gustaría hacer es usar la palabra "CurrentUser" en los enlaces de datos libremente para referirse al usuario actualmente conectado. En cambio, tengo que asegurarme de que cada DataContext me da una manera de llegar al objeto de usuario actual. MVVM puede acomodar esto, pero los modelos de vista van a ser un desastre ya que todos tienen que proporcionar acceso a estos datos globales.
Un ejemplo donde MVVM se cae
Digamos que tenemos una lista de usuarios. Al lado de cada usuario, queremos mostrar un botón de "eliminar usuario", pero solo si el usuario actualmente conectado es un administrador. Además, los usuarios no pueden borrarse a sí mismos.
Los objetos de su modelo no deberían saber sobre el usuario actualmente conectado: solo representarán los registros de usuario en su base de datos, pero de alguna manera el usuario actualmente conectado debe estar expuesto a enlaces de datos dentro de las filas de su lista. MVVM dicta que debemos crear un objeto de modelo de vista para cada fila de la lista que compone el usuario actualmente conectado con el usuario representado por esa fila de lista, luego exponer una propiedad llamada "DeleteButtonVisibility" o "CanDelete" en ese objeto de modelo de vista (dependiendo de sus sentimientos) sobre convertidores vinculantes).
Este objeto se parecerá muchísimo a un objeto Usuario en la mayoría de las otras formas: es posible que deba reflejar todas las propiedades del objeto modelo del usuario y reenviar actualizaciones a esos datos a medida que cambien. Esto se siente realmente asqueroso: de nuevo, MVVM lo convierte en un empleado al obligarlo a mantener este objeto similar al del usuario.
Considere: probablemente también tenga que representar las propiedades de su usuario en una base de datos, el modelo y la vista. Si tiene una API entre usted y su base de datos, entonces es peor: están representados en la base de datos, el servidor API, el cliente API, el modelo y la vista. Realmente dudaría en adoptar un patrón de diseño que agregue otra capa que deba tocarse cada vez que se agregue o cambie una propiedad.
Peor aún, esta capa se escala con la complejidad de su interfaz de usuario, no con la complejidad de su modelo de datos. A menudo, los mismos datos se representan en muchos lugares y en su interfaz de usuario; esto no solo agrega una capa, sino que agrega una capa con una gran superficie adicional.
Cómo podrían haber sido las cosas
En el caso descrito anteriormente, me gustaría decir:
CurrentUser estaría expuesto globalmente a todos los XAML en mi aplicación. Id haría referencia a una propiedad en el DataContext para mi fila de la lista. La visibilidad se convertiría de booleana automáticamente. Cualquier actualización de Id, CurrentUser.IsAdmin, CurrentUser o CurrentUser.Id activaría una actualización de la visibilidad de este botón. Pan comido.
En cambio, WPF / XAML obliga a sus usuarios a crear un desastre completo. Por lo que puedo decir, algunos bloggers creativos le pusieron un nombre a ese desastre y ese nombre era MVVM. No se deje engañar: no está en la misma clase que los patrones de diseño de GoF. Este es un truco feo para evitar un sistema de enlace de datos feo.
(Este enfoque a veces se conoce como "Programación funcional reactiva" en caso de que esté buscando lecturas adicionales).
En conclusión
Si debe trabajar en WPF / XAML, todavía no recomiendo MVVM.
Desea que su código esté estructurado como en el ejemplo anterior "cómo podrían haber sido las cosas": modelo expuesto directamente a la vista, con expresiones de enlace de datos complejas + coacciones de valor flexibles. Es mucho mejor: más legible, más grabable y más fácil de mantener.
MVVM le dice que estructurar su código de una manera más detallada y menos mantenible.
En lugar de MVVM, cree algunas cosas para ayudarlo a aproximarse a la buena experiencia: desarrolle una convención para exponer el estado global a su IU de manera consistente. Construya algunas herramientas con convertidores de enlace, MultiBinding, etc. que le permitan expresar expresiones de enlace más complejas. Construya una biblioteca de convertidores vinculantes para ayudar a que los casos comunes de coerción sean menos dolorosos.
Aún mejor: reemplace XAML con algo más expresivo. XAML es un formato XML muy simple para crear instancias de objetos C #: no sería difícil encontrar una variante más expresiva.
Mi otra recomendación: no use kits de herramientas que fuercen este tipo de compromisos. Dañarán la calidad de su producto final al empujarlo hacia basura como MVVM en lugar de centrarse en su dominio problemático.
fuente
Realmente me gusta MVVM y encuentro sus desafíos motivadores y veo los muchos beneficios, pero ...
Para aplicaciones o juegos que requieren una gran cantidad de código de interfaz de usuario / interacción para agregar muchos comportamientos personalizados mientras se mantiene el rendimiento, a menudo es mejor usar MVVM un poco sucio, úselo cuando sea útil o esté más centrado en los datos en lugar de Áreas de interacción centradas en el código. Supongamos que desea crear un control y moverlo entre diferentes controles principales o, de lo contrario, almacenarlo en caché ...
Tiene una curva de aprendizaje bastante empinada, por lo que, a menos que tenga tiempo, planee desarrollar mucho en WPF / SL, tenga diseñadores expertos en Blend, sienta la necesidad de escribir un código de prueba para su interfaz de usuario o de lo contrario espere hacer años de mantenimiento para su proyecto: puede que no valga la pena.
No muchos diseñadores conocen Blend, no todos los proyectos valen la pena centrar las pruebas automatizadas en la capa de presentación, ya que de todos modos debe probarse manualmente y así es como encontrará los errores más importantes, no probando sus máquinas virtuales.
Realmente es una inversión. Primero debe comprender los conceptos básicos de WPF / SL y XAML, luego descubrir las formas de hacer los enlaces correctamente, conectar vs vms en algún orden, obtener su orden correcta, elegir un marco en la mayoría de los casos que podría sea problemático debido a las licencias, cree una biblioteca de sippets para codificar de manera eficiente, solo para descubrir que la plataforma no siempre funciona bien con enlaces y necesita construir una biblioteca de comportamientos que le brinden lo que necesita.
Sin embargo, en general, si supera todos los obstáculos y se vuelve bastante rentable en el patrón, todo vale la pena en claridad, facilidad de mantenimiento y ... ¿Derechos de fanfarronear? :)
fuente
He sido un programador de WPF / Silverlight durante años creando grandes aplicaciones, como sistemas comerciales, en MVVM.
Para mí, a medida que pasaron los años, aprendí que MVVM estricto consume tiempo y cuesta dinero. Por estricto, me refiero a reglas como "sin código detrás".
Es imposible en cualquier cosa que no sea la aplicación de base de datos / formulario más básica, no tener código subyacente.
Su diseñador especificará algo en el primer día que no es posible con los controles estándar, por lo que debe crear una serie de controles personalizados, o ajustar los controles existentes, para soportar el paradigma de interacción mientras trabaja con MVVM.
He escrito todo tipo de controles de interfaz de usuario con matemática, inercia, gestos, etc. y su arduo trabajo.
Pero todo esto está detrás del código, simplemente no está a la vista. Debe manejar los clics de los botones, el desplazamiento, el arrastre, etc., pero todo está bien envuelto en un conjunto de controles, lo que de alguna manera hace que este código subyacente esté bien.
A menudo es más fácil simplemente escribir el código subyacente y las cosas inteligentes de la interfaz de usuario en la vista, en lugar de crear un conjunto de controles solo por el simple hecho de hacerlo.
El objetivo de MVVM es separar la lógica de aplicación / negocio de la lógica de la interfaz de usuario. El sistema de enlace y MVVM es una buena manera de hacer esto.
Los otros objetivos promocionados, como el diseñador XAML en un escritorio, el programador C # en el otro, uno trabajando en Blend y el otro en VS, es una falacia.
Ser capaz de rediseñar rápidamente una interfaz de usuario es otra falacia. Nunca sucede, su optimización prematura; cualquier retrabajo importante requiere mucho trabajo para los modelos de vista. Ajustar es una cosa, pero las revisiones rápidas de UI no son posibles; los modelos de vista deben ajustarse al paradigma de interacción, por lo que el acoplamiento es más estricto de lo que puede imaginar.
Para mí, uso MVVM para mantener la lógica de mi aplicación separada (usualmente uso un controlador comprobable y un conjunto de modelos de vista sin lógica), pero sea cual sea el código y los trucos necesarios para que mi IU se vea y actúe de una manera sexy, no lo hago. sudalo.
De lo contrario, terminas reinando en tus diseños, animaciones geniales, etc., solo porque la idea de cómo MVVM-arize todo se vuelve demasiado alucinante.
MVVM, como la mayoría de las cosas en la vida, tiene un punto dulce en algún lugar entre dos extremos.
Lo más importante en el diseño de software es enviar su producto temprano, descubrir qué características se usan, qué interfaz de usuario funciona bien y no escribir código hermoso para un producto que nadie usa.
fuente
Si su aplicación requiere que se una a cantidades excesivas de datos en tiempo real, MVVM realmente puede interponerse porque está introduciendo abstracciones que ralentizan el proceso y, suponiendo que estamos hablando de WPF / Silverlight / WP7 en este momento, el enlace el motor actualmente no es tan eficiente; aunque las mejoras están en camino.
MVVM, tal como está, tampoco es la única parte de la ecuación que debe tener en cuenta. El MVVM puro debe ser compatible con la infraestructura, como el patrón Mediator, para permitirle comunicarse a través de ViewModels desconectados.
A pesar de la opinión de blucz arriba, MVVM está en la línea de los patrones de GoF. Si echa un vistazo a los patrones, MVVM es el equivalente del modelo Presentador pasivo de vista de modelo, que apareció aproximadamente al mismo tiempo que MVVM. A menudo, aquí las personas se quejan de la complejidad de MVVM simplemente porque no entienden cómo diseñar su uso.
Otra área en la que he encontrado problemas con MVVM es donde debe incorporar una tecnología de terceros que no esté diseñada para admitirla (como el marco UII para MS Dynamics). A veces tienes que preguntarte si vale la pena o no "hackear" la otra tecnología solo para trabajar con MVVM.
Si está mezclando y combinando algo como Win Forms en su solución WPF, entonces esa parte de la solución probablemente tampoco será adecuada para MVVM. Espero que esto te dé una idea de algunas áreas en las que MVVM no es aplicable.
fuente
Usar MVVM no tiene sentido cuando:
Eso es. Realmente no puedo pensar por qué NO usarías MVVM cuando trabajas con WPF / Silverlight, a menos que estés probando o depurando algo en un proyecto separado. El patrón de diseño me parece ideal para el desarrollo de WPF / Silverlight debido a la forma en que funcionan los enlaces XAML.
El punto principal de MVVM es que toda su aplicación se ejecuta en sus ViewModels, y sus Vistas son simplemente una bonita capa que los usuarios pueden usar para interactuar con sus ViewModels. Desea hacer clic en un botón, en realidad está ejecutando un método ViewModel. Si desea cambiar la página, en realidad está cambiando la propiedad CurrentPage en ViewModel.
Uso MVVM para todo el desarrollo de WPF / Silverlight, incluso proyectos pequeños y simples de una sola página, aunque la forma en que uso MVVM es diferente según el tamaño del proyecto y lo que necesito. La única vez que hice una pequeña aplicación sin MVVM, terminé arrepintiéndome (luego se refactorizó para usar MVVM al agregar una actualización)
fuente
Trabajé un poco para un cliente en un proyecto que estaba detrás del código con un intento de convertir a MVVM y fue un desastre enorme. Eso no quiere decir que todos los proyectos de código subyacente sean un desastre. Las vistas producirían un error o bloquearían Blend, lo que causó problemas a los diseñadores.
He incursionado en RoR y prácticamente me he saltado de hacer cualquier cosa con ASP.NET Webforms, pero cuando salió ASP.NET MVC intenté aprender todo lo que pude, a menudo usando los libros ASP.NET MVC en acción y el servidor de código como referencia. . Aunque es un patrón diferente, uso muchas de las cosas que aprendí de los libros In Action en el desarrollo de SL / MVVM.
Cuando comencé a trabajar con Silverlight, me sorprendió lo desnudo que estaba y me sentí como un requisito para elegir uno de los muchos marcos disponibles para vestirlo. Veo esto como un problema con las personas que dejan de aprender MVVM.
Comencé con el excelente MVVM-Light que me ayudó a comprender el patrón. Más tarde comencé a trabajar con Caliburn Micro y luego se encendieron las luces. Para mí, Caliburn Micro es como usar ASP.NET MVC sobre ASP.NET Webforms. Entonces, incluso para pequeñas aplicaciones de muestra, creo el proyecto, NuGet CM, y estoy listo para funcionar. Sigo el primer enfoque de ViewModel y mantengo mis Vistas tontas y fáciles de trabajar en Blend. Mis máquinas virtuales son comprobables si estás en eso y con CM es bastante fácil pasar por diseños de pantalla complejos.
fuente
Puede disfrutar mirando esta alternativa. Esta opción evita la forma de vinculación de datos, plantillas de datos y MVVM de WPF. Esta opción es más como el viejo, simple y confiable enfoque WinForms designer.cs.
Compuestos WPF
http://wpfcomposites.codeplex.com/
Aquí, el código conciso C # subyacente para WPF se produce al superponer una matriz simple en la parte superior de la interfaz de usuario a través de compuestos basados en cuadrícula. Si una interfaz de usuario XAML moderna solo contiene unas pocas etiquetas de texto y un cuadro de lista de fotos, ¿por qué no se puede definir esto por la simple línea de código: grid.AddText (guid, coordenada x, coordenada y)? Tenga en cuenta que esto no está en un lienzo, pero aún está dentro de los contenedores de WPF: cuadrícula, panel de acoplamiento, etc. WPF es muy poderoso. Este enfoque simplemente aprovecha esto.
Los desarrolladores no suelen preocuparse por las matrices e índices. Comience con un nivel de contenedor de grano grueso definido por los GUID de los objetos de transferencia de datos (DTO) o POCO, luego complemente estos contenedores con clave con una matriz de granos y columnas potenciales dentro de un grano más fino.
El proyecto codeplex anterior introduce este enfoque comenzando con el control ListBox pero se está expandiendo para cubrir todos los controles compuestos de WPF. Por ejemplo, cada elemento de listbox es un compuesto agregado con un GUID (un compuesto vincula uno a uno a una clase), luego dentro de este elemento hay una cuadrícula en la que los elementos de la interfaz de usuario secundaria (los elementos secundarios se unen a las propiedades en una clase) se puede agregar a voluntad mediante código subyacente. Los niños pueden ser bloques de texto o imágenes.
La idea es aprovechar los índices y una estructura de elemento de interfaz de usuario bien definida (obliga a un marco de presentación. Este nuevo enfoque limita deliberadamente lo que se puede hacer, pero al hacerlo produce un código de C # conciso y robusto que es intuitivo. No es necesario buscar soluciones de plantillas de control para diseñar una barra de desplazamiento o saturar una solución con múltiples plantillas de datos para tareas simples.
fuente
MVVM se basa principalmente en el marco de la interfaz de usuario que estoy usando. Entonces, con algo como WPF o Silverlight que tiene un paradigma basado en el enlace a un contexto de datos, ese contexto de datos siempre podría llamarse un modelo de vista.
Entonces, la pregunta para mí es cuándo construye una clase separada grande y gruesa que es el modelo de vista para este control / ventana / aplicación y cuándo puede salirse con la suya utilizando los objetos que ya están construidos.
Así que tenemos una pregunta clásica sobre cómo agregar una capa de abstracción. la VM agregará peso, inercia y estructura a un proyecto. Hará que sea más fácil construir, pero más difícil de cambiar y más largo de construir. Ninguna de esas cosas es fácilmente cuantificable.
Para una respuesta barata, MVVM no es apropiado para aplicaciones de línea de comandos o servicios web :)
fuente