Porting Turborepo to Rust

This ad is not shown to multipass and full ticket holders
JSNation US
JSNation US 2025
November 17 - 20, 2025
New York, US & Online
See JS stars in the US biggest planetarium
Learn More
In partnership with Focus Reactive
Upcoming event
JSNation US 2025
JSNation US 2025
November 17 - 20, 2025. New York, US & Online
Learn more
Bookmark
Rate this content

A todos les encanta hablar sobre reescribir en Rust, pero las reescrituras son difíciles. Es demasiado fácil caer en el efecto del segundo sistema, retrasos en el envío y terminar perdiendo a todos tus usuarios. ¿Cómo puedes mudarte a Rust mientras sigues lanzando funciones y manteniendo felices a tus usuarios? Fácil, en lugar de reescribir, ¡porta! En esta charla, repasaremos cómo portamos Turborepo de Go a Rust usando tres estrategias diferentes: un shim de Rust que envolvía el código Go existente; un sándwich Rust-Go-Rust para portar dependencias de manera incremental; y finalmente una implementación completamente paralela en Rust. Hablaremos sobre por qué elegimos estas estrategias, cómo las implementamos y cómo las enviamos a los usuarios.

This talk has been presented at JSNation US 2024, check out the latest edition of this JavaScript Conference.

Nicholas Yang
Nicholas Yang
25 min
18 Nov, 2024

Comments

Sign in or register to post your comment.
Video Summary and Transcription
La charla de hoy trata sobre portar a Rust, específicamente la experiencia de portar Turbo Repo, un sistema de construcción para JavaScript, de Go a Rust. El orador discute los desafíos enfrentados durante el proceso de portación, como las discrepancias en el código de permisos de archivos y problemas con Alpine Linux. Explican el enfoque tomado, incluyendo el uso de un shim de Rust y portar dependencias individuales de Go a Rust. La charla también cubre las limitaciones y desafíos encontrados durante el proceso de portación, así como los beneficios de aprovechar el ecosistema de Rust. El orador discute las consideraciones de reescribir versus portar y la importancia del conocimiento institucional. También tocan el impacto en el rendimiento del proceso de portación y las mejoras logradas al pasar a una implementación completamente en Rust.
Available in English: Porting Turborepo to Rust

1. Introduction to Porting to Rust

Short description:

Hoy, estoy aquí para hablar sobre cómo portar a Rust. Turbo Repo es un sistema de construcción para JavaScript que coordina diferentes paquetes dentro de un monorepo, construye un gráfico de dependencias de paquetes y orquesta tareas en paralelo. Son alrededor de 70,000 líneas de Go, compiladas para x86 y ARM en Mac, Windows y Linux. Decidimos portar por razones de alineación.

♪♪ Sí, si quieren información sobre aceite de chile, literalmente he escrito tres publicaciones de blog al respecto. Pueden buscarlas. Veamos. Sí, es genial. Entonces, ¿a quién aquí le gusta escribir en Rust? Yay, a algunos de ustedes. Y debido a eso, bueno, se ha convertido en un movimiento de reescribir en Rust, y es genial. La gente ha reescrito de todo, desde compiladores hasta navegadores en Rust. Pero las reescrituras son difíciles. Vienen con muchos desafíos. Tienes que aprender esta nueva tecnología. Tienes cambios disruptivos, errores, y puedes terminar perdiendo usuarios en el proceso.

Y así que hoy, no estoy aquí para hablar sobre reescribir en Rust. En cambio, estoy aquí para hablar sobre cómo portar a Rust. Y esto puede parecer una distinción menor, pero realmente se trata de mover piezas incrementalmente sin cambios disruptivos y manteniendo el mismo comportamiento fundamental en la arquitectura. No estás tratando de reinventar la rueda aquí. Y así es como lo hicimos con Turbo Repo. Entonces, primero, ¿qué es Turbo Repo? Turbo Repo es un sistema de construcción para JavaScript. Básicamente te permite coordinar los diferentes paquetes dentro de tu monorepo, y construye un gráfico de dependencias de paquetes, y luego desde allí, orquesta las diferentes tareas que necesitan ejecutarse. Y hace esto en paralelo, y luego almacena en caché los resultados. Así que, si quieres ejecutar la misma tarea de nuevo, simplemente leerás desde la caché en lugar de ejecutarla.

Así que, en una configuración tradicional, puede verse así, donde simplemente estás ejecutando todo secuencialmente, pero con Turbo Repo, es en paralelo y, por supuesto, en caché. Así que, debajo del capó, lo que básicamente está haciendo es cargar un montón de configuraciones. Luego inicia un gráfico de dependencias de paquetes. Así que, de nuevo, es qué paquetes dependen de cuáles. Podrías tener como una biblioteca de UI que es utilizada tanto por una aplicación web como por una aplicación de documentación, y luego desde allí, inicia las dependencias de tareas. Así que, tal vez tengas una tarea de lint que depende de una tarea de construcción, y luego ejecuta estas en paralelo, almacena en caché los resultados y muestra un resumen al usuario. Y son alrededor de 70,000 líneas de Go, y está compilado para seis objetivos diferentes. Eso es x86 y ARM en Mac, Windows, Linux. Entonces, ¿por qué decidimos portar? Bueno, la primera razón es realmente sobre alineación. Verán, Go es realmente genial si estás escribiendo un servidor web ejecutándose en Linux.

