Modularización de aplicaciones Android: consejos para empezar

Compartir esta publicación

La modularización de aplicaciones Android se refiere al proceso de dividir una aplicación Android en módulos más pequeños e independientes. Estos módulos pueden considerarse bloques de construcción que pueden combinarse para formar la aplicación completa.

Cada módulo suele ser responsable de una característica o funcionalidad específica de la aplicación y puede desarrollarse, probarse y desplegarse de forma independiente. La modularización de una aplicación puede ofrecer varias ventajas, como un mantenimiento más sencillo, ciclos de desarrollo más rápidos, mejor escalabilidad y mayor rendimiento.

Al aislar los cambios en módulos específicos, los desarrolladores pueden realizar actualizaciones de forma más eficiente y evitar efectos secundarios no deseados. Además, la modularización puede ayudar a reducir el tamaño de la aplicación y mejorar su rendimiento general al permitir a los usuarios descargar sólo los componentes necesarios. En resumen, la modularización es una potente técnica que puede ayudar a los desarrolladores a crear aplicaciones Android más eficientes, escalables y fáciles de mantener.

Contexto

Trabajamos con un proyecto legacy cuyo desarrollo comenzó hace más de 4 años por otra empresa con otros estándares, prácticas y experiencias.

En este proyecto trabajamos con sprints de 2 semanas, siempre entregando nuevas funcionalidades y arreglando bugs, con alcances muy cerrados donde añadir tareas técnicas es difícil. Hemos ido añadiendo buenas prácticas comunes como testing y arquitectura limpia, y también hemos añadido nuevos elementos dentro del entorno de desarrollo Android como Room o Jetpack Compose.

Ahora empezamos a afrontar una necesidad: empezar a modularizar la app de Android para obtener todas sus ventajas.

Modularización de aplicaciones Android: ¿Por qué hacerlo?

La modularización de aplicaciones Android puede aportar varias ventajas al mantenimiento, la escalabilidad y el proceso de desarrollo de su aplicación.

  • Compilaciones más rápidas: Gradle acelera el tiempo de compilación de tu proyecto al permitirte realizar tareas en paralelo y reutilizar todo el código ya compilado sin modificarlo. Cuando empiezas un proyecto nuevo puede que no aprecies el tiempo de compilación, pero cuando tu proyecto crece es habitual tener tiempos de compilación de alrededor de 5 minutos. Para ajustar pequeños detalles de la vista, deberás compilar tu proyecto entre 3 y 5 veces, acumulando así tiempos muertos.
  • Tiende a simplificar el desarrollo. Trabajar en pequeños módulos centrados en una única funcionalidad facilita la corrección, el mantenimiento y la mejora del código. Solo con limitar el tamaño del código, revisar o añadir pruebas para iniciar una refactorización resulta más cómodo.
  • Reutiliza módulos entre apps. Tal vez uno de tus módulos pueda convertirse fácilmente en una biblioteca y puedas abrirlo a la comunidad de código abierto con todas las ventajas sin que ello afecte a toda tu app, tanto en términos de seguridad como de integración.
  • Facilita la incorporación de más personas al equipo. Al dividir tu código en módulos más pequeños, puedes asignarles personas o equipos directamente sin afectar al resto de la aplicación. Por ejemplo, si tienes una función de chat en tu aplicación para Android y necesitas ayuda para cumplir un plazo con una funcionalidad, el mero hecho de tener que entender ese módulo sin tener que entender el resto de la aplicación hace que recibir o dar ayuda sea mucho más rápido.
  • Mejora de la automatización de las pruebas. Al poder probar módulos sin tener que hacer todo el flujo, las pruebas irán más rápido y los errores de pasos anteriores no se propagan. Puedes crear reglas específicas en tu CI para acelerar el tiempo de compilación, por ejemplo, solo activar las pruebas de interfaz de usuario, normalmente las más lentas, al fusionar a tu rama de desarrollo principal.
  Nuestra experiencia migrando de Dagger a Koin

Modularización de aplicaciones Android: Consejos para empezar

¿Cómo podemos iniciar la modularización de nuestra aplicación Android sin detener el desarrollo ni afectar a nuestra capacidad de entrega?

Afrontar un reto tan grande nos puede abrumar, pero el consejo más importante es tener paciencia. Al final encontraremos el primer paso del camino y poco a poco iremos añadiendo módulos hasta tener la app completamente modularizada.

