Video Summary and Transcription
La charla de hoy presenta Reacher, una herramienta de monitoreo de rendimiento para bases de código de React y React Native. Destaca la necesidad de detectar regresiones de rendimiento temprano en el proceso de desarrollo e identifica el mal uso de JavaScript como una fuente común de problemas de rendimiento. ReaSure, desarrollado por Covstack, se presenta como una biblioteca prometedora que se integra con los ecosistemas existentes y proporciona mediciones confiables de tiempo de renderizado y conocimientos útiles para la revisión de código. Se discuten consideraciones para operar en un VM de JavaScript, incluyendo JIT, recolección de basura y caché de resolución de módulos. Se menciona el análisis estadístico utilizando el z-score como un método para determinar la importancia de los resultados de las mediciones.
1. Introduction to Performance Monitoring
Hoy voy a hablar sobre el monitoreo del rendimiento en los codebases de React y React Native con Reacher. La entropía es el aumento del desorden, que distingue el pasado del futuro. Como desarrolladores, luchamos contra la entropía siguiendo un ciclo de desarrollo y solucionando errores. Sin embargo, incluso con un flujo de trabajo bien diseñado, pueden aparecer críticas negativas.
Hola, hoy voy a hablar sobre el monitoreo del rendimiento y cómo hacerlo en tus codebases de React y React Native con Reacher. Me llamo Michał Pieszchala, soy el Jefe de Tecnología en Callstack, responsable de nuestra investigación y desarrollo y esfuerzos de código abierto. También soy un colaborador principal en una serie de bibliotecas, actualmente manteniendo el React Native CLI y la biblioteca de pruebas de React Native.
Comencemos con algo de inspiración, ¿de acuerdo? ¿Alguien ha oído hablar de la entropía? No realmente esta. La entropía del mundo real, descrita por la física de esta manera. O cómo lo enmarcó Stephen Hawking. Puedes ver una taza de té caerse de una mesa y romperse en pedazos en el suelo, pero nunca verás que la taza se reúna y salte de nuevo a la mesa. El aumento del desorden, o esta entropía, es lo que distingue el pasado del futuro, dándole una dirección al tiempo. O en otras palabras, las cosas eventualmente se desmoronarán si no se les presta atención.
Pero no nos pongamos demasiado deprimidos o cómodos con las cosas que se convierten en caos, porque podemos y debemos luchar contra ello. Podemos hacer esfuerzos para crear tipos útiles de energía y orden, lo suficientemente resistentes como para resistir la implacable atracción de la entropía al gastar esta energía. Cuando desarrollamos software, sentimos que la entropía es algo real. Es por eso que generalmente hacemos un esfuerzo adicional y seguimos algún tipo de ciclo de desarrollo. Por ejemplo, comenzamos agregando una nueva función. Durante el desarrollo, la acompañamos con una serie de pruebas. Cuando terminamos, la enviamos a QA. QA la mejora y promueve nuestro código para su lanzamiento en el canal de producción. Y volvemos a agregar otra función. Pero eso es una versión bastante simplificada de lo que generalmente hacemos. Complicémoslo un poco. Entre otras cosas, no tenemos en cuenta que los errores pueden aparecer repentinamente. Ahora nuestro círculo se convierte en un grafo, pero está bien porque sabemos qué hacer. Necesitamos identificar la causa raíz, agregar una prueba de regresión para que nunca vuelva a romperse, enviarla a QA una vez más, enviarla y volver a agregar nuevas funciones.
Entonces estamos contentos con nuestro flujo de trabajo. Funciona bastante bien. Agregamos función tras función, nuestra versión de la aplicación está tan bien diseñada que incluso agregar 10 nuevos desarrolladores no nos ralentiza. Y luego echamos un vistazo a las reseñas de nuestra aplicación para ver qué piensan las personas. Y aparece una reseña salvaje de una estrella. Y luego llega otra más.
2. Challenges with Performance Monitoring
Nuestro flujo de trabajo perfecto no es resistente a las regresiones de rendimiento. Necesitamos una forma de detectarlas antes de que afecten a nuestros usuarios. Tratar los problemas de rendimiento como errores nos permite detectar las regresiones temprano en el proceso de desarrollo. Para encontrar la mejor herramienta para las pruebas de rendimiento, debemos considerar el impacto y enfocarnos en las regresiones más probables. La mayoría de los problemas de rendimiento se originan en el lado de JavaScript, particularmente por un mal uso de React. Estimamos que alrededor del 80% del tiempo dedicado a solucionar problemas de rendimiento se encuentra en el ámbito de JavaScript. Encontramos una prometedora biblioteca de pruebas de rendimiento para React que vale la pena explorar.
Y simplemente... siguen llegando. Y empezamos a darnos cuenta de que nuestro flujo de trabajo perfecto basado en la ciencia, nuestras experiencias y las mejores prácticas, que se suponía que evitaría que nuestra aplicación se desmoronara, no es resistente a un tipo particular de errores. Regresiones de rendimiento. Nuestro código no tiene las herramientas para combatir esto. Sabemos cómo solucionar los problemas una vez que los detectamos, pero no tenemos forma de detectarlos antes de que afecten a nuestros usuarios.
Entonces, ¿cómo era de nuevo? O... El rendimiento se desmoronará eventualmente cuando no se haya previsto. Así que si no hago nada para optimizar mi aplicación mientras agrego nuevo código y dejo que el tiempo pase, se volverá más lenta. Y no sabemos cuándo sucederá. Tal vez mañana, tal vez en una semana, o en un año. Y si solo hubiera una forma establecida de detectar al menos algunas de las regresiones temprano en el proceso de desarrollo, antes de que nuestros usuarios se den cuenta. ¡Espera un minuto, la hay! Si comenzamos a tratar los problemas de rendimiento como errores, ni siquiera necesitamos interrumpir nuestro flujo de trabajo de desarrollo. Las pruebas de regresión se ejecutan en un entorno remoto, en cada cambio de código, así que solo necesitamos encontrar una forma de incluir las pruebas de rendimiento allí, ¿verdad?
Pero antes de salir a buscar la mejor herramienta, demos un paso atrás y pensemos en el impacto y en lo que vale la pena probar. Al igual que con cualquier cobertura de pruebas, hay una proporción saludable a la que aspiramos, para proporcionarnos el mejor valor con el menor esfuerzo. Queremos asegurarnos de enfocarnos en las regresiones que es más probable que afecten a nuestros usuarios. Y al parecer, estamos desarrollando una aplicación reactivada. Por cierto, ¿sabías que hay una fuente llamada Impact? Y probablemente la hayas visto en memes. De todos modos, echemos un vistazo a los problemas típicos de rendimiento con los que los desarrolladores se enfrentan a diario. Listas e imágenes lentas, SVG, mal uso del contexto de React, re-renderizaciones, TCI lento, solo por mencionar algunos. Si observamos esta lista desde el punto de vista del origen del problema, notaremos que la gran mayoría de ellos provienen del lado de JavaScript. Ahora, veamos la frecuencia relativa. Y lo que emerge es bastante revelador. Estimamos que la mayor parte del tiempo que nuestros desarrolladores dedican a solucionar problemas de rendimiento, alrededor del 80%, proviene del ámbito de JavaScript, especialmente por un mal uso de React. Solo el resto es la sobrecarga de comunicación entre puentes y el código nativo, como la renderización de imágenes o las operaciones de la base de datos que funcionan de manera ineficiente. Pero no soy partidario de reinventar la rueda, así que he buscado en Google una biblioteca de pruebas de rendimiento para React, y encontré esto. Este paquete. Parece prometedor. Veamos qué hay dentro. No es muy popular, pero está bien. La última versión se lanzó hace 9 meses.
3. Introduction to ReaSure
Necesitamos una nueva biblioteca que se integre con nuestro ecosistema existente, mida los tiempos de renderizado de manera confiable, proporcione un ejecutor de CI, genere informes legibles y analizables, y ofrezca información útil para la revisión de código. Les presento ReaSure, un compañero de pruebas de regresión de rendimiento para aplicaciones de React y React Native. Desarrollado por Covstack en colaboración con Intane, ReaSure mejora el proceso de revisión de código al integrarse con GitHub. Ejecuta Jest a través de código Node con parches especiales para aumentar la estabilidad y utiliza el perfilador de React para manejar las mediciones de manera confiable. ReaSure compara los resultados de las pruebas entre ramas y proporciona un resumen de los resultados categorizados estadísticamente. Abrazar la estabilidad y evitar la inestabilidad es clave para los puntos de referencia cognitivos, especialmente en Node.js.
Está bien. ¿Qué más? Parchea React. Eso no está bien. También utiliza internamente React. Eso es decepcionante. No se ajusta a nuestro caso de uso y no parece una base sólida para construir.
Pero, ¿qué necesitamos realmente de una biblioteca como esta? Idealmente, debería integrarse con el ecosistema existente de bibliotecas que estamos utilizando. Debería medir los tiempos de renderizado y contar de manera confiable, tener un ejecutor de CI, generar informes legibles y analizables, proporcionar información útil para la revisión de código y, según nuestra biblioteca de Google, tener un diseño estable. Y dado que no hay nada como esto disponible, necesitamos una nueva biblioteca.
Y me gustaría presentarles ReaSure, un compañero de pruebas de regresión de rendimiento para aplicaciones de React y React Native. Se desarrolla en Covstack en colaboración con Intane, uno de los grupos de apuestas y juegos más grandes del mundo. ReaSure se basa en su configuración existente y la complementa con una API de medición de rendimiento discreta. Está diseñado para ejecutarse en un entorno de servidor remoto como parte de su integración continua. Para aumentar la estabilidad de los resultados y reducir la inestabilidad, ReaSure ejecutará sus pruebas una vez para la rama actual y otra vez para la rama base. Una experiencia de desarrollo agradable es fundamental en nuestro diseño de ingeniería. Es por eso que ReaSure se integra con GitHub para mejorar el proceso de revisión de código. Actualmente, aprovechamos Danger.js como nuestro backend de bot, pero en el futuro nos gustaría preparar una acción de GitHub plug-and-play.
Ahora, veamos qué hace. ReaSure ejecuta Jest a través de código Node con parches especiales para aumentar la estabilidad. La función measureRender que proporcionamos utiliza el perfilador de React para manejar las mediciones de manera confiable, lo que nos permite evitar el parcheo de React. Después de completar la primera ejecución, cambiamos a la rama base y ejecutamos las pruebas nuevamente. Una vez que se completan ambas ejecuciones de pruebas, la herramienta compara los resultados y presenta el resumen, mostrando resultados categorizados estadísticamente en los que se puede actuar. Volvamos a nuestro ejemplo. Observa cómo creamos un nuevo archivo con la extensión .perf-test-.dsx, que reutiliza nuestra prueba de componente regular de la biblioteca React en una función de escenario. Luego, el método measurePerformance de ReaSure utiliza el escenario para renderizar nuestro componente contador, en este caso, 20 veces. Bajo el capó, el perfilador de React mide los tiempos de renderizado y la cantidad de veces que se renderiza, que luego escribimos en el sistema de archivos. Y eso es generalmente todo lo que tienes que escribir. Copia y pega tus pruebas existentes, ajústalas y disfruta. Los puntos de referencia cognitivos no son pan comido, incluso en entornos que no son de JS. Pero es particularmente complicado con Node.js. La clave es abrazar la estabilidad y evitar la inestabilidad.
4. Consideraciones para JavaScript VM
Al operar en un JavaScript VM, debemos tener en cuenta el JIT, la recolección de basura y el almacenamiento en caché de resolución de módulos. El análisis estadístico requiere ejecutar las mediciones varias veces. El z-score se utiliza para determinar la significancia estadística de los resultados.
Al operar en un JavaScript VM, debemos tener en cuenta el JIT, la recolección de basura y el almacenamiento en caché de resolución de módulos. Tenemos un costo de concurrencia que nuestro ejecutor de pruebas asume para una ejecución rápida. Necesitamos decidir qué promediar y qué percentil tomar. Y mucho más. Por ejemplo, para realizar un análisis estadístico. Para asegurarnos de que nuestros resultados de medición tengan sentido matemáticamente, no es suficiente ejecutarlos una o dos veces. Teniendo en cuenta otras cosas, hemos determinado que diez veces es una buena referencia. Luego, para determinar la probabilidad de que el resultado sea estadísticamente significativo, necesitamos calcular el z-score, que requiere el valor medio o la divergencia promedio y la desviación estándar. Esto me trae recuerdos de la universidad, así que no voy a profundizar aquí. Ahora, el almacenamiento en caché de resolución de módulos es algo que es genial para las aplicaciones de Node.js, pero nos causó problemas al desarrollar la biblioteca. Resultó que la ejecución posterior del mismo componente a menudo resultaba en ejecuciones incluso diez veces más lentas. Como puedes imaginar, promediar eso haría que los resultados no fueran confiables. Por lo tanto, descartamos la prueba más lenta, ya que probablemente está limitada por la falta de caché. Con todos esos datos, podemos presentar los tiempos de duración de renderizado como estadísticamente significativos o sin sentido. Además de los tiempos de renderizado, otra métrica útil que puede degradarse fácilmente son los recuentos de renderizado, que obtenemos de forma gratuita del Profiler de React. Toda esta información se almacena en formato JSON para su análisis posterior y en Markdown para su legibilidad. Utilizamos la salida de Markdown como fuente para el bot de comentarios de GitHub, impulsado por Danger.js. Esta es, con mucho, nuestra forma favorita y recomendada de usar ReaSure, ya que enriquece el proceso de revisión de código y nos permite mitigar la inestabilidad de la CI que estamos utilizando. Permíteme compartir lo que hemos aprendido hasta ahora al usar esta biblioteca. Debes cubrir los escenarios de usuario más importantes. Incluso si no tienes problemas de rendimiento ahora, los detectarás si aparecen. Prueba pantallas completas o incluso secuencias de pantallas. Las pruebas a nivel de componente son posibles, pero a menudo requieren más ejecuciones de pruebas. Puedes reutilizar tus pruebas de bibliotecas de React Native y Testing si las tienes, y se aplican todas las prácticas establecidas de la biblioteca de pruebas. Haz que tus pruebas se parezcan al comportamiento del usuario y evita simular cualquier cosa que no sea IOH. Debido a sus características, parece que las pruebas de rendimiento frontend se asemejan a las pruebas de extremo a extremo para nuestras aplicaciones. Tiene sentido tratarlas como tal en lugar de en nuestras Trophies o Pirámides de Testing. Recuerda que el rendimiento no es un objetivo, es un camino. Recórrelo con confianza. Hacia EARNED, ReaSure no existiría si no fuera por mis colegas Maciej Jastrzębski, quien es el cerebro detrás de la biblioteca, y un increíble equipo de desarrollo formado por Tomasz y Jakub. Asegúrate de seguir su trabajo. ReaSure es de código abierto. El código QR te redirigirá al repositorio. Dale una estrella si te gusta y avísame si tienes algún problema al adoptarlo. Estaré encantado de ayudarte. Y eso es todo, amigos. Puedes encontrarme en Twitter o GitHub con este nombre de usuario. Que tengas una gran conferencia y gracias.
Comments