2. Challenges and Starting with Rust Shim

Short description:

Go miente sobre los códigos de permisos de archivos en Windows, pero Rust lo hace bien. Rust aprovecha excelentes proyectos como Biome, SWC, NAPI y Auxy para construir mejores herramientas. Comenzamos de manera incremental, agregando funcionalidad de Rust a TurboRepo a través del Rust shim.

Asume muchas cosas de Unix. Y así, el ejemplo clásico de esto son los códigos de permisos de archivos. Go te permitirá establecer un código de permiso de archivo al estilo Unix. Pero el único problema es que, en Windows, ese concepto no existe. Y así, cuando estableces este código, Go básicamente te mentirá. Será como, sí, claro, lo establecí, y no hará nada. Y eso aparece en cada pequeño detalle.

Y así, con Rust, acierta en estos detalles. Se asegura de que, si quieres establecer un código de permiso de archivo al estilo Unix, tienes que estar ejecutando en Unix. De lo contrario, hay una API separada para Windows. Y la segunda razón es realmente sobre el ecosistema. Verás, hay muchos proyectos excelentes por ahí haciendo un gran trabajo apoyando JavaScript en Rust. Esto podría ser Biome, que es un excelente Winter y Formatter, SWC, NAPI, Auxy. Y queremos aprovechar estas plataformas para construir mejores herramientas.

Entonces, ¿cómo empezamos? Podrías imaginar un mundo donde simplemente comienzas desde cero. Construyes una línea de comandos, construyes un gráfico de paquetes, construyes un gráfico de tareas, y sí, estás en buen camino. Pero hay muchas características. Hay muchas cosas que construir. Y es importante recordar, este es un producto maduro que es utilizado por mucha gente. No puedes simplemente eliminar estas características. Y así que no tomamos ese enfoque. En cambio, decidimos seguir lanzando características y realmente hacer las cosas de manera incremental. Nuestro objetivo era realmente que el código Rust añadiera funcionalidad a TurboRepo.

Y así decidimos comenzar con una característica muy básica. Y está facilitado por lo que llamo el Rust shim. El Rust shim nos permite implementar turbo global. Turbo global te permite usar TurboRepo como un binario común y corriente. Pero dentro de tu monorepo, encontrará la versión local de TurboRepo que está instalada y la ejecutará. Puedes pensar en ello como algo similar a core pack, donde core pack te permite ejecutar un binario global de NPM, pero usará la versión especificada en tu package.json. Y la forma en que implementamos esto fue con lo que llamamos el Rust shim, que es esencialmente una capa delgada de Rust envolviendo el código Go.

3. Porting Issues with Alpine Linux

Short description:

El código Go compilado como una biblioteca compartida vinculada con C y ejecutada por un shim de Rust. Análisis de línea de comandos portado usando la biblioteca clap. Args serializados a JSON y enviados a Go. Problemas encontrados con Alpine Linux debido a la falta de glibc. Intento de usar muscle como sustituto, pero se encontró un fallo de segmentación. Se encontró un problema de GitHub de hace nueve años que explica la incompatibilidad de Go como biblioteca compartida con muscle. Se tuvo que reconsiderar el enfoque.

El código Go se compilará como una biblioteca compartida vinculada con C y ejecutada por un pequeño shim de Rust. Y después de esto, fue bastante simple portar el análisis de la línea de comandos, ya que ya teníamos que hacer un poco para turbo global. Y así analizamos los args usando una gran biblioteca llamada clap.

A partir de ahí, serializamos esos args a JSON y los enviamos al Go. Y la razón por la que usamos pic.json aquí es que realmente no queríamos escribir un montón de tipos C codificando los diferentes args. C es notoriamente un lenguaje no muy portátil. Y así fue mucho más fácil simplemente enviar una gran cadena.

Así que con eso, decidimos enviarlo. Excepto que nada sale según lo planeado. Así que aquí hay algunos problemas con los que nos encontramos. El principal fue con Alpine Linux. Si no están familiarizados, Alpine es una distribución de Linux que se usa a menudo en la computación en la nube. Y una cosa que lo hace genial es que es súper ligero.

Y una cosa que lo hace ligero es que no viene con glibc. glibc es una implementación de la biblioteca estándar de C que muchos binarios enlazan dinámicamente. Básicamente, el binario llamará a una versión separada de glibc. Sin embargo, dado que glibc no está en Alpine, y de hecho, dado que queremos soportar versiones realmente antiguas de Alpine, no pudimos usar su versión de glibc que puedes instalar. Y así decidimos en su lugar usar muscle, que es una variante de la biblioteca estándar de C que puedes enlazar estáticamente. Básicamente podrías simplemente incluirlo en el binario.

