Patrones de arquitectura de Android Parte 1: Modelo-Vista-Controlador

Florina Muntenescu
Florina Muntenescu

Follow

1 de noviembre, 2016 – 6 min read

Hace un año, cuando la mayoría del equipo actual de Android empezó a trabajar en upday, la aplicación estaba lejos de ser la app robusta y estable que queríamos. Intentamos entender por qué nuestro código estaba en tan mal estado y encontramos dos culpables principales: el cambio continuo de la UI y la falta de una arquitectura que soportara la flexibilidad que necesitábamos. La aplicación estaba ya en su cuarto rediseño en seis meses. El patrón de diseño elegido parecía ser Modelo-Vista-Controlador pero entonces ya era un «mutante», lejos de cómo debería ser.

Descubramos juntos qué es el patrón Modelo-Vista-Controlador; cómo se ha aplicado en Android a lo largo de los años; cómo debería aplicarse para poder maximizar la testabilidad; y algunas de sus ventajas e inconvenientes.

En un mundo en el que la lógica de la interfaz de usuario tiende a cambiar más a menudo que la lógica de negocio, los desarrolladores de escritorio y web necesitaban una forma de separar la funcionalidad de la interfaz de usuario. El patrón MVC fue su solución.

  • Modelo – la capa de datos, responsable de la gestión de la lógica de negocio y el manejo de la red o la base de datos API.
  • Vista – la capa de interfaz de usuario – una visualización de los datos del Modelo.
  • Controlador – la capa lógica, se notifica del comportamiento del usuario y actualiza el Modelo según sea necesario.

Estructura de la clase Modelo-Vista-Controlador

Entonces, esto significa que tanto el Controlador como la Vista dependen del Modelo: el Controlador para actualizar los datos, la Vista para obtenerlos. Pero, lo más importante para los desarrolladores de escritorio y de la Web en ese momento: el Modelo estaba separado y podía ser probado independientemente de la UI. Aparecieron varias variantes de MVC. Las más conocidas están relacionadas con si el Modelo es pasivo o notifica activamente que ha cambiado. Aquí hay más detalles:

Modelo Pasivo

En la versión de Modelo Pasivo, el Controlador es la única clase que manipula el Modelo. Basado en las acciones del usuario, el Controlador tiene que modificar el Modelo. Después de que el Modelo haya sido actualizado, el Controlador notificará a la Vista que también necesita actualizarse. En ese momento, la Vista solicitará los datos del Modelo.

Modelo-Vista-Controlador – Modelo pasivo – comportamiento

Modelo activo

Para los casos en que el Controlador no es la única clase que modifica el Modelo, éste necesita una forma de notificar a la Vista, y a otras clases, sobre las actualizaciones. Esto se consigue con la ayuda del patrón Observer. El Modelo contiene una colección de observadores que están interesados en las actualizaciones. La Vista implementa la interfaz del observador y se registra como observador del Modelo.

Modelo-Vista-Controlador – Modelo activo – estructura de la clase

Cada vez que el Modelo se actualiza, también itera a través de la colección de observadores y llama al método update. La implementación de este método en la Vista desencadenará entonces la solicitud de los últimos datos del Modelo.

Modelo-Vista-Controlador – Modelo activo – comportamiento

Modelo-Vista-Controlador en Android

Alrededor de 2011, cuando Android empezó a hacerse más y más popular, aparecieron naturalmente preguntas sobre la arquitectura. Dado que MVC era uno de los patrones de interfaz de usuario más populares en ese momento, los desarrolladores trataron de aplicarlo también a Android.

Si buscas en StackOverflow preguntas como «Cómo aplicar MVC en Android», una de las respuestas más populares decía que en Android, una Actividad es tanto la Vista como el Controlador. Mirando hacia atrás, ¡esto parece casi una locura! Pero, en ese momento, el énfasis principal estaba en hacer que el Modelo fuera comprobable y, normalmente, la elección de la implementación de la Vista y el Controlador dependía de la plataforma.

Cómo se debe aplicar MVC en Android

