- Quando vazamentos e falhas continuaram ocorrendo em Zig, que não tem segurança de memória, o Bun migrou 535.496 linhas de código para Rust com 64 agentes de IA, reduzindo para 11 dias um trabalho que levaria de 1 a 2 anos
- O ponto de partida do sucesso foi um
PORTING.mdde 600 linhas, e o processo seguiu esta ordem: conversão paralela por arquivo, duas revisões adversariais, correção de erros de compilação, testes locais e aprovação no CI - Para gerar 6.500 commits, foram usados US$ 165 mil em preços de API, além de 5,9 bilhões de tokens de entrada sem cache, 690 milhões de tokens de saída e 72 bilhões de leituras de tokens de entrada em cache
- Se fosse manual, estimou-se que 3 engenheiros com profundo conhecimento da base de código teriam de parar por cerca de 1 ano de melhorar o produto, corrigir bugs e falhas de segurança e desenvolver novos recursos, o que tornaria a própria reescrita difícil de viabilizar
- Para repetir a mesma abordagem, é preciso ter um engenheiro que entenda profundamente a base de código, uma suíte de testes forte o suficiente para confiar no resultado e disposição para bancar o custo em tokens mesmo sem garantia de sucesso
Por que o Bun escolheu uma reescrita em Rust
- O Bun é um projeto de produção complexo que oferece vários recursos além de um runtime JavaScript
- Transformação, bundling e minificação de JavaScript, TypeScript e CSS
- Test runner e gerenciador de pacotes compatível com npm
- Resolução de módulos, cliente WebSocket, implementação de Node.js e vários módulos
- Tem 22 milhões de downloads mensais, é dependência do Claude Code e do OpenCode, e recebe suporte direto de Vercel, Railway e DigitalOcean
- Como Zig não é uma linguagem com segurança de memória, mesmo nas versões mais recentes do Bun continuavam ocorrendo vazamentos de memória, falhas causadas por problemas de memória e escritas fora dos limites do heap
- A equipe do Bun aplicou patches no compilador Zig e introduziu testes de vazamento de memória de ponta a ponta, mas não conseguiu eliminar o problema
- No processo de lidar ao mesmo tempo com a vida útil de valores com garbage collection e de valores gerenciados manualmente, surgiam pequenos vazamentos e falhas intermitentes
- Era preciso revisar, em cada alocação de memória, onde ela seria liberada, se havia double-free, o tratamento de exceções JavaScript e a visibilidade de ponteiros para o scanner conservador de stack
- Em Rust seguro, use-after-free e double-free viram erros de compilação, e problemas de esquecer liberações em caminhos de erro podem ser tratados com limpeza automática baseada em
Drop - Também foi avaliada a possibilidade de introduzir ponteiros inteligentes ao estilo Rust no código do Bun, mas isso teria pior usabilidade do que Rust e não ofereceria as mesmas garantias
Por que projetos de reescrita costumam demorar
- Durante a reescrita, novos recursos continuam sendo adicionados à base original, então a conclusão tende a ser adiada repetidamente
- Um trabalho estimado em 9 meses pode ainda precisar de mais 6 meses ao fim desses 9 meses
- Mesmo após 15 meses, ainda podem restar vários meses de trabalho só para alcançar os novos recursos
- Mesmo com sorte, seria necessário congelar recursos por 2 meses e concluir em cerca de 18 meses, fazendo a estimativa inicial de 9 meses virar mais de 2 anos
- O código Zig do Bun, sem contar comentários, tem 535.496 linhas, então estimou-se que uma pequena equipe de engenharia levaria cerca de 1 ano para migrá-lo para outra linguagem
- Como não era realista passar 1 ano sem melhorias visíveis para o usuário, decidiu-se testar com a Fable se seria possível validar em uma semana a viabilidade da migração para Rust
Projeto prévio e validação da migração
- Na primeira etapa, discutiu-se com Claude por cerca de 3 horas como mapear padrões de Zig para equivalentes próximos em Rust, e isso foi organizado em um
PORTING.mdcom 600 linhas - As diretrizes de migração incluíam restrições específicas para preservar a estrutura de execução existente do Bun
- Não usar
tokio,rayon,hyper,async-trait,futures - Proibir módulos com acesso a I/O como
std::fs,std::net,std::process - Como o Bun controla seu próprio event loop e suas system calls, usar callbacks e máquinas de estado como no Zig existente em vez de
async fn - Se houver conflito com o borrow checker, armazenar os valores escalares necessários em variáveis locais, encerrar o empréstimo e então emprestar novamente
- Proibir o uso de ponteiros brutos para contornar o borrow checker e deixar notas de migração nos pontos em que a estrutura foi alterada
- Não usar
- Dos 1.448 arquivos no total, 3 arquivos foram reescritos primeiro e depois Claude fez duas revisões adversariais em uma sessão separada da sessão de alteração
Trabalho paralelo com 64 agentes de IA
- O trabalho foi dividido para que os arquivos pudessem ser tratados de forma independente, e 64 agentes de IA foram executados em paralelo
- No início, houve conflitos porque vários agentes mexiam ao mesmo tempo no mesmo estado do repositório
- Um agente executava
git stash, depois outro executavagit stash popegit reset HEAD --hard - Atribuir um worktree separado a cada agente esbarrava na falta de espaço em disco por causa do tamanho do repositório do Bun, além da restrição de que as mudanças precisariam ser compiladas juntas no fim
- Um agente executava
- O workflow foi corrigido para proibir comandos Git como
git stashegit reset, exceto comandos que faziam commit imediato de arquivos específicos, e também para impedir o uso decargoe de comandos com longa duração - No fim, o trabalho foi dividido em 4 worktrees, cada um com 16 instâncias do Claude fazendo commits e push de arquivos
- Em dois dias, os agentes migraram 535.496 linhas de código Zig, e cada commit passou por duas revisões adversariais antes de ser aplicado
Correção de erros de compilação e testes
- A conversão inicial terminou, mas o código não compilava, então Claude corrigiu os erros por crate, a unidade superior de compilação em Rust
- O título da etapa fala em cerca de 1.600 erros de compilação, mas a citação diz que, ao resolver dependências circulares, surgiram cerca de 16.000 erros
- O processo de correção também foi paralelizado
- Executar
cargo checkem cada crate - Agrupar a saída por arquivo e salvar os arquivos de erro
- Corrigir todos os erros de compilação daquele crate
- Dois revisores adversariais verificam as mudanças
- Um agente responsável por correções aplica o resultado da revisão
- Executar
- Os agentes corrigiram erros de compilação da meia-noite até 11h30 da manhã sem intervenção humana
- Depois disso, foram necessários cerca de dois dias para fazer a enorme suíte de testes rodar localmente sem erros de compilação, e mais alguns dias para corrigir testes que falhavam e passar no CI
- Depois que todos os testes passaram e o funcionamento foi confirmado, as mudanças foram mescladas, totalizando 11 dias do planejamento à conclusão
- Cerca de 550 mil linhas de código migradas
- 6.500 commits
- 64 agentes usados
Custos e comparação com trabalho manual
- Pelo preço da API da Fable, o custo total da reescrita foi de US$ 165 mil
- 5,9 bilhões de tokens de entrada sem cache
- 690 milhões de tokens de saída
- 72 bilhões de leituras de tokens de entrada em cache
- A Anthropic vende tokens de API com margem, então o custo interno real seria menor
- O custo de API é parecido com o salário-base anual de um engenheiro de software corporativo de nível intermediário nos EUA, mas avalia-se que um único engenheiro nessa faixa salarial não conseguiria entregar o mesmo resultado em 11 dias
- Isso também bate com a avaliação de Mitchell Hashimoto de que a Fable se destaca especialmente em tarefas difíceis e concentradas com uma função de recompensa clara
- Se fosse manual, seriam necessários cerca de 3 engenheiros que conhecessem totalmente a base de código por aproximadamente 1 ano
- Nesse período, seria difícil avançar em compatibilidade com Node.js, correção de bugs e falhas de segurança e implementação de novos recursos
- A alternativa realista seria não reescrever e continuar corrigindo os bugs de memória existentes
Condições para aplicar isso em outros projetos
- Se a IA consegue reduzir para uma semana uma reescrita ou migração que levaria 1 ano, projetos antes difíceis de considerar também passam a ser viáveis
- Para reutilizar o fluxo de trabalho do Bun, são necessárias três condições
- Um engenheiro que conheça muito bem a base de código e tenha forte disposição para conduzir o trabalho
- Uma suíte de testes forte o bastante para que passar nos testes seja uma base confiável do funcionamento real
- Disposição para investir um custo considerável em tokens mesmo sem saber de antemão se dará certo
- Como tarefas repetitivas como migração de código costumam ser relativamente bem tratadas por LLMs, as chances de sucesso são altas se houver bons testes e um engenheiro para estruturar o problema
- Nem todo projeto precisa de US$ 165 mil
- Em projetos mais simples, o custo pode ser menor
- É possível usar o modelo mais caro no planejamento de alto nível e modelos mais baratos para codificação e revisão
- As migrações baseadas em IA estão ficando mais rápidas, mas velocidades como a do Bun só podem ser alcançadas em projetos bem projetados do ponto de vista de engenharia
Ainda não há comentários.