Skip to main content

arquitectura limpia android¿Alguna vez os habéis encontrado con que el código de vuestras aplicaciones Android es un auténtico caos? Si la respuesta es sí, tranquilos, no sois los únicos. Esto puede deberse a la cantidad de las llamadas asíncronas, métodos relacionados con UI y boiler code que introduce el propio ecosistema de Android. En estos casos solucionar bugs, testear e incluso hacer modificaciones sobre nuestras apps resulta un trabajo casi imposible. Entonces ¿Cómo podemos evitar todos estos problemas? Aquí es donde entra el concepto de Clean Arquitecture o Arquitectura limpia.
De manera muy resumida sería una serie de conceptos y metodologías que procuran que nuestras aplicaciones sean lo más eficientes, robustas y escalables posible. ¿Qué objetivos tenemos a la hora de implementar una arquitectura limpia? Principalmente son tres:

  • Tener un sistema independiente del framework que estemos usando
  • Poder testear
  • Tener independencia de la UI, de la base de datos y de cualquier factor externo

El primer paso para lograr estos objetivos es separar la UI (framework de Android) del resto de elementos del sistema. Una vez lograda la independencia de la UI, podemos alcanzar el resto de objetivos anteriormente señalados. ¿Cómo logramos entonces separa la UI?  La respuesta, como casi siempre en cuanto a arquitectura de software se refiere, es la separación del sistema en diferentes capas.

  • Capa de presentación (Framework Android): En ella se gestiona la lógica relacionada con las vistas, activities, fragments, views, etc. Existen diversos patrones que nos permiten implementar esta capa de una forma estructurada y «limpia»: MVP (model view presenter), MVC (model view controller) y MVVM (model view view model) son algunas de ellas. La única lógica que existe en esta capa es la de la UI, solamente se envían y se reciben datos ya procesados.
  • Capa de dominio: Toda la lógica de negocio de nuestra aplicación se gestiona aquí. Esta capa debería ser un módulo de Java puro, sin ninguna dependencia del framenwork de Android. También implementa la comunicación entre las capas de presentación y datos.
  • Capa de datos: Todos los datos que necesita nuestra aplicación proceden de esta capa. La mejor forma de implementarla es utilizando el patrón repositorio. Es decir, a las capas superiores les da igual de donde vengan los datos y cómo se gestionan, ya sean web services, bases de datos, etc.separacion por capas android

Ahora bien ¿cómo llevamos toda esta teoría a la práctica? Uno de los problemas que nos encontramos con las arquitecturas limpias es la cantidad de clases e interfaces que debemos crear para conseguir una Arquitectura Limpia. Gracias a la comunidad de desarrolladores de Android y al propio Google, disponemos de una gran cantidad de librerías que permiten ahorrarnos trabajo a la hora de picar todo ese código sin perder de vista el objetivo de ser «limpios». Algunas con las que trabajamos en SlashMobility y que más nos han gustado son las siguientes (todas ellas disponibles vía Gradle):

  • ButterKnife: permite evitarnos hacer las pesadas declaraciones de vistas típicas de Android mediante la anotación @Bind(id_view). Pero la potencia de ButterKnife no termina aquí sino que también hace posible declarar métodos para eventos mediante anotaciones como: @OnClick(id_view), @OnItemClick(id_view), etc. 
  • Dagger 2: la misión de este inyector de dependencias es ahorrarnos trabajo a la hora de declarar nuevas variables, clases, interfaces, etc. Intenta mimetizar el código que haría un programador a mano a la hora de hacer declaraciones.
  • Mosby: esta librería nos ayuda a implementar apps usando el patrón MVP, de una forma mucho más estructurada que haciéndolo nosotros a mano. 
  • Reactive Libs (RxJava, RxAndroid): esta nueva metodología permite la realización de tareas asíncronas utilizando el patrón Subscriber -> Observable. Es bastante compleja de utilizar pero una vez nos hemos acostumbrado a este patrón veremos que ya no necesitaremos nunca más los tediosos AsyncTask de Android.
  • RetroLambda: permite utilizar el concepto de lambdas, que hasta ahora sólo estaba disponible en lenguajes de programación funciones como Prolog, Haskell, etc. 

Pero ¿es realmente necesario todo esto? Puede parecer bastante abrumador al principio intentarlo. Pero como dice el dicho: la práctica hace al maestro. Y como no, el resultado final es una app robusta, fácil de testear y de detectar errores y bugs. Al fin y al cabo, seremos más eficientes a la hora de trabajar y desarrollar nuestras apps. Además, si tenemos que implementar nuevas features en nuestra aplicación los cambios a realizar sobre el código ya escrito y testeado serán mínimos. ¿Necesitáis alguna razón más?
Autor del post: Daniel Morales

Deja una respuesta