Cómo aceleramos la puesta en marcha de la aplicación de Dropbox para Android en un 30%.

El inicio de la aplicación es lo primero que experimentan nuestros usuarios después de instalar una aplicación y, además, cada vez que la inician.

Una aplicación sencilla y ágil proporciona a los usuarios mucha más alegría que una aplicación con un montón de funciones pero que tarda una eternidad en cargarse. Consciente de ello, el equipo de Android de Dropbox ha invertido en medir, identificar y solucionar los problemas que afectaban al tiempo de inicio de nuestra aplicación.

Acabamos mejorando el tiempo de inicio de nuestra aplicación en un 30%, y esta es la historia de cómo lo hicimos.

Históricamente, en Dropbox hemos hecho un seguimiento del inicio de la aplicación midiendo el tiempo que transcurría desde que un usuario tocaba el icono de nuestra aplicación hasta que ésta se cargaba por completo y estaba lista para las interacciones del usuario.

Abstrajimos la medición de la inicialización de la aplicación de la siguiente manera:

Copiar:
perfMonitor.startScenario(AppColdLaunchScenario.INSTANCE)

// realiza el trabajo necesario para el lanzamiento de la aplicación

perfMonitor.stopScenario(AppColdLaunchScenario.INSTANCE)

Al ser un equipo orientado a los datos, hemos estado siguiendo y monitorizando la inicialización de la aplicación con la ayuda de gráficos accesibles para todos los ingenieros.

Android

El siguiente gráfico muestra las mediciones del p90 de inicio de la aplicación desde finales de marzo hasta principios de abril de 2021.

Como puedes ver en el gráfico, el tiempo de inicio de la aplicación no parece estar cambiando mucho. Las pequeñas fluctuaciones en el inicio de la aplicación que oscilan un par de milisegundos son esperables en una aplicación utilizada por millones de usuarios con variedad de dispositivos y versiones de SO.

Sin embargo, cuando observamos el tiempo de inicio de la aplicación desde diciembre de 2019 hasta abril de 2020, vimos una imagen diferente.

El tiempo de inicio de la aplicación ha ido aumentando durante meses a medida que la aplicación evolucionaba y se añadían más funciones. Sin embargo, como nuestros gráficos solo mostraban los cambios en un periodo de dos semanas, no vimos el lento aumento del tiempo de inicio de la aplicación que se produjo durante varios meses.

Aunque el descubrimiento del lento aumento del tiempo de arranque fue accidental, nos hizo profundizar en las razones, así como asegurarnos de que nuestras herramientas de monitorización, alerta y gráficos tuvieran una visión más amplia y cohesionada de nuestras métricas.

Android

Dame más números

Algunas características de la aplicación pueden ser relativamente sencillas de medir, como el tiempo que tarda una llamada a la API del servidor. Mientras que otras características, como el inicio de la aplicación, son mucho más complicadas de medir.

Quizás también te interese  La actualización estable One UI 3.0 de Samsung Galaxy Note 10 con Android 11 comienza a desplegarse

El inicio de la aplicación requiere muchos pasos diferentes en el dispositivo antes de que la pantalla principal de la aplicación se muestre al usuario y la aplicación esté lista para la interacción del usuario. Examinando nuestro código de inicialización, hemos identificado los principales eventos que ocurren durante la inicialización de nuestra aplicación. Aquí están algunos de ellos:

Ejecutar migraciones

-Cargar los servicios de la aplicación
-Cargar los usuarios iniciales

Comenzamos nuestra investigación aprovechando las herramientas de perfilado de Android Studio para medir el rendimiento en nuestros teléfonos de prueba.

Android

El problema de perfilar el rendimiento con este enfoque era que nuestros teléfonos de prueba no nos darían una muestra estadísticamente significativa de lo bien que funciona realmente el inicio de la aplicación.

La aplicación Android de Dropbox tiene más de mil millones de instalaciones en Google Play Store, abarcando múltiples tipos de dispositivos, algunos de ellos viejos Nexus 5s, y otros los más nuevos y mejores dispositivos de Google.

Sería una tontería intentar perfilar tantas configuraciones. Así que decidimos medir los diferentes pasos del inicio de la aplicación utilizando escenarios y pasos de escenarios en producción.

Aquí está el código de inicialización actualizado donde añadimos el registro para los tres pasos mencionados:

Copiar
perfMonitor.startScenario(AppColdLaunchScenario.INSTANCE)
perfMonitor.startRecordStep(RunMigrationsStep.INSTANCE)

// realizar el paso de migraciones wrok

perfMonitor.startRecordStep(LoadAppServicesStep.INSTANCE)

// cargar los servicios de la aplicación paso

perfMonitor.startRecordStep(LoadInitialUsers.INSTANCE)

// realizar el paso de carga de usuarios iniciales

perfMonitor.stopScenario(AppColdLaunchScenario.INSTANCE)

Con las mediciones instrumentadas en el código, pudimos comprender qué pasos de la inicialización de la aplicación estaban contribuyendo más al aumento del inicio de la misma.

Infracciones de rendimiento que encontramos

El siguiente gráfico muestra el tiempo total de inicio de la aplicación desde enero hasta octubre de 2021.

En mayo, introdujimos mediciones para cada uno de los principales pasos que ocurren durante la inicialización de la aplicación. Estas mediciones nos permitieron identificar y abordar los mayores infractores del rendimiento del inicio de la app.

Los principales infractores del inicio de la aplicación incluyen la inicialización de la biblioteca Firebase Performance, la migración de la bandera de características y la carga inicial del usuario.

Biblioteca Firebase Performance

La biblioteca Firebase Performance se incluye en el conjunto de productos Firebase de Google para medir y enviar métricas sobre el rendimiento de las aplicaciones.

Proporciona funcionalidades útiles como métricas para el rendimiento de métodos individuales, así como infraestructura para monitorizar y visualizar el rendimiento de diferentes partes de la app.

Quizás también te interese  ¿Por qué los teléfonos Android intercambian misteriosamente 260 MB al mes con Google a través de los datos móviles cuando ni siquiera están en uso?

Desafortunadamente, la biblioteca Firebase Performance también viene con algunos costes ocultos. Entre ellos se encuentra un costoso proceso de inicialización y, como resultado, un aumento significativo de los tiempos de compilación.

En nuestra depuración, descubrimos que la inicialización de la suite Firebase era siete veces más larga cuando la herramienta Firebase Performance estaba activada. Para solucionar el problema de rendimiento, optamos por eliminar la herramienta Firebase Performance de la aplicación Android Dropbox.

La librería Firebase Performance es una herramienta maravillosa que permite perfilar detalles de rendimiento de muy bajo nivel, como las llamadas a funciones individuales, pero como no hemos estado utilizando estas características, decidimos que el inicio rápido de la aplicación tenía más peso que los datos de rendimiento de los métodos individuales, y por eso eliminamos la referencia a esa librería.

Migraciones

Hay varias migraciones internas que se ejecutan cada vez que se inicia la aplicación de Dropbox. Estas pueden incluir la actualización de los indicadores de características, las migraciones de la base de datos, etc.

Desafortunadamente, encontramos que algunas de estas migraciones se ejecutaban en cada lanzamiento de la aplicación. No nos dimos cuenta del mal rendimiento de estas migraciones anteriormente, porque la aplicación se lanzaba rápidamente en los dispositivos de desarrollo y de prueba.

Por desgracia, este código de migración funcionaba especialmente mal en versiones antiguas del sistema operativo y en dispositivos más antiguos, lo que contribuía a aumentar el tiempo de inicio. Para resolver el problema, empezamos por investigar qué migraciones eran esenciales en cada lanzamiento y qué migraciones podían eliminarse por completo de la aplicación.

Encontramos y eliminamos al menos una migración que era muy antigua y, por tanto, ya no era necesaria, lo que ayudó a recuperar el tiempo de inicio de nuestra aplicación.

Carga de usuarios

En la parte heredada de nuestra aplicación, almacenamos los metadatos de los contactos de usuario de Dropbox en el dispositivo como blobs JSON.

En un mundo ideal, esos blobs JSON deberían ser leídos y convertidos en objetos Java sólo una vez. Desgraciadamente, el código para extraer usuarios era llamado varias veces desde diferentes características heredadas de la aplicación, y cada vez, el código realizaba un costoso análisis de JSON para convertir los blobs JSON del usuario en objetos Java.

El almacenamiento de los contactos de los usuarios como JSON era un diseño muy anticuado y formaba parte de nuestro código heredado monolítico.

Para conseguir una solución inmediata a este problema, añadimos la funcionalidad de almacenar en caché los objetos de usuario analizados durante la inicialización. A medida que continuamos trabajando en el desmantelamiento del código heredado del monolito, una solución más eficiente y moderna para el almacenamiento de los contactos de los usuarios sería utilizar los objetos de la base de datos Room y convertir esos objetos en entidades de negocio.

Quizás también te interese  Un nuevo malware para Android que se propaga a través de WhatsApp

Como resultado de la eliminación de la referencia a Firebase Performance, la eliminación de los costosos pasos de migración y el almacenamiento en caché de la carga del usuario, hemos mejorado el rendimiento de lanzamiento de la aplicación de Dropbox para Android en un 30%. A través de este trabajo, también hemos elaborado cuadros de mando que ayudarán a prevenir la degradación del tiempo de inicio de la app en el futuro.

También adoptamos varias prácticas que, con suerte, evitarán que cometamos los mismos errores de rendimiento. He aquí un par de ellas:

Medir el impacto en el rendimiento del inicio de la aplicación al añadir bibliotecas de terceros

Con el descubrimiento de lo mucho que la biblioteca Firebase Performance degradaba el inicio de nuestra aplicación, introdujimos un proceso para añadir bibliotecas de terceros.

Hoy en día, requerimos medir el tiempo de inicio de la aplicación, el tiempo de compilación y el tamaño del APK de la aplicación antes de que la biblioteca pueda ser añadida y utilizada en nuestra base de código.

Caché de todas las cosas

Dado que dos de los principales problemas de rendimiento en el inicio de la aplicación tienen que ver con el almacenamiento en caché, preferimos almacenar en caché los cálculos costosos, aunque esto complique un poco el código. Después de todo, una mejor experiencia de usuario merece un poco más de mantenimiento.

Con más inversiones en análisis creíbles y mediciones de rendimiento, nos hemos convertido en un equipo mucho más orientado a los datos, lo que nos permite realizar mayores inversiones en nuestra base de código, como la eliminación del código C++ heredado, con mucha más confianza.

En la actualidad, supervisamos varios paneles que nos proporcionan información sobre el rendimiento de las partes más importantes de nuestras aplicaciones, y contamos con procesos para garantizar que las aplicaciones de Dropbox sigan siendo ágiles y un placer para nuestros usuarios.

Android

Ir al contenido