Cuando llevas un tiempo programando, te das cuenta de la necesidad de establecer una serie de reglas para que tu código sea lo más simple, autoentendible y reutilizable posible. Con este artículo se explicará la arquitectura Clean utilizada en Bemobile, con la cual se establecen unas líneas sobre el desarrollo, y se describirán las razones de sus características.

El diagrama mostrado a continuación es la descripción gráfica de la arquitectura clean utilizada en Bemobile, basada en distintas implementaciones de diferentes “personalidades” del mundo Android. Todas estas metodologías están basadas en la arquitectura de the Uncle Bob, definida con unos círculos concéntricos de dependencias que diseñó y presentó en agosto 2012.

graph_clean architecture2

Como podemos apreciar en la figura anterior la lógica de la aplicación se divide en 3 módulos, un módulo PRESENTATION, otro DOMAIN, y finalmente DATA.

La capa Presentation:

parte1

Es la encargada de generar y mostrar la información a través de cualquiera de los tipos de vistas disponibles en Android y la dividimos en tres partes: la VIEW, el CONTROLLER y el PRESENTER. En esta última capa también se incluyen las librerías de terceros que se encargan de mostrar mensajes por pantalla.

La VIEW siempre, o prácticamente siempre, se tratará de un elemento contenedor visual de Android: Actividades, fragmentos, diálogos, etc. Todas y cada una de estas clases tendrán un PRESENTER asociado, encargado de gestionar la lógica de conversión de los modelos de datos a vistas. Para definir las posibles comunicaciones que se podrán realizar entre el PRESENTER y la VIEW está el CONTROLLER. El Controller está definido como un interfaz que contiene dos interfaces a su vez, una que define la comunicación vista -> presentador y otra para la comunicación presentador -> vista.

Toda la capa PRESENTATION es ejecutada en el thread de UI de interfaz.

La Capa de Dominio:

parte2

Esta capa es la encargada de alojar todos los casos de uso, la interfaz principal del repositorio, y los parseadores de datos.

Un caso de uso se trata de una acción unitaria que puede derivar en una o varias acciones del repositorio y que se ejecuta en segundo plano. Normalmente cada caso de uso necesitará un parseador de datos, que se define como un conversor que tiene como entrada una entidad y a partir de ella nos genera un modelo, o bien tiene como entrada un modelo y nos genera una entidad.

La gran ventaja y el por qué de utilizar parseadores y modelos de datos diferentes para las capas de DATA y PRESENTATION es la siguiente: normalmente los datos mostrados por pantalla son diferentes de los datos de las respuestas de los servicios web y otras fuentes de datos, y muchas veces necesitaremos llamar a más de un servicio que devolverán una o varias entidades que convertiremos a un modelo, para mostrarlo por pantalla. Realizando así la estructura de la aplicación conseguimos separar completamente la parte visual de la aplicación de la parte de backend, obteniendo dos cosas:

  1. Libertad para desarrollar toda la interfaz sin depender de backend.
  2. Blindar la aplicación ante cambios en el modelo de datos del servicio.

La Capa Data:

parte3

La capa data es aquella encargada de obtener los datos desde los orígenes más variopintos que se nos puedan ocurrir. En el diagrama podemos ver 3 orígenes de datos disponibles: origen de red basado en RETROFIT 2, un origen de datos de sesión, para guardar la sesión de usuario basado en shared Preferences, y un repositorio de información local en donde podemos tener desde bases de datos hasta archivos de texto, entre otras fuentes de datos.

Esta capa se centra en la implementación del repositorio definido en la capa domain, dónde se definirán también las interfaces de cada uno de los repositorios específicos. La razón tras utilizar siempre interfaces para realizar las comunicaciones es sencilla: si en algún momento queremos implementar por ejemplo un MOCK NETWORK REPOSITORY, podríamos crear dicha clase que implemente las interfaces de NETWORK REPOSITORY y que sea esta la que contenga la lógica de cada método definido en las interfaces. Definiendo una clase con interfaces nos desentendemos del contenido de la clase y solo nos importan las entradas y salidas de datos.

Jordi GonzalezJordi Gonzalez

Leave a Reply

Your email address will not be published. Required fields are marked *