En este artículo, no buscamos dar con una receta perfecta sobre cómo modularizar tu app. Cada proyecto es diferente y abordarlo con unos pasos estrictos puede ser más un problema que una solución. Por ejemplo, si nos dijeran que en nuestro proyecto empezaremos por la parte de networking sería un caos y decaeríamos en el intento al ver que tenemos algunas dependencias en analítica y muestra de errores. Solo crear estos dos módulos que utilizará el networking nos podría tomar un par de semanas en tenerlo todo testado y asegurar que no hemos roto nada. Y volvemos al contexto, no tenemos estas dos semanas para focalizarnos en tareas técnicas. Debemos adaptarnos a nuestra situación y buscar cómo añadir pequeños módulos para que al final, abordar networking sea mucho más trivial y poder realizarlo en los típicos finales de sprint con algún hueco para tareas externas.

Analiza tus dependencias

Busca una funcionalidad pequeña que tenga pocas dependencias, o mejor aún, ninguna. En nuestro caso fue toda la parte de programación funcional y todas las extensiones de Kotlin que hemos creado a lo largo de estos años. Creamos el módulo, movimos todo el código allí, test incluidos, y compilamos. Eureka! funciono! ¿Fácil? Bueno tuvimos que cambiar todos los imports del proyecto, más de 100 archivos modificados, comprobar que no habíamos roto ningún test y que todas las funcionalidades de la app seguían intactas, pero teníamos nuestro primer módulo.

  ORM: evitar el uso de many-to-many relationships

Prueba antes de empezar

Una buena práctica que deberíamos tener en nuestros proyectos es tener una buena base de tests, pero a veces llegamos a un proyecto y no es así. Por lo tanto, si encontramos esa pequeña funcionalidad sin dependencias, antes de moverla al nuevo módulo, crearemos unos test que la envuelvan y migraremos todo al nuevo módulo sea, con suerte, cambiar imports y que todo funcione. Nosotros pudimos hacer el primer módulo porque ya teníamos una buena base de test qué cubrían toda esta parte.

Usar Gradle para componer dependencias

Uno de los inconvenientes que nos podemos encontrar al modularizar nuestro proyecto, puede ser la gestión de dependencias y versiones. Suele ser habitual el típico error de compilación de conflicto de versiones de la librería X de Android. Para ello podemos sacar provecho de Gradle para componer nuestros archivos build.gradle.
 En nuestro proyecto tenemos un fichero dependencies.gradle donde definimos primero las versiones de nuestras dependencias y después las dependencias en sí.


 


versions = [
"koin_version"              	: "3.1.4",
]

libs = [
    "koin"     	 : "io.insert-koin:koin-android:$versions.koin_version",
    "koinCore"   	 : "io.insert-koin:koin-core:$versions.koin_version",
    "koinJavaCompat" : "io.insert-koin:koin-android-compat:$versions.koin_version",
    "koinCompose"  : "io.insert-koin:koin-androidx-compose:$versions.koin_version",
]

Como podéis ver, al utilizar koin tenemos varias dependencias que comparten versión y si tuviéramos que actualizarla para solventar algún error de ella solo tenemos que venir aquí y no buscar en todos los ficheros Gradle que tenemos en cada módulo del proyecto.

Pero, si tenemos muchos módulos, tendremos muchos ficheros build.gradle y podemos sacar ventaja de la composición para ahorrarnos mucho código repetido. Si definimos un fichero con la configuración básica de todos los módulos de Android, lo único que tendremos que añadir en cada fichero es una línea de código y las dependencias particulares de ese.

Android_lib.gradle
apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'kotlin-kapt'
apply from: "$rootDir/buildsystem/dependencies.gradle"

android {
  compileSdkVersion configs.compileSdk

  defaultConfig {
	targetSdkVersion configs.targetSdk
	minSdkVersion configs.minSdk

	testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
	consumerProguardFiles "consumer-rules.pro"

  }

  buildTypes {

	debug {
  	debuggable = true
	}

	release {
  	minifyEnabled false
  	proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
	}
  }
  compileOptions {
	sourceCompatibility JavaVersion.VERSION_1_8
	targetCompatibility JavaVersion.VERSION_1_8
  }
  kotlinOptions {
	jvmTarget = '1.8'
  }
  sourceSets {
	main.java.srcDirs += 'src/main/kotlin'
	test.java.srcDirs += 'src/test/kotlin'
	androidTest.java.srcDirs += 'src/androidTest/kotlin'
  }
  buildFeatures {
	compose true
  }
  composeOptions {
	kotlinCompilerExtensionVersion '1.0.1'
  }
}



