Documentos de Académico
Documentos de Profesional
Documentos de Cultura
MIT License
42 stars 13 forks
Star Notifications
master Go to file
View code
README.md
Clean Architecture
¿Qué propone?
Gritando la arquitectura
Robert Martin, más conocido como Tío Bob (Uncle Bob en inglés), plantea que la
arquitectura de un software debe gritar cuál es el uso de dicho software. Así como al ver
planos de edificios, si uno ve que el edificio posee un baño, cocina, comedor, dormitorios,
la arquitectura grita que es una casa familiar. De esta manera, al visualizar la arquitectura
de un software, se debería notar cual es el uso del mismo. La arquitectura no debería
indicar cuál es el framework o herramientas usadas para su construcción.
Volviendo al arquitecto de edificios, el mismo se asegura que un edificio cumpla con los
casos de uso antes de decidir qué materiales se usarían para su construcción. En el caso
del desarrollo de software, cumplimentar esto, asegura que el producto satisfaga los casos
de uso y retrase la decisión sobre los frameworks o herramientas a usar. Incluso, una
buena arquitectura basada en casos de usos permite que sea fácil cambiar la herramienta
que se va a usar.
La arquitectura limpia
La propuesta del Tío Bob sobre la arquitectura limpia impone las siguientes restricciones:
La regla de la dependencia
Entidades
Encapsulan la lógica de negocio de la empresa. Una entidad puede ser un objeto con
métodos, o puede ser un conjunto de estructuras de datos y funciones. Encapsulan la
mayoría de la lógica general y de alto nivel; y deberían poder reutilizarse en las diferentes
aplicaciones de la empresa. Las entidades deberían ser las menos propensas a sufrir
cambios debidos a un cambio externo. Por ejemplo, no se espera un cambio en las
entidades habiendo modificado algún aspecto de la UI o la seguridad. Ningún cambio
operacional de una aplicación particular debería afectar a la capa de entidades.
Casos de uso
Adaptadores de interfaz
Esta capa contiene un conjunto de adaptadores que convierten los datos desde el formato
más conveniente para el caso de uso y entidades al formato más conveniente o aceptado
por elementos externos como la base de datos o la UI. Los presentadores, vistas y
controladores pertenecen a esta capa. Los modelos son sólo estructuras que se pasan
desde los controladores a los casos de uso y de vuelta desde los casos de uso a los
presentadores y/o vistas. Del mismo modo, los datos son convertidos en esta capa, desde
la forma de las entidades y casos de uso a la forma conveniente para la herramienta de
persistencia de datos.
Frameworks y drivers
El círculo más externo se compone generalmente de frameworks y herramientas como la
base de datos, el framework web, etc. Generalmente en esta capa sólo se escribe código
que actúa de “pegamento” con los círculos interiores. En esta capa es donde van todos los
detalles. La web es un detalle. La base de datos es un detalle. Se mantienen estas cosas
afuera, donde no pueden hacer mucho daño.
Cruzando la frontera
En el gráfico se ve un ejemplo de cómo se cruzan las fronteras del círculo. Muestra cómo
los controladores y presentadores se comunican con los casos de uso del círculo interno.
El control del flujo empieza en el controlador, atraviesa el caso de uso y finaliza en el
presentador. La dependencia a nivel de código fuente apunta hacia adentro, hacia los
casos de uso. Se resuelve esta supuesta contradicción usando el principio de inversión de
dependencia, es decir, desarrollando interfaces y relaciones de herencia de tal manera que
las dependencias de código fuente se oponen al flujo de control en sólo algunos puntos a
través de la frontera.
Considerando que los casos de uso necesitan llamar al presentador, esta llamada no debe
ser directa ya que se violaría el principio de la regla de dependencia. Ninguna
implementación de un círculo exterior puede ser llamado por un círculo interior. En esta
situación el caso de uso llama a una interfaz definida en el círculo interno y hace que el
presentador implemente dicha interfaz en el círculo exterior.
Los datos que cruzan las fronteras deben ser estructuras de datos simples. Se puede
utilizar estructuras básicas u objetos Data Transfer. O los datos pueden ser argumentos en
las llamadas a funciones. O bien, almacenar en un diccionario o hash. Cuando se pasan
datos a través de una frontera, siempre debe ser en la forma más conveniente para el
círculo interior.
Este patrón considera la presencia de una única vista o controlador. Lo que ocurre cuando
hay múltiples vistas es lo siguiente:
En la mayoría de los frameworks de UI actuales, especialmente los de aplicaciones
móviles, los componentes de las vistas suelen ser también controladores, por ejemplo, un
botón “virtual”, siendo difícil aplicar el patrón MVC tal como fue concebido en sus orígenes.
Sin embargo, el patrón MVC o similares sigue siendo usado para el manejo de la vista y los
eventos, por lo que se puede seguir usando dentro de la capa de presentación de las
aplicaciones.
Hay muchas variantes alternativas, entre ellas MVP y MVVM. Incluso existe librerías de
programación reactiva. Sin embargo, sus diseños e implementaciones siguen siendo
acotados y no cubren varios aspectos.
Debido a que las aplicaciones móviles hace uso de internet y a que el mismo es
intermitente, es imperante la interacción con servicios externos y la persistencia de los
datos en el dispositivo, elementos que ninguno de los patrones mencionados contempla.
Que un patrón de arquitectura no contemple dichas situaciones da origen a problemas
como llamadas a un servicio web o acceso a base de datos directamente desde las clases
de la vista o el presentador, afectando a la mantenibilidad del código a futuro.
El criterio de Clean Architecture parece adecuado para resolver los problemas planteados
a pesar de que no se tiene constancia de uso de este criterio en alguna aplicación
conocida. Sin embargo ha surgido material que propone ideas para su implementación.
Tanto para Android como iOS, la comunidad de desarrolladores han realizado diversas
propuestas de la implementación de Clean Architecture. Google dispone de un repositorio
en GitHub que contiene ejemplos de arquitectura para aplicaciones Android. Uno de los
ejemplos consta de una posible implementación de Clean Architecture. Apple no ha
provisto información sobre la arquitectura de aplicaciones iOS.
Además, cada pantalla de una aplicación móvil, por lo general, responde a un caso de uso
particular. Siendo natural en el desarrollo móvil agrupar los archivos relacionados a cada
pantalla, se propone incluir los interactores de casos de usos junto con los
correspondientes archivos de la capa de presentación.
Capa de dominio
Esta capa contiene todas las entidades y reglas de negocio (casos de usos). Contiene
también las implementaciones de los interactores.
Esta capa debe estar escrito en el lenguaje puro de la plataforma, sin ninguna dependencia
con el SDK o UI.
Todos los componentes externos utilizan interfaces para conectarse con los objetos de
negocio.
Capa de presentación
Contiene la lógica relacionada con las vistas y animaciones. Se puede usar Modelo Vista
Presentador (MVP) o cualquier otro patrón de vista como MVC o MVVM. No hay lógica en
esta capa, excepto la de interfaz de usuario.
Para esta capa se propone utilizar una idea de Raymond Law, que consiste en diseñar la
presentación como un ciclo, llamado VIP, el cual tiene un diseño que se acerca al
propuesto por el Tío Bob sobre la interacción entre elementos de la frontera de 2 capas (en
este caso, capa de dominio con la capa de presentación).
Las llamadas realizadas desde la vista no deben ser bloqueantes, para evitar afectar el
rendimiento de la aplicación. Cualquier operación bloqueante que realice el interactor u otro
elemento deben realizarse en otro thread.
Capa de datos
Todos los datos necesarios para la aplicación provienen de esta capa a través de una
implementación de la interfaz que se encuentra en la capa de dominio. Utiliza un patrón de
repositorio con una estrategia de elegir diferentes fuentes de datos en función de ciertas
condiciones.
Por ejemplo, cuando se desea conseguir un usuario por ID, se selecciona la fuente de
datos de caché de disco, si el usuario ya existe en la caché, de lo contrario se consultará
en la nube para recuperar los datos y luego guardarlo en la memoria caché de disco.
La idea detrás de todo esto es que el origen de datos es transparente para el cliente, no le
interesa si los datos provienen de memoria, disco o la nube, la única verdad es que los
datos llegarán y serán conseguidos.
Una propuesta, ya adelantada en la estructura de directorios del proyecto, es definir para
cada elemento del dominio una interfaz de un repositorio para esa entidad y que en el
directorio de servicios se implemente.
Manejo de errores
Hay 2 enfoques posibles. Por un lado se pueden usar callbacks para la respuesta del
repositorio de datos, por ejemplo, el callback puede contener 2 métodos: onResponse() y
onError(). La última debe encapsular las excepciones en una clase contenedora. Este
enfoque tiene algunas dificultades porque causan cadenas de callbacks hasta que el error
llegue a la capa de presentación para ser presentados. La legibilidad del código puede ser
afectada. Otro enfoque es implementar un sistema de bus de eventos que lanza eventos si
algo ocurre algo no deseado, pero este tipo de solución es como usar un GOTO.
Mockup de la aplicación
Aclaraciones sobre la implementación
Por lo general, este tipo de aplicaciones suelen comunicarse con un servicio web, estando
toda la lógica de negocio fuera de la aplicación móvil. A modo de ejemplo, se prescindió del
desarrollo de un servicio web y se incluyó la lógica en la aplicación móvil. Los datos de las
asignaturas y cursos son provistos mediante un JSON estático y luego son almacenados
los cambios localmente, en una base de datos.
Conclusión
Inicialmente la experiencia nos indicó que había que escribir mucho código, aún para vistas
y casos de usos relativamente sencillos. Sin embargo, tener bien definida la
responsabilidad de cada elemento, el desarrollo y los cambios se pueden hacer de forma
incremental. Por ejemplo, desarrollar bien el caso de uso y luego la vista (o viceversa,
situación común en el desarrollo de aplicaciones móviles). Además, el rendimiento de la
aplicación no ha sido afectada a pesar de que se instancian muchos objetos por cada caso
de uso implementado. De todas maneras, recordemos que la aplicación de ejemplo es
relativamente simple y no tiene interacción con Internet, una de las operaciones más
lentas.
Aún nos queda definir bien cómo manejar los errores, detalle que tampoco ha sido
expuesto con claridad por las propuestas actuales de la comunidad de desarrolladores. El
problema que nos hemos encontrado en este apartado es que la capa de presentación
está totalmente aislada de la capa de datos (lugar común donde ocurren errores, ya sea
por falta de internet, timeout, etc) y la capa de dominio no debería manejar los errores, ya
que incluiría elementos del SDK de la plataforma en que se desarrolla.
Bibliografía
LAW, R. (2015). Clean Swift iOS Architecture for Fixing Massive View Controller. Clean
Swift.
http://clean-swift.com/clean-swift-ios-architecture/
Releases
No releases published
Packages
No packages published
Languages