Qué es el patrón MVC (Modelo-Vista-Controlador)

En programación, el patrón Modelo-Vista-Controlador (MVC) hace referencia a un tipo de patrón o arquitectura de software que divide la estructura de la aplicación en los tres componentes mencionados.

Pese a que este patrón se popularizó especialmente con la salida de Ruby on Rails en 2004. Posteriormente fue adoptada por como una posible «plantilla de inicio» en la mayoría de frameworks de los lenguajes más utilizados, como AngularJS (Javascript), Ruby on Rails (Ruby), Django (Python), Spring (Java) o ASP.NET (C#).

Como con otras arquitecturas de software, el patrón MVC busca proveer una justificación y orden a la forma de estructurar una aplicación. La finalidad de esta estructura es facilitar la escalabilidad de la aplicación creando abstracciones para simplificar la reusabilidad del código. Como veremos más adelante, la arquitectura MVC no es perfecta, pero tiene sus casos de uso en los que puede ser una buena opción.

Flujo de trabajo de MVC

Cada componente está diseñado para cumplir con una función distinta, a continuación veremos qué debería contener cada parte en el orden del flujo de una petición HTTP.

Flujo de petición HTTP en arquitectura MVC
Flujo de una petición HTTP a una web con arquitectura MVC.

Al comienzo de cada componente voy a ir presentando los componentes con una analogía para entender este flujo de trabajo como un restaurante. Las narraciones contendrán los números de los eventos de la imagen anterior.

Vista

Un cliente [Usuario] entra al restaurante [plataforma] y se sienta en una mesa (1). Al poco, un camarero [Controlador] le trae el menú [Vista] (2). No todo lo que le apetezca al cliente estará en el menú, por tanto el menú le va dando una idea de qué podría pedir, evitando que haga pedidos cualesquiera.

En este caso el «menú» es la parte del frontend de nuestra web, el diseño de la Interfaz del Usuario, el contenido de la plataforma, etc. Por tanto, la Vista es la que contiene todas las lógicas del lado del cliente, a través del uso de HTML, CSS y Javascript por lo general.

Como mencionaba la analogía, el menú «valida» parcialmente las decisiones que quiera tomar el cliente. Sin embargo, esto solo puede ocurrir si la petición viene desde la web, donde podemos poner validadores de las peticiones HTTP que hagan los usuarios a través de nuestros formularios. Es posible utilizar otros sistemas externos para lanzar peticiones a la misma, como veremos más adelante.

Controlador

Una vez el cliente ha decido lo que desea pedir, llama al camarero [Controlador] para realizar su pedido (3)(4). El camarero puede darle mucha información al cliente antes de llevar su pedido a cocina. Por ejemplo, puede ser que aquello que lo que quiera el cliente no exista en el restaurante o que tenga que consultar en cocina [Modelo] si queda aquello que el cliente pide.

Si todo es correcto, elevará el pedido a la cocina. (5)

En este caso el «camarero» es nuestro Controlador, y se encarga de procesar cualquier acción que realice el usuario en la plataforma. Como no podemos fiarnos del todo del «menú» (Vista), también es utilizado para validar la petición tanto por si mismo como con el modelo, así el usuario consigue lo que pide si todo está correcto.

Modelo

La cocina [Modelo] conoce todo lo que se puede preparar, cómo prepararlo, cuánto queda de los ingredientes, etc. Es decir, le puede proveer información importante al camarero para que se la comunique al cliente.

Cuando recibe una petición adecuada, se encarga de preparar la comida, actualizar el inventario de productos del restaurante [Base de Datos] (6), y devolverle el pedido preparado al camarero (7) para que se lo lleve de vuelta al cliente (8)(9).

Cuando decimos que la cocina conoce todo lo que se puede preparar, estamos hablando de la «lógica de negocio». Este término hace referencia a la parte de la plataforma que se encarga de codificar las funcionalidades que se les pueden ofrecer a los clientes, así como recoger las instrucciones para indicar cuándo una petición es válida y cómo se va a crear, actualizar, consultar o eliminar la información de la Base de Datos.

Controlador vs Modelo

Hay múltiples desventajas – así como ventajas – en la arquitectura MVC. Sin embargo me voy a centrar en una que hace que muchos desarrolladores nos liemos cuando comenzamos a usar este patrón:

¿Controladores «gordos» y modelos «flacos» o controladores «flacos» y modelos «gordos» (Fat controllers and skinny models or skinny controllers and fat models)?

Esta es una forma de preguntarse dónde debería ir la lógica de negocio. Muchos frameworks abogan por lo que explicábamos previamente, centrarse en que los modelos contengan la mayor parte de la lógica de negocio y el controlador contenga lo mínimo indispensable. Este planteamiento tiene sentido hasta cierto punto, pues si buscas reutilizar al máximo el código, es más fácil reutilizar un modelo que reutilizar un controlador.

Y es que si la historia acabase aquí, el patrón MVC sería prácticamente perfecto. Lamentablemente, la realidad es que muchas veces te preguntarás dónde deberías meter determinadas lógicas, porque no sentirás que pertenezca al Modelo ni a la Vista, optando por meterlo en el Controlador.

Pongamos un ejemplo de una situación con dicho problema, para ello, imagína cómo debería funcionar un artículo entre bambalinas. Tendrías seguramente un Modelo que fuera un clase llamada «Artículo», con atributos como «Título», «Contenido», «Fecha de creación» y «Autor», por nombrar unos pocos.

Te das cuenta de que la fecha tiene el formato dd/mm/aaaa hh:mm:ss, ¡pero tu no quieres que aparezca la hora, minuto y segundo de tu artículo en la pantalla que ve el usuario! Sin embargo lo piensas y no puedes eliminarlo porque la necesitas internamente para poder ordenar tus articulos por fecha de creación, por si publicas dos el mismo día.

Entonces… ¿dónde va la lógica para formatear la fecha?

¿La vista? Parecería tener sentido porque es donde queremos que se haga el cambio, pero realmente no es buena idea porque ese formateo se podría considerar lógica de negocio y la vista no debería tener dicha lógica. Piensa que las lógicas puestas en la «Vista» solo afectan a la web, pero realmente la petición podría venir desde otro sistema. Volviendo al ejemplo del restaurante, un pedido podría venir de un pedido que venga desde un cliente externo, como si pidieran por JustEat o Uber. En estos casos, la petición le llega al controlador directamente y no se devuelve ninguna vista, por tanto… ¿cómo controlas que la fecha entregada al cliente tenga el formato de lo que tu quieres?

¿El modelo? Es una opción que parece tener «sentido», pero sienta un mal precedente. ¿Por qué el modelo debería hacerse responsable por una tarea relacionada con la interfaz del usuario? Aparte, hemos dicho que nos viene bien conservar el tema de las horas para ofrecer los artículos ordenados de más recientes a menos recientes, por lo que no deberíamos modificar las lógicas ni de guardado de la fecha ni de consulta.

¿El controlador? Por descarte parece ser que es la opción que nos queda, ¿pero realmente es algo que debería decidir el controlador? Al fin y al cabo el controlador realmente solo deberia transmitir la información de un lado a otro. Volviendo al ejemplo del restaurante, es como si cuando el camarero (Controlador) recibe la comida de la cocina (Modelo), probase la comida, viera que le falta sal y se la echase antes de entregársela al cliente.

Esta situación lleva a que, pese a que los frameworks recomiendan que tus modelos sean «gordos» y tus controladores «flacos», la situación pueda acabar invirtiéndose con el tiempo, ya que acaba siendo más fácil lanzarlo todo en el «cajón desastre» llamado controlador.

El problema ha sido «resuelto» por otras arquitecturas como el Modelo-Vista-VistaModelo-Controlador (MVVM), por poner un ejemplo. El problema se resuelve creando una nueva abstracción, una cuarta capa de «Servicios» que corresponde en este caso con la VistaModelo. Esta cuarta capa actuaría como «adaptador» entre las capas Controlador y Modelo, permitiendo hacer las transformaciones necesarias entre estas dos capas.

¿Significa que no deberíamos utilizar MVC?

En absoluto, como todos los patrones, tiene ventajas y desventajas frente a otros. Lo importante es saber en qué punto está un proyecto y/o qué necesidades va a tener. Esta es una tabla resumen de las ventajas frente a las desventajas de este patrón:

VENTAJASDESVENTAJAS
Desarrollo rápido gracias a que la mayoría de frameworks te dan las bases «prehechas»Complejo de comprender en bien, poniendo mucha lógica en los controladores, perdiendo reusabilidad, escalabilidad y testabilidad
Baja complejidad para aprenderlo inicialmentePuede ser demasiada complejidad para proyectos simples
Buena integración entre equipos interdisciplinares gracias a la separación de vistas (frontend) y controladores/modelos (backend)Puede ser poca abstracción en las diferentes capas para proyectos complejos
Relativa facilidad de debug
Relativa facilidad a la hora de escalar
Las capas permiten que se pueda aplicar TDD hasta cierto punto

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

%d