Cuando tus dependencias rompen tu software, ¿no te gustaría que lo arreglaran?

Nosotros en la Fábrica Digital Global de Allianz (GDF) usamos las herramientas de Angular para mantener nuestro ecosistema en sincronía. Nuestro principal activo es nuestra biblioteca de componentes de interfaz de usuario (UI), que permite a los equipos de Allianz utilizar componentes de UI ya preparados para construir sus aplicaciones. Las principales técnicas que utilizamos son Schematics y ng update . Esto es algo que ya está bien establecido cuando se utiliza el propio Angular (por ejemplo, la historia de KLM). Aquí queremos compartir nuestro viaje de utilización de tal pila de herramientas para nuestro ecosistema de Allianz.

Enfoques para las principales actualizaciones de la biblioteca
Imagina que los cables de energía de tu baño necesitan ser recableados. Un artesano entra, quita los azulejos, arregla el cableado, sella la pared, pero luego se va con los azulejos que están en el suelo del baño. No mola, ¿verdad? Esto es más o menos lo que sucede cuando las bibliotecas de software envían cambios de ruptura. Se encargan de mejorar el cableado interno, pero tú (los desarrolladores de la aplicación) te quedas limpiando las partes pegadas en la parte superior.
Para el equipo que envía una biblioteca, esto funciona de alguna manera, ya que no sienten la carga de trabajo total de la limpieza después del cambio de ruptura. Para los equipos que usan la biblioteca es doloroso pero se ve como una parte inevitable de la vida de un desarrollador. Sin embargo, desde una perspectiva a vista de pájaro, también es malo para el equipo de la biblioteca, ya que su ecosistema se desincroniza. Conduciendo a diferentes versiones que deben ser mantenidas, los equipos pierden nuevas capacidades, aumentan los esfuerzos, disminuyen la velocidad, en resumen un ecosistema frágil e ineficiente. Angular tiene la pila de herramientas para ayudar aquí, convirtiendo las actualizaciones de la mayoría de las aplicaciones en una línea. Que es lo que el equipo de Angular provee para su biblioteca central:

 ng update @angular/cli @angular/core

En el GDF, queríamos aprovechar esto para nuestra biblioteca de componentes de UI. Nuestra biblioteca se utiliza en Allianz para aplicaciones internas y de cara al cliente en cientos de repositorios. Al pasar a Angular 8 teníamos planeados varios cambios de ruptura, por ejemplo, se cambiaron las rutas de importación, dos componentes fueron reemplazados por un solo componente nuevo y se eliminaron múltiples opciones de la API.
Esta vez, sin embargo, no queríamos cargar a los usuarios de nuestra biblioteca con la carga de tener que adaptarse a estos cambios manualmente. Queríamos proporcionar la misma experiencia que el equipo de Angular para nuestra biblioteca de componentes de interfaz de usuario (llamada ngx-ndbx):

 ng update @allianz/ngx-ndbx

Creando el actualizador

