Android - Desmitificando Clean Architecture
Tags: android, programming, architecture, mobile
Published: 2021-12-30 17:22:28

## Antes de comenzar…

Si es tu primera vez leyendo sobre Clean Architecture quizá te convenga saber algunas cosillas antes de seguir:
- Clean Architecture es el título de un libro escrito por Robert C. Martin (aka. Uncle Bob)
- No es una arquitectura en sí, sino una guía que encierra un conjunto de principios a seguir.
- La base de esta guía se encuentra en aplicar los principios SOLID.
- En términos generales, te intenta llevar a una estructura basada en el Dominio (_Domain_) como punto central de tu aplicación (la capa en la que se implementará la lógica de tu aplicación). ¿Alguien habló de Domain-driven development?
- Un buen número de desarrolladores la confunde la arquitectura con N-capas.
- No es el santo grial, es una expresión algo mainstream entre los desarrolladores y por ende sirve como una forma fácil de describirle a un desarrollador de qué manera se ha estructurado un proyecto.

## ¿Qué es una arquitectura?

Básicamente, es una estructura, una manera de distribuir los componentes que conforman una aplicación en distintas agrupaciones. Por esto mismo, no existe una única manera de organizar tu proyecto. Diversos aspectos como el estado de tu proyecto, el tamaño de tu equipo, el tiempo, etc influirán en las decisiones que tomes al momento de decidir la manera en la que organizarás los componentes de tu aplicación.

## Clean Architecture en el mundo Android

Mucho se ha dicho y escrito sobre cómo aplicar _Clean Architecture_ en las aplicaciones que desarrollamos, un buen número de desarrolladores te hablarán sobre _Separation of concerns and testing_ como las principales características de seguir estos principios, suelen a su vez olvidar un aspecto muy importante sobre _Clean Architecture_ y que consiste en que su base yace en la implementación de la capa de Dominio.

Dicho esto ¿cómo se estructuraría un proyecto base siguiendo estos principios? Para trabajar en esto es importante establecer dos consideraciones importantes:

- Existe una regla en _Clean Architecture_ por la cual toda capa exterior dependerá de una capa interior (y no al revés), quedando para el final la capa de Dominio sin dependencia alguna.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dadpc22gfbugpf3pmd17.png)

- Existe un flujo de datos que pasa por todas las capas externas e internas tanto de ida desde que se efectúe el ingreso de datos por parte del usuario (o de los sensores), pasando por la lógica de negocio/aplicación y terminando en la persistencia de los datos o el envío de los mismos a un servicio remoto, como también de vuelta con el resultado de la operación con el servicio hasta la presentación del resultado a nuestro usuario.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccepm0me3tm77wsfltwp.png)

Teniendo en cuenta estos dos aspectos, para una estructura básica contaríamos con tres módulos: _presentation_, _domain_ y _data_. La relación entre estos sería de la siguiente manera:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/96jyttwblu32zd88ru05.png)

## ¿Qué componentes irían en cada capa?

Es importante reiterar que al hablar de arquitectura, hablamos de organización y estructura, por lo tanto, la distribución y qué componentes en específico irán en cada módulo dependerá del patrón que decidas emplear y el propósito de cada módulo: 
- _Domain_ deberá contener los elementos que contengan la lógica de tu aplicación y la lógica del negocio. Con ello en mente, tendremos clases de dominio, y además componentes que tendrán la lógica como son los Casos de Uso o Interactors. Este módulo NO debe depender del Android framework ni de dependencias de terceros. Este módulo puede ser un módulo Kotlin.
- _Presentation_ tendrá los elementos que permitan mostrar información a nuestro usuario, recibir datos del mismo o de sensores. Además de los componentes visuales propios de Android (Activity y Fragment) y su sistema de UI (archivos XML o funciones de Compose), si se siguen patrones como MVP o MVVM, tendremos también Presenters o ViewModels respectivamente. Este módulo es un módulo Android.
- _Data_ va a incluir todas las dependencias de networking (Retrofit, volley, etc) y de persistencia de datos (Room, SharedPreferences, DataStore, Firebase, etc). Si se emplea el patrón repositorio será en esta capa en la que tendremos la implementación de los repositorios y las fuentes de datos (data sources). Este módulo es un módulo Android también.

Seguramente aquí te podría surgir la siguiente duda: si _Domain_ no tiene visibilidad de _Data_ ¿cómo es que podríamos inyectar los repositorios en nuestros casos de uso? La respuesta se encuentra en el principio de Inversión de Dependencia (_Dependency inversion_) de SOLID.

## Dependency inversion principle

Este principio de SOLID establece dos consignas:

- Los módulos de alto nivel no deberían importar nada de un módulo de bajo nivel. Pero ambos deberían depender de abstracciones (interfaces).
- Las abstracciones no deberían depender de los detalles. Los detalles (las implementaciones concretas) deberían depender de las abstracciones.

Teniendo en mente esto, nuestro módulo _Domain_ deberá ser propietario de la interfaz del repositorio que se implementará dentro del módulo _Data_. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gboebcmfhsy7uuprzhjg.png)

En código esto luciría más o menos de la siguiente manera, en el módulo _Domain_ estaría la abstracción de un BookRepository.

```
interface BookRepository {
    suspend fun getBooks():List<Book>
}
class GetBooksUseCase(
    private val bookRepository: BookRepository
) { /*...*/ }
```
Mientras que en el módulo Data iría su implementación.
```
class BookRepositoryImpl (...) : BookRepository {
    override suspend fun getBooks(): List<Book> { /* ... */}
}
```

De este modo al momento de crear una instancia de nuestro caso de uso le podremos inyectar la implementación debido a la interfaz que hemos declarado.

## Conclusiones
Podría mencionar algunas cosas como parte de la conclusión:
- Contar con una arquitectura o forma de organizar los componentes es mejor que no tener ninguna.
- _Clean Architecture_ no es una arquitectura en sí, pero nos provee de una guía a seguir para estructurar nuestros proyectos.
- Existen otras arquitecturas que no cuentan con mucha fama, pero no por ello son menos útiles.
- Teniendo esta estructura, puedes usar lo que se te antoje tanto en la presentación (sea Views-XMLs o Compose) como a nivel del acceso a datos (Retrofit, Room, SharedPreferences, etc).
- En mi experiencia, la buena aplicación de los principios SOLID te da una buena base para ir perfilando la arquitectura de tu proyecto.
- La relanzada [guía oficial de arquitectura de Android](https://developer.android.com/jetpack/guide) no sigue Clean Architecture, pero sí provee de una arquitectura separada en capas.

## Referencias

- [Clean Architecture](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164)
- [Dependency Inversion principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle)
- [Architecting Android…Reloaded by Fernando Cejas](https://fernandocejas.com/blog/engineering/2019-05-08-architecting-android-reloaded/)