Actualmente, la pregunta de cómo aplicar los patrones MVC tiene una respuesta más fácil de encontrar. Las Actividades, Fragmentos y Vistas deberían ser las Vistas en el mundo MVC. Los Controladores deben ser clases separadas que no extiendan ni usen ninguna clase de Android, y lo mismo para los Modelos.

Un problema surge al conectar el Controlador con la Vista, ya que el Controlador necesita decirle a la Vista que se actualice. En la arquitectura MVC del Modelo pasivo, el Controlador necesita mantener una referencia a la Vista. La forma más fácil de hacer esto, mientras nos centramos en las pruebas, es tener una interfaz BaseView, que la Actividad/Fragmento/Vista extendería. Así, el Controlador tendría una referencia a la Vista Base.

Ventajas

El patrón Modelo-Vista-Controlador soporta altamente la separación de preocupaciones. Esta ventaja no sólo aumenta la testabilidad del código sino que también facilita su extensión, permitiendo una implementación bastante sencilla de nuevas funcionalidades.

Las clases del Modelo no tienen ninguna referencia a las clases de Android y, por tanto, son sencillas de probar unitariamente. El Controlador no extiende ni implementa ninguna clase de Android y debe tener una referencia a una clase de interfaz de la Vista. De esta manera, las pruebas unitarias del Controlador también son posibles.

Si las Vistas respetan el principio de responsabilidad única entonces su papel es sólo actualizar el Controlador para cada evento del usuario y sólo mostrar los datos del Modelo, sin implementar ninguna lógica de negocio. En este caso, las pruebas de UI deberían ser suficientes para cubrir las funcionalidades de la Vista.

La Vista depende del Controlador y del Modelo

La dependencia de la Vista del Modelo empieza a ser un inconveniente en las Vistas complejas. Para minimizar la lógica en la Vista, el Modelo debe ser capaz de proporcionar métodos comprobables para cada elemento que se visualiza. En una implementación activa del Modelo, esto aumenta exponencialmente el número de clases y métodos, dado que se requerirían Observadores para cada tipo de datos.

Dado que la Vista depende tanto del Controlador como del Modelo, los cambios en la lógica de la UI podrían requerir actualizaciones en varias clases, disminuyendo la flexibilidad del patrón.

¿Quién maneja la lógica de la interfaz de usuario?

Según el patrón MVC, el Controlador actualiza el Modelo y la Vista obtiene los datos a mostrar del Modelo. Pero, ¿quién decide cómo mostrar los datos? ¿Es el Modelo o la Vista? Consideremos el siguiente ejemplo: tenemos un User, con nombre y apellido. En la Vista necesitamos mostrar el nombre del usuario como «Lastname, Firstname» (por ejemplo, «Doe, John»).

Si el papel del Modelo es sólo proporcionar los datos «en bruto», significa que el código en la Vista sería:

String firstName = userModel.getFirstName(); 
String lastName = userModel.getLastName(); nameTextView.setText(lastName + ", " + firstName)

Así que esto significa que sería la responsabilidad de la Vista de manejar la lógica de la UI. Pero esto hace que la lógica de la UI sea imposible de probar unitariamente.

El otro enfoque es hacer que el Modelo exponga sólo los datos que necesitan ser mostrados, ocultando cualquier lógica de negocio de la Vista. Pero entonces, terminamos con Modelos que manejan tanto la lógica de negocio como la de UI. Sería testeable por unidades, pero entonces el Modelo termina siendo implícitamente dependiente de la Vista.

String name = userModel.getDisplayName(); nameTextView.setText(name);

Conclusión

En los primeros días de Android el patrón Modelo-Vista-Controlador parecía haber confundido a muchos desarrolladores y conducido a un código que era difícil, si no imposible de testear por unidades.

La dependencia de la Vista con respecto al Modelo y el hecho de tener la lógica en la Vista condujeron nuestra base de código a un estado del que era imposible recuperarse sin refactorizar completamente la aplicación. ¿Cuál fue el nuevo enfoque en la arquitectura y por qué? Descúbrelo leyendo esta entrada del blog.