¿Cómo lo hicimos? Primero, necesitábamos un mapa para cada cambio de última hora como base para una migración automatizada. En nuestro caso, esta parte era sencilla y podíamos anotar todos los cambios de ruptura como mapeos lógicos.
La segunda parte era establecer la estructura. Añadimos esto directamente a nuestra biblioteca de componentes, junto con los componentes de la interfaz de usuario. Para las pruebas, establecimos una infraestructura local usando Verdaccio. Esto proporciona un servidor npm ligero para comprobar el proceso antes de publicarlo.
El último paso de la configuración fue decidir cómo atravesar y manipular Typescript y HTML. Para TypeScript usamos la API del compilador de TypeScript y el TypeScript AST Viewer. Para HTML un analizador común era suficiente. Con esta estructura en su lugar comenzamos a escribir los esquemas para todos nuestros cambios de ruptura.
Mientras hacíamos esto encontramos más casos de borde de lo que habíamos anticipado inicialmente. Por ejemplo, las pruebas de unidad y el uso programático de los componentes tenían que ser considerados. Para endurecer nuestros esquemas hicimos pruebas en diferentes aplicaciones reales. Después de varias iteraciones confiábamos en que habíamos cubierto los principales casos de uso. En ese momento pudimos enviar el lanzamiento principal!
Mirando hacia atrás tuvimos algunos baches y pequeños desvíos. Uno de los mayores cambios fue que empezamos con TSLint y terminamos escribiendo nuestros propios fragmentos de código de mapeo. La razón principal de esto fue que en los grandes proyectos nuestro TSLint tenía largos tiempos de ejecución y TSLint será desaprobado y reemplazado por ESLint. Para establecer los esquemas definimos nuestros mapeos en un archivo JSON y escribimos una serie de funciones de ayuda más pequeñas para realizarlos, por lo que tomamos prestada una página de Material Angular.
Lo que definitivamente tomó algo de tiempo fue sentirse cómodo con la comprensión de los mapeos en AST. Especialmente, ya que puede haber diferentes patrones que tienen que ser considerados para mapear todos los cambios. Para resumir, especialmente para la actualización de ng , se debe planear algún tiempo para sentirse cómodo con la AST y para comprobar si se han cubierto todos los casos relevantes que puedan ocurrir en las aplicaciones.
Cuando se ejecuta la actualización ng, así es como se ve.

Aftermath

¿Qué pasó después de la liberación? La liberación es ahora varios meses atrás y hasta ahora sólo hemos recibido comentarios positivos. Todos los equipos de Allianz informaron de una fácil actualización a la versión 8, tanto para Angular como para nuestra biblioteca de UI. En la mayoría de los casos, se informó que la actualización completa tomó menos de una hora. También descubrimos que muchos equipos seguían actualizando manualmente nuestra biblioteca. En la mayoría de los casos, no sabían acerca de la actualización de ng y simplemente seguían el camino al que estaban acostumbrados. En general, estábamos muy contentos con el resultado.
En esta etapa queríamos mirar más de cerca lo que estaba sucediendo en nuestro ecosistema. Uno de nuestros cambios fue eliminar dos componentes desaprobados (A & B) y reemplazarlos por uno nuevo y consolidado. Cuando desaprobamos los antiguos componentes, sus números se mantuvieron estables. Así que los equipos recogían el nuevo componente, pero no se tomaban el tiempo de reemplazar el viejo componente. Esto no fue sorprendente, ya que los equipos quieren centrarse en la entrega y no gastar tiempo valioso en la eliminación de los componentes desaprobados.

Ejemplo de migración de componentes realizada por ng update.
Con el lanzamiento de la versión 8 eliminamos esos componentes, forzando una disminución de los componentes obsoletos. En el pasado, los equipos necesitaban invertir tiempo para reemplazar manualmente los componentes. Ahora con ng update estamos reemplazando los componentes obsoletos automáticamente. Esto es una gran ganancia tanto para los desarrolladores de bibliotecas como de aplicaciones.

Los componentes A y B son sustituidos por los componentes C.
¿Pero cómo se puede traducir esto para los interesados que no están profundamente involucrados en temas técnicos?
Para ayudar con esto, podemos esbozar un caso simple, usando números aproximados que reflejen nuestra experiencia. Si miramos nuestra última actualización importante, estimamos que el esfuerzo de actualización manual es de aproximadamente un día de trabajo (8 horas). Si asumimos que se actualizan 100 aplicaciones, terminamos con un esfuerzo total de 800 horas. Con la actualización de ng asumimos que cada actualización toma una hora, lo que lleva a un ahorro de 700 horas. Escribir los esquemas para nuestra biblioteca de UI, por otro lado, nos llevó unas 200 horas, incluyendo la creación de la infraestructura de los esquemas. Con este simple caso, obtenemos un retorno de la inversión más del triple. A escala y a partir de un coste total perspe

Categorías Blog