Patrones y Arquitecturas de Software

Un estilo arquitectónico establece un marco de referencia a partir del cual es posible construir aplicaciones que comparten un conjunto de atributos y características mediante el cual es posible identificarlos y clasificarlos.

Arquitectura en Capas

La arquitectura en capas es una de las más utilizadas, no solo por su simplicidad, sino porque también es utilizada por defecto cuando no estamos seguros que arquitectura debemos de utilizar para nuestra aplicación.

La arquitectura en capas consta en dividir la aplicación en capas, con la intención de que cada capa tenga un rol muy definido, como podría ser, una capa de presentación (UI), una capa de reglas de negocio (servicios) y una capa de acceso a datos (DAO), sin embargo, este estilo arquitectónico no define cuantas capas debe de tener la aplicación, sino más bien, se centra en la separación de la aplicación en capas (Aplica el principio Separación de preocupaciones (SoC)).

En la práctica, la mayoría de las veces este estilo arquitectónico es implementado en 4 capas, presentación, negocio, persistencia y base de datos, sin embargo, es habitual ver que la capa de negocio y persistencia se combinan en una solo capa, sobre todo cuando la lógica de persistencia está incrustada dentro de la capa de negocio.

capas

Un detalle a tener en cuenta en esta arquitectura, es que cada capa debe de ser un componente independiente, de tal forma que se puedan desplegar por separado, incluso, es habitual que estos componentes residan en servidores separados pero que se comunican entre sí.

Referencias

Monolito

El estilo arquitectónico monolítico consiste en crear una aplicación autosuficiente que contenga absolutamente toda la funcionalidad necesaria para realizar la tarea para la cual fue diseñada, sin contar con dependencias externas que complementen su funcionalidad. En este sentido, sus componentes trabajan juntos, compartiendo los mismos recursos y memoria. En pocas palabras, una aplicación monolítica es una unidad cohesiva de código.

Una falsa creencia es que, una aplicación monolítica es un caos por dentro, donde todo el código está amontonado, no hay una estructura clara y que por lo general tiene miles de clases u objetos, sin embargo, esto es solo una mala fama que se le ha dado, si bien es verdad que se podía dar el caso, recordemos que eso también se podría dar en cualquier estilo de arquitectura, pues eso dependen más bien del programador y no del estilo arquitectónico.

Otra falsa creencia es creer que las aplicaciones Monolíticas son solo las aplicaciones grandísimas que hacen un montón de cosas, pero lo cierto es que un monolítico puede ser de una sola clase, o de miles, lo que define un estilo monolítico no es el número de clases, archivos o líneas de código, lo que lo define es que es autosuficiente, es decir, que tiene toda la funcionalidad para operar por sí mismo y sin depender de nadie más.

monolitic lg

En la imagen podemos apreciar cómo funciona el proceso de compilación de una aplicación Monolítica, el cual todos los paquetes junto con sus dependencias son compilados y da como resultado un solo artefacto, el cual incluye todo el código junto con las dependencias. En este ejemplo decimos que hemos creado un EXE, pero se pudo haber creado un Jar en el caso de Java o un JS en el caso de JavaScript, dependiendo la tecnología utilizada tendremos un artefacto diferente, pero al final, todos contendrán todo el código con sus dependencias.

Referencias

Microservicio

El estilo de Microservicios consiste en crear pequeños componentes de software que solo hacen una tarea, la hace bien y son totalmente autosuficientes, lo que les permite evolucionar de forma totalmente independiente del resto de componentes.

Un Microservicios es un pequeño programa que se especializa en realizar una pequeña tarea y se enfoca únicamente en eso, por ello, decimos que los Microservicios son Altamente Cohesivos, pues toda las operaciones o funcionalidad que tiene dentro está extremadamente relacionadas para resolver un único problema.

microservicios

En este sentido, podemos decir que los Microservicios son todo lo contrario a las aplicaciones Monolíticas, pues en una arquitectura de Microservicios se busca desmenuzar una gran aplicación en muchos y pequeños componentes que realizar de forma independiente una pequeña tarea de la problemática general.

Patrón Modelo Vista Controlador

MVC (Modelo-Vista-Controlador) es un patrón en el diseño de software comúnmente utilizado para implementar interfaces de usuario, datos y lógica de control. Enfatiza una separación entre la lógica de negocios y su visualización. Esta "separación de preocupaciones" proporciona una mejor división del trabajo y una mejora de mantenimiento. Algunos otros patrones de diseño se basan en MVC, como MVVM (Modelo-Vista-VistaModelo), MVP (Modelo-Vista-Presentador) y MVW (Modelo-Vista-Whatever).