Sin embargo, cuando esto sucedió, tuvimos un fallo de segmentación casi de inmediato. Y de hecho, esto fue un gran misterio porque cuando lo investigamos, el fallo de segmentación venía literalmente del medio del tiempo de ejecución de Go y la pila estaba completamente corrupta. Y básicamente era como este error de vudú. No había explicación de lo que estaba sucediendo. Y finalmente, encontramos este problema de GitHub de hace nueve años que básicamente explica que no puedes usar Go como una biblioteca compartida con muscle. Todavía está abierto, por cierto. Puedes ir a verlo. Por favor, vota mi comentario. Y sí, esto fue un obstáculo. Tuvimos que soportar Alpine, y no podíamos tomar este enfoque. Así que tuvimos que volver a la mesa de dibujo un poco.

4. Porting the Go Sandwich

Short description:

Dos binarios: Rust llama a Go. Sándwich Go: Porta dependencias individuales de Go a Rust y enlázalas en el binario de Go. Usa protobuf para la comunicación. Proceso regimentado permite pruebas entre versiones de Rust y Go.

Y lo que se nos ocurrió fueron dos binarios. Básicamente, el binario de Rust llama al binario de Go y pasa los args. Y eso funcionó bastante bien. Así que con eso, pudimos enviar el gem de Rust en Turbo 1.7.

Así que ahora hablemos del sándwich Go. Así que en este punto, logramos portar un montón de cosas pequeñas como iniciar sesión, cerrar sesión. Pero no pudimos averiguar cómo portar la tubería de ejecución principal. Porque casi de inmediato, tenemos que iniciar el gráfico de dependencias del paquete. Y realmente no queríamos enviar eso a través de JSON porque los gráficos no son las cosas más serializables.

Y así, lo que decidimos fue lo que llamamos el sándwich Rust-Go-Rust, o el sándwich Go para abreviar. Básicamente, tomaríamos dependencias individuales de Go, las portaríamos a Rust y las enlazaríamos en el binario de Go. Aunque no podíamos enlazar Rust a Go, podíamos enlazar Go a Rust. Y así, esto funcionó bastante bien. Y usaríamos protobuf para comunicarnos entre estas dependencias para, nuevamente, evitar escribir demasiado C.

Y esto también hizo un proceso realmente agradable y regimentado. Podríamos comenzar teniendo el código Go. Podríamos escribir la versión en Rust. Podríamos probar entre los dos. De hecho, podríamos literalmente probar simplemente llamando a la versión de Rust, y luego llamando a la versión de Go, y comparando las salidas. Podemos fusionar el código, pero desactivar la versión de Rust. Y luego podríamos activar la versión de Rust. Y en cualquier momento, si teníamos algún error, simplemente podríamos volver a marcar, y volver a la versión de Go.

5. Porting Challenges and Limitations

Short description:

Piezas portadas: análisis de archivos de bloqueo, hash de archivos. Desafíos de compilación cruzada con Rust y Go debido a dependencias de C. Orquestar la compilación cruzada con ZigCC. Enviado sándwich Go en Turbo 1.8.6. Limitaciones al manejar llamadas async usando el sándwich.

Y así, esto funcionó muy bien. Pudimos portar un montón de piezas, como nuestro análisis de archivos de bloqueo y hash de archivos, lo cual es importante para los artefactos de caché y demás. Así que vamos a enviarlo. Aceptar más problemas.

Así que recordemos. Estamos construyendo para seis arquitecturas diferentes. Y debido a eso, tenemos que hacer lo que se llama una compilación cruzada. Básicamente, tenemos que construir para una arquitectura diferente a la que estamos compilando. Así que tal vez estés apuntando a Windows x86 mientras ejecutas en un Linux ARM. Y normalmente, Rust y Go son bastante buenos en la compilación cruzada. Pero juntos, son terribles, porque Rust tiene todas estas dependencias de C que utiliza.

Y estas dependencias de C, normalmente, Rust es lo suficientemente inteligente como para compilar cruzadamente. Pero como Rust no está construyendo un binario, Go lo está haciendo. Go tiene que hacer ese enlace final de compilación cruzada. Y Go realmente no entiende lo que está pasando tampoco. Y así tienes que orquestar esto tú mismo, y tienes que encontrar un buen compilador cruzado de C, lo cual no es fácil. A menudo requiere instalar un montón de versiones diferentes y encontrar las bibliotecas relevantes y crear rutas de sistema. Y es solo un proceso enorme y desordenado. Excepto si usas Zig. Sí, más cebo de hacker news. Y Zig, específicamente, viene con un gran compilador de C llamado ZigCC que te permite compilar cruzadamente como si nada. Es genial.

