Mi opinión sobre la reescritura de Bun en Rust
(en.liujiacai.net)- La reescritura de Bun en Rust se parece más a una decisión de moverlo a un stack tecnológico más convencional manteniendo la arquitectura y las estructuras de datos existentes hechas en Zig
- El PR de la reescritura tuvo una escala de 6,755 commits; se abrió el 8 de mayo y se fusionó el 14 de mayo, lo que deja dudas sobre la profundidad de la revisión para un cambio de runtime de nivel de producción
- Que las pruebas pasen solo valida rutas conocidas, y es difícil que garantice también invariantes globales como rutas de error, concurrencia o condiciones extremas de memoria
- El punto clave no es un fracaso de Zig, sino un desajuste estructural entre la cultura del equipo de Bun, que prioriza lanzar rápido, y el costo de la gestión manual de memoria
- La apuesta real no es Zig vs Rust, sino si se puede mantener a largo plazo código generado por IA y no suficientemente revisado
La base de Bun construida con Zig
- Antes de ver el PR de la reescritura de Bun en Rust, vale la pena recordar que Zig tuvo un papel importante en que Bun llegara a donde está hoy
- Jarred eligió Zig no porque “se viera genial”, sino porque permitía a un equipo pequeño crear rápidamente el prototipo de un runtime de JS de alto rendimiento sin garbage collector
- La baja fricción de Zig, la manipulación directa de memoria y su sencilla interoperabilidad con C hicieron posible el rendimiento inicial de Bun y el tamaño reducido del equipo
- Como dijo Jarred, “la arquitectura no cambia, y las estructuras de datos tampoco”, así que la reescritura en Rust se parece más a una estructura que hereda el armazón construido en Zig
- Construir la base con Zig, lanzar el producto, conseguir inversión y luego, después de ser adquirida y crecer, mover la empresa a un stack más convencional puede verse como una decisión de negocio normal
- Pero es difícil presentar eso como una prueba de que Zig en sí no era adecuado
El riesgo de una reescritura masiva fusionada en 6 días
- El PR de la reescritura dejó un registro de 6,755 commits, con el nombre de rama
claude/phase-a-port, abierto el 8 de mayo y fusionado el 14 de mayo - El problema central es que una reescritura completa de un runtime de JS de nivel de producción se fusionó en 6 días
- Un principio básico de la ingeniería de software es que “el código que no entiendes no debería ejecutarse en producción”
- Ese principio no existe porque el código necesariamente tenga bugs, sino porque cuando aparezcan, ya no sabrás por dónde empezar a revisar; por eso es una línea base de mantenibilidad
- En la lista de revisores del PR estaban
coderabbitai[bot]yclaude[bot], y el único revisor humano,alii, seguía en estado “Awaiting requested review” - El bucle cerrado en el que Claude escribe y Claude revisa no es algo lógicamente imposible, pero en la práctica significa que ningún humano leyó de verdad toda la base de código hasta el final
Lo que pasar las pruebas no puede garantizar
- Aunque la suite de pruebas pase en todas las plataformas, eso solo valida la corrección de comportamientos conocidos y rutas conocidas
- Es difícil que una suite de pruebas garantice suficientemente las siguientes áreas
- si las rutas de error se manejan correctamente
- qué comportamiento aparece en condiciones límite bajo estrés
- si la consistencia del estado se mantiene en escenarios de concurrencia
- si el modelo de memoria coincide con la intención bajo condiciones extremas
- También se resume que Jarred reconoció que los problemas de memoria al reingresar el límite de JS no pueden ser resueltos por el compilador de Rust y siguen dependiendo de humanos
- El problema es que la parte que depende de humanos no fue revisada por humanos
- La traducción de código por IA se parece más a una equivalencia semántica local, ajustando cada función para que se comporte igual que el original de forma aislada
- Los invariantes globales entre funciones y las restricciones de diseño que no están escritas en las pruebas y solo existen en la cabeza del autor original son difíciles de garantizar solo con una traducción por IA
- Esas restricciones pueden no aparecer en las pruebas actuales y manifestarse seis meses después como un fallo difícil de explicar bajo cierta carga de producción
- Esto no es solo un problema de Claude; también aplica a cualquier herramienta y a cualquier programador humano que traduzca sin revisión suficiente
- A una escala de 6,755 commits, ese riesgo se amplifica mucho
Quién carga con el riesgo después de la adquisición
- Al inicio, Bun era un proyecto en el que Jarred apostaba por sí mismo, y el uso de Zig, la iteración rápida y la aceptación de deuda técnica podían entenderse con la lógica de una startup donde uno mismo asume el riesgo
- Ahora que Bun fue adquirido por una gran empresa y tiene una base de usuarios que lo usa en sistemas reales de producción, quien carga con el riesgo de la reescritura ya no es Jarred, sino los ingenieros que ejecutan Bun en producción y los usuarios detrás de ellos
- Jarred dice que esa versión todavía es canary y que antes del lanzamiento oficial aún faltan optimizaciones y trabajo de limpieza
- Canary es una línea de defensa, pero no sustituye la revisión humana
- La optimización y la limpieza son temas de calidad de código; no resuelven si los mantenedores realmente entendieron el código
- Una base de código que nadie del equipo ha leído por completo sigue siendo una caja negra para quien la mantiene, incluso si las pruebas son amplias o el periodo canary es largo
- Este problema puede convertirse en dolor real más adelante, cuando toque depurar un bug serio
El error al diagnosticar un problema de Zig
- La razón previa que dio Jarred fue que la base de código en Zig tenía muchos use-after-free, double-free y fugas de memoria en rutas de error
- Ese diagnóstico en sí es correcto, pero de ahí es difícil concluir que “Zig no funciona”
- Un diagnóstico más preciso sería que, en un proyecto comercial que prioriza la iteración rápida, el costo cognitivo de la gestión manual de memoria superó el presupuesto del equipo
- Eso puede verse no como un bug de Zig, sino como un desajuste estructural entre los objetivos de diseño de Zig y el modelo de negocio de Bun
- El usuario objetivo de Zig es un programador de sistemas que sabe lo que hace y está dispuesto a pagar ese costo a cambio del control final
- TigerBeetle escribió una base de datos en Zig prácticamente sin bugs de memoria, y se resume que eso fue posible porque la cultura del equipo y la naturaleza del proyecto encajaban con la filosofía de Zig
- La cultura del equipo de Bun se parece más a iterar rápido, lanzar rápido y corregir bugs rápido, y eso está en una relación de tensión fundamental con la estricta disciplina de memoria que exige Zig
- Interpretar “nuestro equipo se equivoca seguido con esta herramienta” como “esta herramienta no sirve” se parece más a un error de atribución
- Se usa la analogía de que si el martillo no era la herramienta correcta, eso no significa que el martillo tenga la culpa
Perspectiva a corto plazo y riesgo a largo plazo
- A corto plazo, es muy probable que la versión reescrita esté mayormente bien
- Las rutas principales están cubiertas por pruebas, los problemas evidentes aparecerán durante la etapa canary, y las garantías del compilador de Rust eliminan una clase de bugs de memoria
- En la superficie, todo puede parecer normal
- A largo plazo, 6,755 commits que ningún humano ha leído por completo siguen siendo un riesgo estructural
- Si dentro de seis meses aparece un bug extraño de concurrencia, o una condición límite bajo cierta carga provoca un comportamiento anómalo, el ingeniero que depure eso se enfrentará a un sistema que nadie llegó a entender de verdad
- Decir que es un sistema nunca entendido no significa que no tenga bugs, sino que cuando aparezcan, nadie sabrá por qué ocurrieron
- La verdadera apuesta técnica de esta reescritura no es Zig vs Rust, sino si se puede dar mantenimiento a largo plazo en producción a código generado por IA y no revisado
- Esa pregunta es más compleja que “todas las pruebas pasan” y más profunda que “la seguridad de memoria de Rust”
- La conclusión se resume en la analogía: “Zig construyó la base, Claude levantó el edificio y el revisor humano todavía viene en camino”
- Cuánto tiempo seguirá siendo habitable ese edificio dependerá de si alguien puede leer los planos cuando aparezca la primera filtración
1 comentarios
Opiniones en Lobste.rs
Antes de debatir “reescribamos Bun en Rust”, hay que decir que Bun llegó hasta donde está gracias a Zig
Jarred, el creador de Bun también lo está diciendo. Dice que Zig hizo posible a Bun, y que Zig tuvo mucho mérito en que un proyecto en el que estuvo programando solo durante un año en un cuarto apestoso de Oakland creciera hasta convertirse en una de las herramientas más usadas del ecosistema JavaScript
También dice que Zig es un gran lenguaje y que Bun le debe mucho de su éxito, pero que otros proyectos como Ghostty o Tigerbeetle no sufrieron los problemas de estabilidad que tuvo Bun
Normalmente, una base de datos tiene desafíos de estabilidad mucho mayores que un runtime de lenguaje
Este artículo huele mucho a que lo escribió un LLM
Así que esa sensación también podría ser una huella de traducción automática
Si el usuario objetivo de Zig es “un programador de sistemas que sabe lo que hace y está dispuesto a pagar el precio por el control absoluto”, se ve como una sobreconfianza estilo C/C++ reapareciendo en el contexto de lenguajes surgidos después de Rust y Swift
Si Jarred dijo que una de las razones del cambio fue que “había demasiados use-after-free, double-free y fugas de memoria en rutas de error en la base de código Zig”, entonces esto sirve como evidencia sobre si se puede volver prácticamente seguro un lenguaje sin seguridad de memoria solo haciendo que un LLM busque con ganas bugs de seguridad de memoria
Incluso las propias empresas de LLM no tomaron ese camino aquí
La frase “como el código lo escribió Claude y lo revisó Claude, aunque el circuito cerrado no es lógicamente imposible, significa que ningún humano ha leído realmente toda esta base de código” claramente no parece correcta
Si una base de código Zig escrita por humanos se tradujo mecánicamente a Rust, alguien que entiende el código original también puede entender el nuevo código. No es como si lo hubieran pasado a APL; ambos son lenguajes procedurales de la tradición sintáctica de C
El punto de que, si en el futuro se deja correr a los LLM sin supervisión, el código podría alejarse cada vez más de la intuición humana, sigue abierto, pero la base de código en su estado actual todavía parece comprensible dentro de lo esperable para un runtime de JavaScript de un millón de líneas y una herramienta todoterreno de binario único
La frase “la IA solo acierta la equivalencia semántica local a nivel de función y no entiende los invariantes globales entre funciones” suena rara tanto desde una postura favorable a los LLM como desde una crítica
Los LLM no son lo bastante deterministas como para garantizar que cada función se comporte igual que el original. Para esa clase de garantía se necesitan herramientas como
c2rust. Un LLM puede traducir código que se vea como el original, pero evitar que cambie((abc & 45) << 3) == 360por((abc & 45) << 30) == 360depende solo del compilador, la suite de pruebas y quizá la detección probabilística de una revisión de código basada en LLMAl revés, si existiera un traductor que, como
c2rust, garantizara la equivalencia de cada función y además, como un LLM, preservara comentarios y estructura, entonces sería un traductor perfecto y podría portar automáticamente incluso una base de código de un millón de líneas. Un compilador también puede verse como un caso especial de esto, y Clang, aunque no está libre de bugs, está lo suficientemente cerca como para que la gente confíe en él. Si un LLM pudiera traducir Zig o C++ a Rust con la confiabilidad de Clang, Chrome ya sería Rust puro a finales de este mesAdemás, codificar invariantes entre funciones es precisamente el punto central de un sistema de tipos. Una de las razones para reescribir Bun en Rust también es que el sistema de tipos de Rust puede expresar mejor invariantes complejos. No es que Anthropic haya compilado todo a ensamblador y luego quemado el código fuente
Bun viene siendo vibe coded desde mucho antes del port a Rust. Adoptó la IA bastante rápido y, desde la adquisición por parte de Anthropic, casi todos los commits los escribe un bot. Jarred también tuiteó que le hizo escribir funciones a una IA durante el fin de semana y así agregó varias funcionalidades
HTML Parsers in Portland analiza varias implementaciones de parsers HTML de Python y muestra que uno de los algoritmos centrales fue implementado de formas muy distintas en cada port. En todos los casos era posible hacer un port mecánico, pero en la práctica no se hizo así
Claro, ese es un caso de principios de este año y el proceso fue distinto, pero algunos fragmentos que vi en la base de código de Bun después del port parecen sufrir problemas parecidos
Pero el hecho de que “los LLM no son lo bastante deterministas como para garantizar que cada función se comporte igual que el original” termina llevando a la conclusión de que ningún humano ha leído realmente toda la base de código
Un ejemplo de “todas las pruebas pasan”: https://github.com/oven-sh/bun/…
Viendo que varias personas en otros foros enlazaron el mismo commit, da la impresión de que alguien vio ese enlace en algún lado, sintió que encajaba con lo que esperaba, y después no verificó si realmente tenía relevancia. Creo que deberíamos exigirnos un estándar más alto
Primer commit: “await process exit / JSON-parse-retry instead of fixed sleeps”
Reversión: “test: revert proc.exited change in spawn.test.ts, keep isDebug iteration count”
Últimamente he estado pensando mucho en el principio de “no deberías ejecutar en producción código que no entiendes”
Mi carrera ya va bastante avanzada, pero deliberadamente no me fui hacia puestos de management, y mi trayectoria como programador cada vez apuntaba más hacia las capas bajas del stack. Es porque me gusta entender a fondo el programa real en sí. Lanzar funcionalidades y mejorar la vida de los usuarios también es muy importante, pero una de las grandes recompensas internas de programar es la sensación de aprender verdades reales sobre sistemas reales
Para alguien como yo, la idea de que un humano debe entender cada línea de un programa se siente casi como un axioma. Pero en el organigrama, mi manager es responsable de los programas que yo mantengo. Es un gran manager y no hace micromanagement, así que obviamente no entiende cada línea del software que el equipo lanza. De hecho, ni siquiera sé si ha leído mucho código. Entonces, en ese sentido, él estaría violando ese principio
Me he estado preguntando si hay una diferencia significativa entre “código escrito por subordinados que yo no entiendo” y “código escrito por mi IA que yo no entiendo”
La opción 1 me parece aceptable, pero la 2 me da mala espina. ¿La diferencia será solo si hay un ser humano que responde por ese código? ¿Si hay alguien a quien se pueda culpar? Todavía no sé si eso basta para justificar la fuerte intuición moral que me genera
Me preocupa que esta emoción tan fuerte no sea esencial para una buena ingeniería, sino más bien una preferencia estética personal. Cada quien puede tener sus gustos, pero si eso es todo, entonces supongo que hay que esperar que esta parte del trabajo se vuelva menos disfrutable en el futuro. Al final sería como que me empujaran hacia management, solo que mis subordinados serían bots
Se dice que “Zig permitió que un equipo pequeño prototipara rápido un runtime de JS de alto rendimiento sin recolector de basura ni runtime pesado”, pero otros runtimes importantes como Node y Deno también hacen lo mismo
Ambos envuelven motores JS usando C++ y Rust, que también son lenguajes sin recolector de basura. No tengo claro si V8 o JSC en sí distribuyen realmente un recolector de basura, pero eso se sale del punto central
Todo el repositorio de Bun se siente distópico. Bots hablándose entre sí mientras crean PRs absurdos
Ej.: https://github.com/oven-sh/bun/issues/30766
La velocidad a la que esto fue considerado “terminado” sí es bastante impactante, pero no me parece un choque de trenes en cámara lenta como el artículo lo describe sin pruebas sólidas
Lo de “si dentro de 6 meses aparece un bug raro de concurrencia y, bajo cierta carga, una condición de borde provoca un comportamiento extraño, el ingeniero que depure eso se enfrentará a un sistema que nadie entendió realmente jamás” es pura especulación y no se presentaron hechos
El port de lenguaje es un área que encaja bien con los LLM, y mucha gente ya entendía el código base. No veo por qué un simple port de lenguaje de pronto haría imposible recuperar la capacidad de diagnosticar el sistema