Video Summary and Transcription
Hoy voy a hablar sobre cómo la generación de tipos ayudó a reducir errores y mejorar nuestra experiencia como desarrolladores en Rollbar. La pila tecnológica de Monolith se construye principalmente en Python Pyramid, un marco web similar a Django, Ruby on Rails o Express. Para abordar los desafíos de depuración, rendimiento y navegación de código, nos hemos migrado a una pila tecnológica que incluye TypeScript, Next.js, GraphQL y React Query. Codegen se utiliza para generar código TypeScript tanto en el lado del servidor como en el lado del cliente, mejorando la depuración, el rendimiento y la navegación de código.
1. Introducción a Rollbar Monolith y Tech Stack
Hoy voy a hablar sobre cómo la generación de tipos ayudó a reducir errores y mejorar nuestra experiencia como desarrolladores en Rollbar. Daré una visión general de la arquitectura que decidimos implementar. La pila tecnológica Monolith está construida principalmente en Python Pyramid, un marco web similar a Django, Ruby on Rails o Express.
Hola a todos. Hoy voy a hablar sobre cómo la generación de tipos ayudó a reducir errores y mejorar nuestra experiencia como desarrolladores en Rollbar. Soy Paul Sereno. Soy un ingeniero de software senior en Rollbar. Tengo unos 10 años de experiencia como desarrollador de software, trabajando en aplicaciones basadas en web, y vivo en Austin, Texas. Para la agenda de hoy, primero daré una breve introducción al monolito de Rollbar. Hablaré sobre algunos de los desafíos técnicos que experimentamos al mantener el código del monolito. Y explicaré por qué tomamos la decisión de migrar nuestra base de código a TypeScript. Luego hablaré sobre la estrategia de migración a TypeScript, y daré una visión general de la arquitectura que decidimos implementar. Después de eso, hablaré sobre cómo estábamos usando GraphQL Code Gen en Rollbar, y proporcionaré algunos ejemplos de código que demostrarán las diferentes formas en que estamos utilizando Code Gen tanto en el lado del servidor como en el lado del cliente de nuestra aplicación.
De acuerdo, primero vamos a revisar la aplicación Monolith. La pila tecnológica Monolith está construida principalmente en Python Pyramid, un marco web similar a Django, Ruby on Rails o Express. Estamos utilizando varias tecnologías de base de datos como MySQL, Elasticsearch y Clickhouse. El front-end está escrito en React 16, por lo que no hay hooks y todo está estilizado usando una combinación de Sass y CSS.
2. Migración a Nueva Pila Tecnológica
A lo largo de los años, el Monolith ha tenido 78 colaboradores, más de 44,000 commits y más de 9,000 pull requests. Desarrollar y desplegar en una base de código monolítica tiene sus beneficios, como procesos de desarrollo y despliegue más sencillos. Sin embargo, la depuración, el rendimiento y la navegación del código han sido desafíos significativos. Para abordar estos problemas, decidimos migrar a una nueva pila tecnológica que incluye TypeScript, Next.js, GraphQL y React Query. Esta pila tecnológica nos permite aprovechar la seguridad de tipos, la flexibilidad en las migraciones del backend y las llamadas eficientes a la API a través de React Query.
A lo largo de los años, el Monolith ha tenido 78 colaboradores, más de 44,000 commits y más de 9,000 pull requests, y tiene 11 años de antigüedad. Hay algunos beneficios de trabajar en una base de código monolítica. Es mucho más fácil desarrollar en una base de código monolítica, porque a menudo hay código de plantilla que los desarrolladores pueden copiar y pegar y ajustar para hacer que algo funcione más rápido. Desarrollar una aplicación monolítica a veces es más fácil si puedes encajar todo en una... Disculpen por eso.
Desplegar una aplicación monolítica a veces es más fácil porque puedes encajar todo en un solo Dockerfile. Y la búsqueda de código a menudo es una mejor experiencia en aplicaciones monolíticas porque una línea de código que deseas buscar está en un solo repositorio. Por lo tanto, es mucho más fácil buscar líneas de código individuales.
Algunos de los desafíos que experimentamos al trabajar en nuestras aplicaciones monolíticas han sido la depuración, que ha sido un gran desafío porque hay mucho código que debes leer para comprender completamente la causa raíz de ciertos problemas. Nosotros mismos usamos Rollbar para clasificar los problemas, y aunque las funciones de agrupación que proporciona Rollbar son buenas, todavía nos resulta difícil identificar la causa raíz de algunas partes del código que son realmente complejas. El rendimiento es otro problema con nuestra base de código monolítica, y se debe principalmente a un código ineficiente. Por ejemplo, cosas como hacer llamadas duplicadas a la base de datos y realizar un procesamiento pesado después de obtener los datos han sido un cuello de botella bastante grande. También hemos experimentado problemas al navegar por el código. A veces puede llevar horas comprender completamente cómo funcionan algunas cosas. Dado estos problemas, decidimos tomar la decisión de migrar lejos de trabajar en una aplicación monolítica hacia una nueva pila tecnológica.
Y esa pila tecnológica incluye TypeScript. Por lo tanto, la nueva pila tecnológica aprovecha Next.js, GraphQL y React Query para ayudar a resolver algunos de los problemas relacionados con nuestra aplicación monolítica. Y, por supuesto, todo está escrito en TypeScript. La nueva pila tecnológica a la que estamos migrando todavía utiliza partes de la aplicación monolítica. Hemos hecho que esas características del monolito estén disponibles a través de varios puntos finales de API internos. El servidor GraphQL se utiliza esencialmente como un proxy de API que se encuentra entre nuestra API interna y nuestra aplicación front-end. Decidimos utilizar GraphQL de esta manera porque no solo proporciona seguridad de tipos entre el servidor y el cliente, sino que también nos brinda flexibilidad en términos de migraciones del backend. Por ejemplo, planeamos reemplazar algunos de los puntos finales de API internos con llamadas gRPC. En esta arquitectura de proxy, podemos experimentar con diferentes soluciones de backend. Todas nuestras llamadas a la API desde el front-end se realizan a través de React Query. Y el cliente de React Query que estamos utilizando se genera completamente a partir de las consultas de GraphQL en sí. Hablaré de eso en un momento. Esta configuración nos ha permitido obtener mucha seguridad de tipos en el front-end. Mencioné que generamos nuestro cliente front-end. Específicamente, utilizamos una herramienta llamada GraphQL Codegen.
3. Usando Codegen para Generación de Tipos
Usamos Codegen para generar código TypeScript tanto en el servidor como en el cliente. Proporciona una herramienta de línea de comandos fácil de usar. Para las funciones de resolución, agregamos manualmente tipos para garantizar la seguridad de tipos. Codegen permite la configuración de anulaciones para la generación de tipos. En el lado del cliente, Codegen puede generar hooks seguros en cuanto a tipos a partir de consultas GraphQL. La migración a esta arquitectura mejora la depuración, el rendimiento y la navegación del código. TypeScript mejora la experiencia del desarrollador al permitir el trabajo en paralelo.
Y esta es una herramienta de código abierto que generará automáticamente código TypeScript a partir de un esquema GraphQL o una operación de consulta GraphQL. Por lo tanto, usamos Codegen tanto en el servidor como en el cliente. En el lado del servidor, lo usamos para generar tipos para nuestros resolutores GraphQL. Y en el cliente, lo usamos para generar el cliente de
Daré algunos ejemplos de las diferencias entre cómo lo usamos en el servidor y en el cliente. Usar Codegen en sí es bastante fácil. Codegen proporciona una herramienta de línea de comandos que es bastante fácil de usar. Solo tienes que ejecutar Codegen y darle una configuración.
Quiero dar un ejemplo específico de cómo estamos usando Codegen en el servidor. Este es un fragmento de código tomado de nuestra base de código. Esto representa el esquema de conexión de entorno que está diseñado para representar una lista de entornos de proyecto. Y usar la nomenclatura de conexión de código es común en GraphQL cuando se representa listas paginadas de data. El resolutor para esta conexión simplemente obtiene de la base de datos los entornos del proyecto y devuelve una lista de entornos.
Uno de los problemas que encontramos al usar TypeScript en GraphQL ha sido agregar seguridad de tipos a estas funciones de resolución. Por ejemplo, de forma predeterminada, los argumentos como límite, después de filtro no generan tipos para ellos. Por lo tanto, tenemos que agregar manualmente los tipos nosotros mismos. Este es un ejemplo de un tipo que definimos explícitamente para esos argumentos del resolutor. Y Codegen de GraphQL proporciona una solución alternativa para estos problemas. Te permite agregar explícitamente una configuración para anular su generación interna. Por ejemplo, en este caso, estamos anulando la generación de la conexión de entorno usando nuestros tipos definidos explícitamente aquí. En el modelo de conexiones de entorno, se asigna a la definición del esquema de conexión de entorno.
En el lado del cliente, puedes usar la herramienta de línea de comandos de la misma manera simplemente llamando a CodeGen de GraphQL. La generación de código es mucho más fácil en el cliente. Dada una consulta GraphQL como esta, en este ejemplo estamos obteniendo una lista de entornos de nuestro servidor GraphQL. Y podemos generar un hook a partir de esa consulta usando CodeGen de GraphQL. Este hook obtendrá los datos que necesitamos y será completamente seguro en cuanto a tipos. Entonces, en este ejemplo, como puedes ver, cuando llamas o escribes en tu editor de texto query.results, podrás ver los diferentes atributos que tiene ese objeto.
Algunos de los beneficios que hemos experimentado al migrar a esta arquitectura han sido la depuración. Es mucho más fácil que el comprobador de tipos detecte posibles problemas. El rendimiento, hay varias optimizaciones en tiempo de compilación que se pueden obtener al tener tu base de código en TypeScript, y hemos visto un aumento en el rendimiento de nuestra aplicación. En cuanto a la navegación en la base de código, tener esas anotaciones de tipo ha hecho que trabajar con bibliotecas internas sea mucho más fácil de usar, especialmente bibliotecas que no tienen una muy buena documentación. Y un beneficio adicional de usar TypeScript ha sido mejorar nuestra experiencia general como desarrolladores, ya que ha permitido a los desarrolladores de front-end y back-end trabajar en paralelo sin depender uno del otro.
Algunas de mis reflexiones finales son que migrar una base de código monolítica es un desafío, pero con la arquitectura adecuada, incluso un equipo pequeño puede hacerlo posible. Hemos obtenido muchos beneficios al configurar esos puntos finales internos y simplemente usar GraphQL como un proxy para nuestra API interna. Y en general, TypeScript mejoró nuestra capacidad para depurar y optimizar nuestro código. Eso es todo. Gracias.
Comments