El patrón Modelo-Vista-Controlador (MVC), es uno de los primeros que se debería aprender. Es tan fundamental que ha sobrevivido décadas en la industria y sus ideas se han esparcido por muchas plataformas. Es el padre de muchos otros patrones derivados como MVVM (Modelo-Vista-VistaModelo), entre otros.

MVC

Este patrón es esencial debido a que ayuda a responder una de las preguntas más comunes: ¿Dónde debería poner esta pieza de código?.

El patrón MVC es uno de arquitectura. Entrega un mapa de la estructura de la aplicación y como su nombre dice, consiste en tres capas: modelo, vista y controlador.

El siguiente diagrama de Apple muestra un poco la relación de las vistas y controladores.

Apple MVC

El principal problema de MVC y por qué razón nacieron otros patrones derivados es debido a la tendencia de que los controladores crecían de forma exponencial. Incluso llegando a ser llamado "Massive View Controllers", por la cantidad de responsabilidades que tenían que cumplir.

En su origen en SmallTalk el patrón representaba tres conceptos fundamentales. El Modelo (Datos y sus validaciones), la Vista (Presentación) y el Controlador (Lógica de Negocios) que tenían una relación como se muestra en la siguiente figura.

MVC en SmallTalk

mvc structure smalltalk

En la figura las líneas continuas implican una asociación directa. Las líneas discontinuas, una asociación indirecta por parte de un observador. Por lo tanto, se puede notar que el modelo desconoce la vista y el controlador, excepto indirectamente mediante notificaciones, y por lo tanto, el código del modelo es reutilizable. El controlador y la vista se vinculan al modelo, no al revés.

La función de la vista y el controlador está fuertemente acoplada, pero no significa que el controlador tenga la responsabilidad sobre múltiples vistas. Apple se desvió de la versión de SmallTalk original al promover un controlador masivo para múltiples vistas y modelos, por lo que se entiende una diferencia entre SmallTalk MVC y Cocoa MVC (Apple). Esto pudo ser consecuencia de las limitaciones en lenguajes como C y Pascal que no contaban con las características de SmallTalk que facilitaban la observabilidad de propiedades.

Para entender bien este patrón se debe mencionar que el Modelo es un objeto que puede ser observado y que encapsula la lógica compleja de las relaciones entre sus propiedades. Es decir, si ocurre un cambio de estado debe lanzar un evento que notifique a la vista y esta a su vez al controlador para que estos puedan actualizar sus estados internos. El modelo es independiente y no interactúa directamente con la vista o el controlador. El estado de la vista siempre debe ser el último estado del modelo. Como mínimo una vista debe ser notificada de las siguientes cosas:

  1. ¿Qué cambió?. Puede ser una notificación tan simple como "El modelo asociado a la vista".

  2. El nuevo valor a mostrar.

Para una implementación robusta el Modelo debe ser capaz de notificar exactamente las partes que han cambiado y cómo han cambiado. De esta forma logrando ser compatible con cualquier tipo de vista presente o futura. Como este patrón es compuesto, puede llegar a ocurrir que se necesite un modelo exclusivo para la vista y su estado actual (tamaño de ventana, entre otros), el cual también debe ser observable. Es decir, una vista puede estar escuchando notificaciones de múltiples modelos, incluso uno exclusivo para su estado interno.

La identificación y correcta definición del Modelo es vital para un sistema bien diseñado. Es común identificar modelos generales como "Imagen", pero un mejor modelo debe considerar los detalles adicionales como "Imagen con configuraciones". Una buena técnica es crear modelos según los parámetros de las funciones de la lógica de negocios.

Un ejemplo sería un botón asociado a eliminar una selección de archivos. Ésta eliminación de archivos está vinculada a una función que requiere una cantidad de parámetros y valores específicos (como ruta del archivo) para su correcta ejecución. Entonces el Modelo asociado a esta función construiría los parámetros necesarios y sus validaciones (como que el nombre del archivo exista y no sea nulo). Ésta validación puede ser observable por la Vista para habilitar/deshabilitar el botón según si es posible eliminar o no. Éste mismo Modelo puede ser reutilizado en distintas vistas y controladores dentro de la aplicación.

Modelo

La capa modelo (model), es la capa que maneja los datos y la lógica de negocios, independiente de su representación visual. Define qué datos debe contener la aplicación. Si el estado de estos datos cambia, el modelo generalmente notificará a la vista (para que la pantalla pueda cambiar según sea necesario) y, a veces, el controlador (si se necesita una lógica diferente para controlar la vista actualizada).