Y así, con eso, enviamos el sándwich Go en Turbo 1.8.6. Así que finalmente, hablemos del esquema de ejecución. En este punto, estábamos alcanzando los límites de lo que el sándwich podía manejar. Específicamente, realmente no queríamos manejar async en absoluto, porque con el sándwich, estábamos haciendo todas las llamadas sincrónicas. Así que literalmente solo el Go llamaría al Rust, el Rust haría algún trabajo, y luego regresaría. Pero con async, el Rust persistiría, y tendrías que encontrar una manera de extraerlo, y tendrías que mantener un runtime de Go alrededor y un runtime de Rust alrededor. Y no sé cómo interactuarían esos. Y simplemente parecía un dolor de cabeza.

6. Building All-Rust Pipeline and Hashing Strategy

Short description:

Construido pipeline de ejecución completamente en Rust. Probadas e integradas piezas existentes. Usado hashing para asegurar confianza en el código. Hashing estable entre Rust y Go. Algoritmo de hashing independiente del lenguaje. Formato Cat and Proto para salida idéntica. Ejecutando pruebas con ruta de código Rust. Creando gráfico de reducción de pruebas fallidas.

Así que, en su lugar, decidimos construir un pipeline de ejecución completamente en Rust y simular las partes no implementadas y luego implementarlas poco a poco. Y añadimos una bandera para que pudieras ejecutar esta ruta de código. Y con eso, pudimos...

Y lo importante a recordar aquí es que ya habíamos construido muchas de estas piezas. Sabes, podrías argumentar que esto es una reescritura, y tendrías razón, pero ya habíamos construido estas piezas, y lo que es más importante, las habíamos probado. Literalmente las habíamos ejecutado en código de producción. Y es importante recordar aquí que hay un peligro real con el código no utilizado. Si simplemente hubiéramos reescrito sin el Sandwich o el shim, solo tendríamos un montón de código escrito en Rust que no estaba siendo utilizado. Y el código que no se usa es fundamentalmente código en el que no puedes confiar. Claro, puedes escribir una prueba, pero una prueba no va a capturar todos los pequeños detalles que un usuario capturará. Y así queríamos encontrar otra manera de integrar estas piezas en nuestro sistema y probarlas. La forma en que descubrimos hacer esto fue usando hashing.

Así que el hashing está en el núcleo de Turbo. La forma en que funciona es que cuando ejecutas una tarea, Turbo crea todas las entradas de la tarea. Esto podría ser los archivos, variables de entorno, otras tareas, y calcula un único valor llamado hash. Este hash se usa luego para indexar en la caché del repo de Turbo. Así que si hay una entrada allí, sabes que la tarea ya ha sido ejecutada, y puedes simplemente restaurar desde la caché. Decidimos mantener el hashing estable entre ambos Rust y Go. Y lo que esto significaba es que esperábamos que Rust y Go estuvieran de acuerdo en el mismo hash. Si no lo estaban, entonces había un problema. Y así esto requería mover tanto el código Rust como el código Go a un algoritmo de hashing independiente del lenguaje. Y esto fue complicado, pero pensamos que valía la pena porque básicamente podías estar seguro de que tanto el gráfico de tareas, el gráfico de paquetes, y el orden de ejecución serían todos idénticos desde Go y Rust. Para hacer esto, usamos un formato de hashing llamado Cat and Proto. Cat and Proto es genial. Es básicamente un formato que se asigna literalmente byte por byte, y así sabes que a través de diferentes lenguajes, producirá exactamente el mismo resultado. Si fuéramos a usar algo como JSON, bueno, hay muchas maneras diferentes de serializar JSON. Y así pudimos entonces usar esta estrategia de hashing para portar un montón de piezas y seguir probando entre los dos sistemas.

En este punto, estábamos casi listos para lanzar. Estábamos ejecutando nuestras pruebas con la ruta de código experimental de Rust. Comenzamos a crear un gráfico de reducción de todas las pruebas fallidas.

7. Leveraging Ecosystem and Interoperability

Short description:

Se corrigieron errores y se lanzó la versión completamente en Rust. Se aprovechó el ecosistema con Biome para errores de análisis. Se implementó Turbo Trace para el seguimiento de dependencias. Se usaron SWC y oxy para límites y Turbo Query. Se interoperó entre Rust y JavaScript con API. Aprendimos al mover 70,000 líneas en 15 meses.

Una vez que solucionamos eso, pudimos dog food para la implementación de Rust para añadir a la venta. Por supuesto, tenemos mucho JavaScript allí, así que usamos Turbo Repo en nuestros monorepos. Y una vez que llegamos a 72 horas sin errores, lanzamos una versión completamente en Rust con una bandera de go-fall-back en caso de que encontráramos errores. Y así, con Turbo 1.11, llegamos a todo Rust. Woo.

Entonces, ¿qué hicimos después del port? Lo primero es este increíble PR donde eliminé como 70,000 líneas de código. Esto es como el pico de mi carrera, lo más satisfactorio que he hecho. Y después de eso, bueno, hicimos lo que dijimos. Comenzamos a aprovechar el ecosistema. Así que comenzando, usamos Biome para crear errores de análisis realmente agradables. Verás, tenemos mucha configuración JSON, y estábamos usando Seride para cargarlo, pero ahora usamos Biome porque Biome viene con un analizador realmente bueno. Y así te dará errores de análisis detallados como, oye, dejaste una coma extra aquí. Y luego también podemos tomar esta información de ubicación y usarla para nuestros propios errores.

Así que ahora si tienes un error en tu configuración, señalará la ubicación exacta donde ocurrió, e incluso te dará un pequeño consejo sobre cómo puedes solucionarlo. A continuación, usamos SWC y oxy para implementar lo que se llama Turbo Trace. Nos permite rastrear a través de diferentes dependencias. Básicamente, puedes determinar qué archivo depende de otro archivo y así sucesivamente. Y esto se está utilizando para implementar límites, que es una nueva característica que saldrá pronto. Tenemos un RFC sobre ello en el que puedes comentar. Básicamente, es una característica que te permite restringir qué paquetes pueden depender de cuáles y qué archivos pueden depender de cuáles para crear reglas para tu monorepo. Y también usamos esto para Turbo Query, que es una implementación de consulta para tu monorepo.

Básicamente, puedes consultar sobre la estructura del repositorio o usando GraphQL. Finalmente, usamos una API para interoperar entre Rust y JavaScript. Y esto es genial porque ahora Vercel puede aprovechar el código de Turbo Repo. Podemos usar Turbo Repo para averiguar qué proyectos afectan tus cambios. Así que si solo cambias algo en tu proyecto de documentos, no reconstruyes todo el mundo. Solo reconstruyes el proyecto de documentos. Y aunque podías hacer esto antes con Turbo Repo, lo bueno es que como está integrado en Vercel, se hace a un nivel muy bajo, así que ni siquiera inicias la VM si no es necesario. ¿Qué aprendimos? En general, hicimos muchas cosas bien.

8. Porting Challenges and Lessons Learned

Short description:

Se lanzaron características y se corrigieron errores. Aprovechar la serialización con JSON, Protobuf y Captain Proto. El equipo se puso al día con Rust. Deberíamos haber invertido en mantenimiento y proceso de construcción. Podríamos haber lanzado nada rápidamente. Rust es excelente para productos maduros pero no para comenzar cosas. Portar es una gran manera de avanzar sin perder usuarios.

Y podrías pensar, 15 meses, eso es mucho tiempo. Pero fueron 15 meses de lanzamiento de características, de corrección de errores. No fueron 15 meses de silencio radial. Y no nos quedamos atascados en este proceso. Habría sido muy fácil, como, vamos a re-arquitecturar esto y crear el mejor sistema de construcción de todos los tiempos. No, no hicimos eso. Lo mantuvimos simple. Mantuvimos nuestros ojos en el premio. Y movimos las cosas rápidamente. Y en ese proceso, pudimos aprovechar la serialización, tanto con JSON en el shim, con Protobuf en el sandwich, y luego con Captain Proto en el esquema de ejecución. Y logramos que el equipo se pusiera al día con Rust en el proceso.

¿Qué no salió bien? Bueno, definitivamente podríamos haber invertido en algo de mantenimiento antes del port. Teníamos esta idea vaga de que podrías refactorizar mientras portabas. Y eso rápidamente resultó no ser el caso. Así que teníamos algunas características que estaban obsoletas, pero no eliminadas, que probablemente deberíamos haber eliminado antes de portar. En cambio, tuvimos que portar estas características porque queríamos mantener la paridad de características. Y eso fue complicado. También podríamos haber invertido en el proceso de construcción. Las construcciones se volvieron realmente lentas. El sandwich Rust go Rust era muy lento de construir. Y finalmente, podríamos haber lanzado nada rápidamente. Y lo que esto significa es que podríamos haber lanzado básicamente una versión en blanco de cada estrategia de portado muy temprano. En cambio, invertimos mucho en el proceso y luego lanzamos. Y esto creó mucho estrés donde si el lanzamiento no iba bien, bueno, teníamos mucho código invertido en esta estrategia. Y así tendríamos que retroceder o hacer que funcionara. Y esto se complicó.

Finalmente, aquí está tu diapositiva de Rust versus Go. En general, diría que Rust es realmente genial para, como, productos maduros donde quieres todos estos pequeños detalles minuciosos. Pero no es genial si quieres poner las cosas en marcha. Como, lleva a algunas discusiones interminables y algunos argumentos generales sobre, como, oh, ¿deberíamos soportar rutas no UTF-8 o deberíamos hacer este pequeño caso especial? Así que quiero dejarte con esta idea de que portar es una gran manera de mover cosas sin perder usuarios y mientras aún puedes lanzar.

QnA

Porting Considerations and Interoperability

Short description:

¿Cuándo es mejor reescribir en lugar de portar? Portar es doloroso y complicado, pero las reescrituras son realmente difíciles. Un buen conocimiento institucional y un compromiso a largo plazo pueden hacer que valga la pena reescribir. Algunos patrones en el código GO no pudieron replicarse exactamente en REST debido al borrow-checker. TurboRepo era propicio para ser escrito en REST. El problema de glibc no habría sido un obstáculo a largo plazo. TypeScript puede portarse a REST usando una estrategia similar, con la ayuda de APIs y serialización para la interoperabilidad.

Gracias. Así que quiero comenzar con una pregunta que tenía. Entonces, cuando estabas portando en lugar de reescribir, hubo muchos beneficios, pero hubo algunas cosas adicionales que tuviste que hacer si no hubieras reescrito. Entonces, para las personas que consideran esto, ¿cuándo crees que es realmente mejor simplemente reescribir en lugar de portar? Porque podría haber algo de complejidad adicional al portar. Esa es una buena pregunta. No estoy completamente seguro. Estoy casi tentado a decir, como, casi siempre deberías portar. Como, portar fue doloroso, fue complicado. En muchos puntos fue lo más molesto, pero creo que valió la pena porque las reescrituras son realmente difíciles. Como, una cosa de la que no hablé es, como, si hubiéramos tomado la ruta de reescribir, como, ¿habríamos seguido actualizando el código Go? Porque si no lo hacíamos, bueno, nuestros usuarios simplemente se quedarían atascados y no recibirían nuevas características o correcciones de errores. Pero si lo hacíamos, entonces, bueno, el código REST tendría que ponerse al día. Sería como una especie de carrera interminable. Y así diría que, como, tal vez si tienes un muy buen conocimiento institucional del producto, has trabajado, tu equipo ha trabajado en él durante mucho tiempo, y tienes el, como, apoyo para pasar el próximo, ya sabes, año o dos reescribiendo, entonces tal vez valga la pena. Pero de lo contrario, diría que probablemente deberías portar.

Bien, y déjame revisar las preguntas aquí. Entonces, de Brian, ¿hubo algunos patrones en el código que no pudiste replicar exactamente en REST debido al borrow-checker? Um, un poco, nada tan loco. Como, definitivamente hubo algunos casos donde tendrías que pensar en el código muy cuidadosamente, y también tal vez te darías cuenta de que el código GO tenía algunos problemas que nunca habían sido, como, vistos antes. Como, me di cuenta mientras portaba parte del código de caché que había, como, una ligera condición de carrera que nunca había sido detectada en un código GO que el código REST no permitiría. Y así te encontrabas con esos. Pero en general, TurboRepo fue un proyecto muy propicio para ser escrito en REST porque los tiempos de vida no eran muy complicados.

Bien. Y a continuación de John, si hubieras sabido sobre el problema de glibc de antemano, ¿habrías elegido aún portar? Sí. Quiero decir, sabes, fue molesto, pero eventualmente funcionó, y, ya sabes, sí, no habría sido un obstáculo a largo plazo. Sí. Siguiente pregunta. ¿Es posible portar TypeScript a REST usando esta estrategia similar? Probablemente. Podrías usar algo como una API para interoperar y luego mover las cosas de manera incremental. Creo que también, como, usar la serialización podría ser una técnica interesante donde básicamente solo envías casi, como, mensajes a través del cable. Creo que podrías hacer esto con cualquier lenguaje, y creo que también el ecosistema para la interoperabilidad está mejorando cada vez más. Como, creo que hay más herramientas por ahí que te ayudan.

Interoperability and Performance

Short description:

Al comenzar, había una publicación de blog sobre la interoperabilidad entre REST y Go que involucraba ensamblaje en bruto, la cual descartamos. No hubo miradas de reojo para la idea del sándwich de Go; el equipo estaba enfocado en hacerlo. El sándwich y el shim tuvieron un impacto en el rendimiento, pero la sobrecarga de syscall de TurboRepo lo mitigó. Pasar a REST completo resultó en una ligera mejora de rendimiento, aunque no tan significativa como se esperaba.

Como, cuando comenzamos, había literalmente, como, una publicación de blog sobre cómo interoperar REST y Go, y literalmente involucraba escribir ensamblaje en bruto, así que rápidamente descartamos esa opción.

Bien. Ahora de Brian, ¿cómo reaccionó tu equipo al cambiar tu camino hacia la entrega? Como, ¿recibiste miradas de reojo por la idea del sándwich de Go?

No, creo que todos estábamos bastante comprometidos y solo teníamos esta idea de, como, tenemos que, como, simplemente hacerlo, y, ya sabes, tengo que darle crédito a mi gerente aquí donde fue realmente bueno en, como, mantener el enfoque y mantener las cosas haciendo cualquier cosa que pudiéramos para seguir avanzando. Sí. Bien. Brian tiene otra pregunta. ¿Notaste diferencias de rendimiento entre las diferentes compilaciones? Sí. Entonces, por supuesto, el sándwich y el shim resultaron en algún impacto en el rendimiento. No fue tan intenso porque TurboRepo es principalmente sobrecarga de syscall. Como, la mayor parte es solo recorrer el sistema de archivos y hacer todo eso, y también, como, dado que literalmente aceleramos las compilaciones mediante el almacenamiento en caché, si somos un poco más lentos, aún no es tan importante porque tienes el caché.

Pero una vez que pasamos a REST completo, notamos una ligera mejora en el rendimiento. Sin embargo, no fue tan grande como se esperaría. Como, Go es razonablemente rápido para lo que estamos haciendo, y, de nuevo, sobrecarga de syscall.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Vite: Repensando las Herramientas de Frontend
JSNation Live 2021JSNation Live 2021
31 min
Vite: Repensando las Herramientas de Frontend
Top Content
Vite is a next-generation build tool that leverages native ES modules for improved performance. It eliminates the need for bundling and improves hot module replacement. Vite provides an opinionated default configuration while still allowing advanced customization through plugins. It is framework agnostic and can be used for React and other applications. Vite is being adopted by Next.js and Create React App, and integration with Nuxt 3 offers significant speed improvements.
Compilador React Forget - Entendiendo React Idiomático
React Advanced 2023React Advanced 2023
33 min
Compilador React Forget - Entendiendo React Idiomático
Top Content
Joe Savona
Mofei Zhang
2 authors
The Talk discusses React Forget, a compiler built at Meta that aims to optimize client-side React development. It explores the use of memoization to improve performance and the vision of Forget to automatically determine dependencies at build time. Forget is named with an F-word pun and has the potential to optimize server builds and enable dead code elimination. The team plans to make Forget open-source and is focused on ensuring its quality before release.
El Futuro de las Herramientas de Rendimiento
JSNation 2022JSNation 2022
21 min
El Futuro de las Herramientas de Rendimiento
Top Content
Today's Talk discusses the future of performance tooling, focusing on user-centric, actionable, and contextual approaches. The introduction highlights Adi Osmani's expertise in performance tools and his passion for DevTools features. The Talk explores the integration of user flows into DevTools and Lighthouse, enabling performance measurement and optimization. It also showcases the import/export feature for user flows and the collaboration potential with Lighthouse. The Talk further delves into the use of flows with other tools like web page test and Cypress, offering cross-browser testing capabilities. The actionable aspect emphasizes the importance of metrics like Interaction to Next Paint and Total Blocking Time, as well as the improvements in Lighthouse and performance debugging tools. Lastly, the Talk emphasizes the iterative nature of performance improvement and the user-centric, actionable, and contextual future of performance tooling.
Depuración de JS
React Summit 2023React Summit 2023
24 min
Depuración de JS
Top Content
Debugging JavaScript is a crucial skill that is often overlooked in the industry. It is important to understand the problem, reproduce the issue, and identify the root cause. Having a variety of debugging tools and techniques, such as console methods and graphical debuggers, is beneficial. Replay is a time-traveling debugger for JavaScript that allows users to record and inspect bugs. It works with Redux, plain React, and even minified code with the help of source maps.
Un Marco para Gestionar la Deuda Técnica
TechLead Conference 2023TechLead Conference 2023
35 min
Un Marco para Gestionar la Deuda Técnica
Top ContentPremium
Today's Talk discusses the importance of managing technical debt through refactoring practices, prioritization, and planning. Successful refactoring requires establishing guidelines, maintaining an inventory, and implementing a process. Celebrating success and ensuring resilience are key to building a strong refactoring culture. Visibility, support, and transparent communication are crucial for addressing technical debt effectively. The team's responsibilities, operating style, and availability should be transparent to product managers.
Construyendo un Asistente AI Activado por Voz con Javascript
JSNation 2023JSNation 2023
21 min
Construyendo un Asistente AI Activado por Voz con Javascript
Top Content
This Talk discusses building a voice-activated AI assistant using web APIs and JavaScript. It covers using the Web Speech API for speech recognition and the speech synthesis API for text to speech. The speaker demonstrates how to communicate with the Open AI API and handle the response. The Talk also explores enabling speech recognition and addressing the user. The speaker concludes by mentioning the possibility of creating a product out of the project and using Tauri for native desktop-like experiences.

Workshops on related topic

Uso de CodeMirror para construir un editor de JavaScript con Linting y AutoCompletado
React Day Berlin 2022React Day Berlin 2022
86 min
Uso de CodeMirror para construir un editor de JavaScript con Linting y AutoCompletado
Top Content
Workshop
Hussien Khayoon
Kahvi Patel
2 authors
Usar una biblioteca puede parecer fácil a primera vista, pero ¿cómo eliges la biblioteca correcta? ¿Cómo actualizas una existente? ¿Y cómo te abres camino a través de la documentación para encontrar lo que quieres?
En esta masterclass, discutiremos todos estos puntos finos mientras pasamos por un ejemplo general de construcción de un editor de código usando CodeMirror en React. Todo mientras compartimos algunas de las sutilezas que nuestro equipo aprendió sobre el uso de esta biblioteca y algunos problemas que encontramos.
Construyendo una Aplicación de Shopify con React & Node
React Summit Remote Edition 2021React Summit Remote Edition 2021
87 min
Construyendo una Aplicación de Shopify con React & Node
Top Content
Workshop
Jennifer Gray
Hanna Chen
2 authors
Los comerciantes de Shopify tienen un conjunto diverso de necesidades, y los desarrolladores tienen una oportunidad única para satisfacer esas necesidades construyendo aplicaciones. Construir una aplicación puede ser un trabajo duro, pero Shopify ha creado un conjunto de herramientas y recursos para ayudarte a construir una experiencia de aplicación sin problemas lo más rápido posible. Obtén experiencia práctica construyendo una aplicación integrada de Shopify utilizando el CLI de la aplicación Shopify, Polaris y Shopify App Bridge.Te mostraremos cómo crear una aplicación que acceda a la información de una tienda de desarrollo y pueda ejecutarse en tu entorno local.
Construye una sala de chat con Appwrite y React
JSNation 2022JSNation 2022
41 min
Construye una sala de chat con Appwrite y React
Workshop
Wess Cope
Wess Cope
Las API/Backends son difíciles y necesitamos websockets. Utilizarás VS Code como tu editor, Parcel.js, Chakra-ui, React, React Icons y Appwrite. Al final de este masterclass, tendrás los conocimientos para construir una aplicación en tiempo real utilizando Appwrite y sin necesidad de desarrollar una API. ¡Sigue los pasos y tendrás una increíble aplicación de chat para presumir!
Problemas difíciles de GraphQL en Shopify
GraphQL Galaxy 2021GraphQL Galaxy 2021
164 min
Problemas difíciles de GraphQL en Shopify
Workshop
Rebecca Friedman
Jonathan Baker
Alex Ackerman
Théo Ben Hassen
 Greg MacWilliam
5 authors
En Shopify a gran escala, resolvemos algunos problemas bastante difíciles. En este masterclass, cinco oradores diferentes describirán algunos de los desafíos que hemos enfrentado y cómo los hemos superado.

Tabla de contenidos:
1 - El infame problema "N+1": Jonathan Baker - Vamos a hablar sobre qué es, por qué es un problema y cómo Shopify lo maneja a gran escala en varios APIs de GraphQL.
2 - Contextualizando APIs de GraphQL: Alex Ackerman - Cómo y por qué decidimos usar directivas. Compartiré qué son las directivas, qué directivas están disponibles de forma predeterminada y cómo crear directivas personalizadas.
3 - Consultas de GraphQL más rápidas para clientes móviles: Theo Ben Hassen - A medida que tu aplicación móvil crece, también lo harán tus consultas de GraphQL. En esta charla, repasaré diversas estrategias para hacer que tus consultas sean más rápidas y efectivas.
4 - Construyendo el producto del futuro hoy: Greg MacWilliam - Cómo Shopify adopta las características futuras en el código actual.
5 - Gestión efectiva de APIs grandes: Rebecca Friedman - Tenemos miles de desarrolladores en Shopify. Veamos cómo estamos asegurando la calidad y consistencia de nuestras APIs de GraphQL con tantos colaboradores.
Construye Aplicaciones Modernas Utilizando GraphQL y Javascript
Node Congress 2024Node Congress 2024
152 min
Construye Aplicaciones Modernas Utilizando GraphQL y Javascript
Workshop
Emanuel Scirlet
Miguel Henriques
2 authors
Ven y aprende cómo puedes potenciar tus aplicaciones modernas y seguras utilizando GraphQL y Javascript. En este masterclass construiremos una API de GraphQL y demostraremos los beneficios del lenguaje de consulta para APIs y los casos de uso para los que es adecuado. Se requiere conocimiento básico de Javascript.
De 0 a Autenticación en una Hora para tu Aplicación JavaScript
JSNation 2023JSNation 2023
57 min
De 0 a Autenticación en una Hora para tu Aplicación JavaScript
WorkshopFree
Asaf Shen
Asaf Shen
La autenticación sin contraseña puede parecer compleja, pero es fácil de agregar a cualquier aplicación utilizando la herramienta adecuada.
Mejoraremos una aplicación JS de pila completa (backend Node.js + frontend Vanilla JS) para autenticar usuarios con contraseñas de un solo uso (correo electrónico) y OAuth, incluyendo:
- Autenticación de usuario: Gestión de interacciones de usuario, devolución de JWT de sesión / actualización- Gestión y validación de sesiones: Almacenamiento seguro de la sesión para solicitudes posteriores del cliente, validación / actualización de sesiones
Al final del masterclass, también abordaremos otro enfoque para la autenticación de código utilizando Flujos de Descope en el frontend (flujos de arrastrar y soltar), manteniendo solo la validación de sesión en el backend. Con esto, también mostraremos lo fácil que es habilitar la biometría y otros métodos de autenticación sin contraseña.