Cómo Duolingo adoptó MVVM en Android


Publicado por Kateryna Semenova, ingeniera de relaciones con desarrolladores de Android

Ilustración de la mano que sostiene un gráfico con el pájaro Duolingo posado en él

Síntesis

La aplicación de Duolingo comenzó a experimentar problemas de crecimiento debido a problemas de escalabilidad en su arquitectura de software de Android. Pudieron abordar estos problemas de rendimiento y recuperar la productividad de los desarrolladores mediante la refactorización a una arquitectura Modelo-Vista-VistaModelo y utilizando Dagger y Hilt de Android Jetpack para la inyección de dependencias. Para obtener más información sobre cómo esto ha afectado a su negocio, lea el artículo adjunto. aquí.

Introducción

Duolingo es la aplicación de aprendizaje de idiomas más popular del mundo, con más de diez millones de estudiantes al día, porque han logrado hacer que algo que la gente encuentra abrumador parezca fácil y divertido. Este éxito continuo se basa en un flujo constante de innovaciones y actualizaciones y una aplicación fluida que puede ofrecerlas todas. Para Duolingo, una sola aplicación que no responde en un dispositivo en cualquier parte del mundo podría significar un estudiante potencialmente desanimado. Esto los compromete con la excelencia de las aplicaciones, particularmente en los dispositivos Android utilizados por el sesenta por ciento de sus estudiantes, incluido su director ejecutivo, que rastrea la aplicación desde un teléfono básico. Y así, cuando el equipo de desarrollo de Android de Duolingo vio un aumento en los errores de “La aplicación no responde”, descartó marcos e incluso recibió una queja escrita a mano, tomaron medidas de inmediato.

Su situación no era tan rara. Las aplicaciones que carecen de una arquitectura escalable y prácticas recomendadas claras a menudo funcionan bien al principio, pero muestran signos de endeudamiento técnico a medida que crecen. El código base de Android de Duolingo fue diseñado para permitirles agregar y lanzar nuevas funciones rápidamente, pero la falta de una arquitectura acordada resultó en regresiones de rendimiento cada vez más frecuentes. Estaba empezando a sufrir de velocidades de fotogramas poco fiables, interacciones visualmente inconsistentes o rotas, y una variedad creciente de nuevos errores. Estas regresiones no solo molestaron a los estudiantes, sino que también le costaron al equipo un esfuerzo de desarrollo significativo para diagnosticar y reparar. El equipo de desarrollo de Android de Duolingo se dio cuenta de que si querían seguir proporcionando nuevas funciones mientras proporcionaban el nivel objetivo de experiencia del usuario, se necesitaba un nuevo enfoque para su base de código.

Descubrimiento

Primero, tenían que llegar al fondo de lo que estaba pasando exactamente. Un análisis en profundidad de los números encontró que a medida que se agregan nuevas funciones, el rendimiento de renderizado de la aplicación retrocede entre un 5% y un 10% cada mes. De hecho, una versión particularmente engorrosa aumentó los bloqueos en un 10%, ralentizó el procesamiento de cuadros en un 25% y las lecciones comenzaron un 70% más lento en los dispositivos de nivel de entrada.

Un análisis más detallado de su código los llevó a la conclusión de que la mayoría de los problemas de la aplicación se remontan a un solo cuello de botella: un objeto de estado global llamado DuoState, que era responsable de mantener el estado entre las diferentes funciones de la aplicación. Varias funciones populares (como puntos de experiencia Y seguimiento de la serie diaria) lo utilizó para acceder a información vital. Centralizar los datos de esta manera había permitido al equipo iterar rápidamente. Simplemente agregaron propiedades a DuoState cada vez que se necesitaba una nueva función para compartir información a través de la aplicación. Pero ahora el acceso frecuente y no optimizado al objeto estaba provocando regresiones de rendimiento cada vez mayores.

DuoState estaba tan estrechamente vinculado a toda la base del código que incluso pequeños cambios podrían afectar al resto de la aplicación. El equipo temía que una nueva característica menor pudiera tener el efecto secundario inesperado de activar muchas actualizaciones internas de la aplicación, haciendo que la versión completa sea demasiado lenta para muchos dispositivos. Estas regresiones de rendimiento se hicieron más frecuentes a medida que la aplicación crecía y el equipo contrataba nuevos ingenieros para mantenerse al día con la hoja de ruta del producto cada vez más acelerada. En 2020, a medida que agregaron más desarrolladores, comenzaron a ver regresiones significativas cada 90 días. En una inspección más cercana, la probabilidad de una regresión en una versión dada era proporcional al número de cambios implementados. A este ritmo, estas regresiones descarrilarían por completo la hoja de ruta del producto en unos pocos años.

Esta arquitectura obsoleta se había convertido en un cuello de botella para el rendimiento de las aplicaciones Y velocidad del equipo Después de un largo debate interno, dejaron de desarrollar nuevas funciones, incluidas algunas estrechamente relacionadas con sus resultados. Durante dos meses completos, el equipo de desarrollo de Duolingo hizo todo lo posible por refactorizar su aplicación de Android en un esfuerzo que llamaron “Android Reboot”.

Reiniciar Android

Uno de los primeros puntos clave del equipo fue que su código no tenía límites claros. El objeto DuoState estaba disponible en cualquier parte del código, lo que llevó a los desarrolladores a acceder a él con frecuencia de manera ineficiente. Necesitaban crear una mayor separación de preocupaciones dentro del código base. Decidieron separar cada característica en su propio módulo claramente definido, utilizando el Modelo-Vista-VistaModelo modelo arquitectónico. MVVM les permitió eliminar llamadas al objeto monolítico DuoState, lo que permitió que muchos módulos funcionaran en subprocesos separados.