Volviendo a nuestra aplicación de lista de compras, el modelo especificará qué datos deben contener los artículos de la lista (artículo, precio, etc.) y qué artículos de la lista ya están presentes.

Vista

La capa vista (view) es la que muestra la información al usuario y permite interacciones, independiente de la capa de datos. La vista define cómo se deben mostrar los datos de la aplicación. En nuestra aplicación de lista de compras, la vista definiría cómo se presenta la lista al usuario y recibiría los datos para mostrar desde el modelo.

Controlador

La capa controlador (controller) es la que actúa como puente entre modelo y vista. Almacena y manipula el estado de la aplicación y proporciona datos a las vista, interpreta las acciones del usuario según las reglas de negocio. El controlador contiene una lógica que actualiza el modelo y/o vista en respuesta a las entradas de los usuarios de la aplicación.

Entonces, por ejemplo, nuestra lista de compras podría tener formularios de entrada y botones que nos permitan agregar o eliminar artículos. Estas acciones requieren que se actualice el modelo, por lo que la entrada se envía al controlador, que luego manipula el modelo según corresponda, que luego envía datos actualizados a la vista.

Sin embargo, es posible que también se desee actualizar la vista para mostrar los datos en un formato diferente, por ejemplo, cambiar el orden de los artículos de menor a mayor precio o en orden alfabético. En este caso, el controlador podría manejar esto directamente sin necesidad de actualizar el modelo.

MVC

Patrón Modelo Vista Vista-Modelo

El patrón Modelo-Vista-VistaModelo (MVVM), es un patrón de arquitectura que facilita estructurar la aplicación dividiéndola en tres roles.

MVVM
  • El modelo (model): representa los datos y lógica de negocio de la aplicación.

  • La vista (view): Muestra la información al usuario y permite la interacción.

  • La vista-modelo (view-model): Actúa como puente entre las capas de vista y modelo. Contiene el estado de la vista y maneja la lógica de interacciones.

¿Diferencias entre MVC y MVVM?

Al comparar los patrones de MVC y MVVM es notable la similitud y son casi idénticos.

La principal diferencia radica en que MVC hace énfasis en los controladores. Encargados de manejar las interacciones para varias vistas. En cambio en MVVM la vista-modelo es un único componente que controla el comportamiento y estado de una única vista. Comúnmente representado como un componente.

Otra diferencia es la forma de comunicación entre la vista y su controlador. En MVC la vista y el controlador tienen funciones definidas que son llamadas de forma imperativa para informar sobre una acción o requerir actualizar la información en la vista. Por otra parte en MVVM la vista y la vista-modelo están unidas por un mecanismo de enlazado (binding) que automáticamente informa sobre interacciones realizadas en la vista y cambios ocurridos en la vista-modelo. Estos mecanismos de enlazado varían según la plataforma.

Las capas de MVC interactúan y son interpretadas dependiendo de algunos factores como:

  • La plataforma donde se implementa.

  • La experiencia del profesional y su interpretación del patrón.

  • La moda del día (Los devs igual pueden seguir modas).

El patrón Modelo-Vista-VistaModelo (MVVM) es principalmente una versión de MVC bajo un nombre diferente.

Si bien hay ligeras diferencias, perfectamente se pueden utilizar los conceptos de MVC y MVVM de forma unificada sin problemas.

La Importancia de MVC y MVVM

El utilizar un patrón de arquitectura como MVVM con roles claramente definidos nos ayudan cumplir principios de diseño como la separación de conceptos. Lo que es una piedra angular para mantener código bien organizado, fácilmente entendible y que sus pruebas unitarias son viables de implementar.

Utilizar patrones de arquitectura como MVVM es sumamente importante. A pesar de que los frameworks otorgen herramientas innovadoras para elaborar aplicaciones, si no utilizamos patrones de arquitectura el código se irá acumulando, aumentando de complejidad, para finalmente crear monolitos masivos que son difíciles de mantener y probar.

El hecho de que algunos frameworks manejen automáticamente la actualización de las vistas no justifica abandonar las buenas prácticas en el desarrollo de software que han existido por décadas en múltiples plataformas.

Más allá de MVC

Los patrones de arquitectura como MVC y MVVM tienen su foco en aplicaciones donde principalmente tenemos interacciones de usuario (UX), pero muchas veces las aplicaciones deben comunicar con servicios externos y otros elementos que necesitan otras formas de gestionar la arquitectura de código.

Para esto se recomienda utilizar patrones como los definidos en el Diseño Orientado a Dominio (Domain Driven Design) y arquitectura Hexagonal.