Con esta definición podemos componer nuestras dependencias en los nuevos módulos.

module.gradle


plugins {
  id 'com.android.library'
  id 'org.jetbrains.kotlin.android'
  id 'kotlin-kapt'
}

apply from: "$rootDir/buildsystem/android_lib.gradle"

android {
  buildFeatures {
	compose true
  }

  composeOptions {
	kotlinCompilerExtensionVersion '1.0.1'
  }
}

dependencies {

  implementation libs.core
  implementation libs.appcompat
  implementation libs.material

  //COMPOSE
  implementation libs.composeActivities
  implementation libs.composeMaterial
  implementation libs.composeConstraintLayout
  implementation libs.composeTooling
  implementation libs.composeRuntime
  implementation libs.composeViewModel

  //Room
  implementation libs.roomRuntime
  implementation libs.roomKtx
  kapt libs.roomCompiler

  //Koin
  implementation libs.koin
  implementation libs.koinJavaCompat
  implementation libs.koinCompose
  implementation libs.koinCore

  //TEST
  testImplementation testLibs.junit
  testImplementation testLibs.coroutinesTest
}

Incluso podemos beneficiarnos de gradle para componer aún más las dependencias y no tener que añadir o actualizar tantos ficheros cuando añadamos una nueva que compartan varios módulos.

  Introducción: Espresso UI Test

Usa el Readme como base de conocimiento

Dentro de nuestros repositorios el archivo Readme.md suele contener pasos para compilar el proyecto, es lo más habitual en proyectos cerrados. La documentación más elaborada suele estar en soluciones externas como Confluence, Notion, etc. Una opción interesante es tener en cada módulo un archivo Readme que contenga una pincelada de información básica. Esta información puede ser una descripción de la funcionalidad del módulo, sus dependencias de otros módulos (con su link relativo para facilitar la navegabilidad), dependencias externas relevantes, posibles mejoras a realizar, etc. Esto facilita la entrada de nuevos miembros al equipo, solo con darle acceso al repositorio pueden navegar por una documentación simple sin tener que navegar por el código que es mucho más confuso e intimidante. Una consideración es que Android studio, a fecha de publicación de este artículo, no tiene un buen soporte para ficheros MD. Una buena alternativa es Visual Studio Code, dónde puedes previsualizar como se vería tu fichero en el repositorio.

¿Tienes un proyecto de Android en mente?

Conclusión

En conclusión, la modularización de aplicaciones Android puede ser una tarea desalentadora, pero necesaria si quieres mejorar su rendimiento, escalabilidad y mantenimiento. Siguiendo los consejos descritos en este artículo, como identificar las características clave de la aplicación y dividirlas en módulos más pequeños, puedes hacer que el proceso sea más manejable. Además, utilizar la inyección de dependencias, desacoplar componentes y establecer límites claros entre módulos puede ayudar a garantizar que los módulos sean independientes y puedan desarrollarse, probarse y desplegarse por separado.

Con estos consejos en mente, puedes modularizar tu antigua aplicación Android y desbloquear toda una serie de beneficios, incluyendo ciclos de desarrollo más rápidos, un mantenimiento más sencillo y un rendimiento mejorado. Así que no tengas miedo de enfrentarte al reto de la modularización y transformar tu aplicación en un producto más eficiente y escalable.

Si te interesa leer más artículos sobre temas técnicos, te sugiero que eches un vistazo al blog de Apiumhub. Cada semana se publica contenido nuevo e interesante no solo sobre modularización de aplicaciones Android, sino también sobre arquitectura de software, desarrollo de software móvil, control de calidad y automatización, y desarrollo de aplicaciones iOS.

 

Author

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Suscríbete a nuestro boletín de noticias

Recibe actualizaciones de los últimos descubrimientos tecnológicos

¿Tienes un proyecto desafiante?

Podemos trabajar juntos

apiumhub software development projects barcelona
Secured By miniOrange