Diagrama que muestra antes y después de la implementación del modelo arquitectónico Model-View-ViewModel

La familiaridad del equipo con MVVM y el soporte de Google lo convirtió en una elección obvia. Les permitió documentar claramente qué lógica se debe colocar en qué archivos (incluidas vistas, plantillas de vista y repositorios). Esto ayudó a que su arquitectura de funciones fuera más consistente. Con un camino claro a seguir, el equipo rápidamente comenzó a reorganizar su código monolítico en grupos de clases con límites y responsabilidades claros.

Junto con MVVM, el equipo usó Dagger and Hilt (también incluido en Jetpack de Android) para implementar plantillas de repositorio para reemplazar DuoState. Dagger genera un código claro y legible que proporciona un registro detallado de errores diseñado para ayudar a los desarrolladores a comprender exactamente lo que hace su código al eliminar los rastros de pila inactivos en las propiedades reflejadas; y Hilt reduce la cantidad de código estándar necesario para escribirlo.

Esta nueva arquitectura permitió al equipo dividir DuoState en objetos más pequeños. Esto redujo inmediatamente el emparejamiento innecesario entre dominios. Por ejemplo, el código responsable del seguimiento del progreso de un usuario ahora podría acceder a sus puntos de experiencia, pero no a la cantidad de veces que inició sesión durante un mes. Estas nuevas pautas de arquitectura significaron que, si bien ninguna cosa era demasiado difícil de cambiar, se necesitaba coordinación y planificación para cambiarla en toda la aplicación. La implementación de la nueva arquitectura en toda la base de código resultó en importantes mejoras de rendimiento general.

La arquitectura MVVM facilita una separación de preocupaciones entre los datos del dominio, la interfaz que ven los estudiantes y la lógica de cómo interactúan estos dos dominios. Le dio a los desarrolladores de Duolingo una forma más deliberada de controlar cómo responde la aplicación a las actualizaciones de estado internas. Ahora podrían desarrollar experiencias de usuario más complejas sin el riesgo de desencadenar regresiones o afectar las reglas comerciales subyacentes.

Productividad del desarrollador

En el pasado, la aplicación inconsistente de modelos de desarrollo hacía que diferentes partes del código base fueran más difíciles de entender y mantener. Sin consentimiento, cada desarrollador implementó el código como mejor le pareció.

MVVM, Dagger y Hilt proporcionaron al equipo una comprensión más detallada de cómo se deben implementar las nuevas funciones. Seguir estas mejores prácticas hizo que el código fuera más simple y predecible. Los desarrolladores ahora pueden ayudar a depurar funciones en las que no trabajaron originalmente. Y los nuevos desarrolladores podrían integrarse de manera más eficiente; siempre que entendieran la arquitectura, podrían hacer una contribución significativa de inmediato. Esta nueva claridad ha aumentado enormemente la velocidad de desarrollo del equipo.

Garantizar la calidad

Básicamente, la nueva arquitectura también reveló que algunas funciones de animación en la aplicación eran dispositivos de nivel de entrada de bajo rendimiento. Como resultado, el otro enfoque principal de reiniciar Android fue reducir los errores de “jank, drop frame” y “App Not Responding” (ANR). El equipo usó plantillas de repositorio para facilitar el intercambio de datos entre subprocesos. Estos modelos aseguraron que pudiera utilizar de manera más eficiente los recursos del dispositivo con múltiples módulos con subprocesos. Alejar el trabajo del hilo principal ha mejorado la capacidad de respuesta, la velocidad de fotogramas general y ha dado lugar a animaciones más fluidas en los dispositivos de nivel de entrada. El rendimiento en los dispositivos insignia también ha mejorado.

Una mejor experiencia general de Android

En los seis meses de trabajo con la nueva arquitectura, el equipo de Android de Duolingo continuó brindando nuevas funciones sin experimentar regresiones significativas en el rendimiento. Los días en que tuvieron que detener la producción de funciones para buscar y corregir errores quedaron atrás.

La tasa de ANR diaria de la aplicación cayó un 41%. El porcentaje de tiempo que la velocidad de fotogramas de la aplicación cayó por debajo del objetivo disminuyó en un 28%. Lo mejor de todo es que los usuarios han experimentado un aumento del 40% en la velocidad al desplazarse por las lecciones, la tabla de clasificación y las historias en la aplicación.

El reinicio ha permitido a Duolingo ofrecer constantemente su experiencia de aprendizaje de idiomas divertida, efectiva y agradable en una gama mucho más amplia de dispositivos Android.

Conclusión

La dedicación de Duolingo a su misión la ha convertido en la mejor aplicación de aprendizaje de idiomas del mundo en el espacio. Su compromiso con la excelencia de las aplicaciones, creando experiencias educativas de vanguardia sin comprometer la accesibilidad, es lo que los mantuvo allí.

Si está interesado en involucrar a su equipo para el reinicio de Android, consulte nuestro estudio de caso condensado para propietarios y ejecutivos de productos conectados aquí.

Compruebe también

en vivo desde Droidcon, incluida la mayor actualización de Gemini en Android Studio y más lanzamientos del SDK de Android.

Acabamos de lanzar nuestro episodio de otoño de #TheAndroidShow en YouTube etcétera desarrollador.android.comy esta vez …

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *