De Rust para Ruby
(xlii.space)- Um experimento pessoal de projeto para migrar um crate de webapp em Rust para Ruby on Rails, com alvo de 14.943 linhas de código baseadas em Tera e Axum
- A configuração atual em Rust exige Playwright E2E, namespaces de banco de dados isolados, serviços mockados e até um crate interno de API, o que eleva o custo de testes
- Na comparação entre LLMs, Rails obteve 710 pontos no total, acima dos 480 de Rust/Axum/Diesel, sendo avaliado com vantagem em velocidade de desenvolvimento e facilidade para testes unitários
- A conversão em one-shot com Local Qwen3.6 levou cerca de 30 minutos, e o código Ruby caiu para 3.322 linhas, mas ainda não foi validado em execução
- Rails tem como pontos fortes os recursos nativos e testes mais concisos, enquanto a falta de segurança de tipos no Ruby pode ser compensada com Sorbet ou adição de tipos baseada em agentes
Contexto do experimento de migração
- Um crate de webapp em Rust, parte de um projeto pessoal, foi escolhido como alvo da migração para Ruby on Rails
- O projeto inteiro tem cerca de 30 mil linhas, e o crate em questão é mais próximo de um webapp escrito com Tera e Axum
- O código Rust alvo da migração soma 14.943 linhas e leva cerca de 10 segundos para compilar
- O código em si não é grande, mas a estrutura arrasta muitas dependências
- A configuração atual em Rust tem alto custo de testes
- Os testes E2E exigem configuração de Playwright
- Como é difícil fazer mocking, são necessários namespaces isolados de banco de dados e serviços mockados
- Também é necessário um crate interno de API separado para que o Playwright interaja com o app em modo headless
- Ruby e Ruby on Rails foram considerados como uma alternativa mais concisa
- Ruby não tem tipagem, então sua estabilidade pode ser inferior à do Rust
- Com Sorbet, é possível compensar parcialmente a segurança de tipos também no Ruby
- Ao comparar complexidade, estabilidade, facilidade de testes e outros fatores com várias instâncias de LLM, Rails apareceu com pontuação mais alta
- A soma de Rust/Axum/Diesel foi 480, Rails ficou em 710 e Rails + Sorbet em 695
- Rails recebeu notas altas em adequação para desenvolvedor individual 90, velocidade de desenvolvimento 90 e facilidade de testes unitários 90
- Rust/Axum/Diesel teve notas altas em segurança 95 e desempenho 95, mas baixas em facilidade de testes unitários 20 e testes de integração 30
- Pelo critério de soma simples, concluiu-se que um app em Rails poderia gerar um resultado 1,47 vez melhor
Resultado da conversão e pontos de análise
- Foi feita uma conversão em one-shot de um projeto relativamente pequeno com Local Qwen3.6
- A conversão levou cerca de 30 minutos
- Ainda não foi executado, então não foi confirmado se realmente funciona
- A maior mudança foi a redução no número de linhas de código
- Total de linhas dos arquivos Rust: 14.943 linhas
- Total de linhas dos arquivos Ruby: 3.322 linhas
- Houve uma redução de 77%, e 1 linha de Ruby equivale a cerca de 4,49 linhas de Rust
- O código Ruby convertido parece limpo e idiomático dentro do que foi analisado rapidamente
- Ainda pode haver bugs
- Ele será revisado com mais cuidado depois
- Outros pontos de análise são complementação de tipos, recursos nativos do Rails e simplificação dos testes
- Adicionar tipos com ajuda de agentes pode aliviar o problema de segurança de tipos
- Ruby/Rails é visto como algo mais próximo de “batteries + kitchen sink included”, e melhor do que 3 GiB de dependências compiladas
- A expectativa é que os testes fiquem muito mais fáceis
- O exemplo de teste em Ruby envolve a chamada ao LLM com
VCR.use_cassette("llm_call")e verifica o tamanho do resultado em uma forma curtaVCR.use_cassette("llm_call") do result = LlmClient.match(entry, data_list) expect(result.results.size).to eq(data_list.size) end - O exemplo de teste em Rust é mais longo e exige implementar diretamente um provedor mockado
- Usa
Arc<RwLock<Vec<Response>>>,AtomicUsize,async_trait,tokio::teste outros - É criado um
MockProviderpara gerenciar a lista de respostas e a contagem de chamadas, depois implementa-se omatchdo traitProvidere, no teste, validam-se o resultado e o número de chamadas
- Usa
- Por ser um projeto pessoal, é possível tomar decisões mais ousadas, e a migração de Rust para Ruby será analisada com cuidado daqui para frente
1 comentários
Comentários no Hacker News
Difícil de acreditar. Soa como: “Tinha uma coceira técnica que eu queria resolver, e uma IA local terminou o trabalho em 30 minutos. Nem cliquei em Start para ver se rodava, mas escrevi um post no blog...”
Claro, isso se não tiver sido impulsionado por bots
2026: vejam este trabalho que eu não escrevi!
2036: como escrevi 200 linhas em C, uma antiga língua latina
No começo achei que seria um texto interessante, mas perdi o interesse na hora em que apareceu a parte de usar LLM na conversão. É parecido com “eu queria fazer isso, então mandei um subordinado fazer, e agora vou contar essa história”
Como ele nem fez a conversão por conta própria nem pensou profundamente sobre ela, não vejo muito motivo para ler
truehardcodedAí, se você só roda um smoke test, pode parecer que deu tudo certo
Fora a programação artesanal, a linguagem de programação em si vai importar cada vez menos
À medida que os LLMs melhorarem, no fim tudo vai virar uma questão de decidir em que tipo de linguagem gerar a especificação
A turma de UML e RUP conseguiu sua vingança
Como disseram em outros comentários, ele fez uma revisão bem ampla. Não era um projeto grande, então tirando algumas partes espinhosas, a maior parte era um app web
Acho injusto dizer que ele “não pensou”. Não foi apertar um botão e YOLO
Ele investigou os trade-offs e os resultados, a diferença entre os trechos em Rust e em Rails era de fato grande, e a testabilidade do app em Rust foi algo sobre o qual ele refletiu por 2 meses
Como dizem os fãs de LLM, contexto importa ;)
Não sei se existe alguma linguagem e framework que priorize tanto a felicidade do desenvolvedor quanto Ruby on Rails
É alguma coisa composta em algum lugar, impossível de localizar, e no fim você para o que estava fazendo para passar uma hora lendo documentação. Para quem usa Rails o dia inteiro isso pode ser ok, mas convenção sobre configuração é um antipadrão enorme para mim
Felicidade nem sempre vira desempenho. Isso me lembra o famoso caso do logo do Twitter antes da migração para JVM e Scala
Ruby on Rails ficou famoso, mas eu já tinha visto experiência parecida com AOLServer e Vignette baseados em Tcl
Num startup português, eles também fizeram sua própria variação, e depois os fundadores criaram o OutSystems. Era uma das primeiras ferramentas gráficas de RAD para desenvolvimento de sites e sistemas distribuídos, voltada para infraestrutura JVM ou CLR com low-code/no-code
Ainda assim, é bom ver JIT no CRuby agora vindo por padrão
Já criei um conjunto de gems chamado propel_rails que leva o já conciso código de Ruby on Rails ainda mais longe. Ele gera classes-base como controller de API e concern, e a partir daí produz um recurso RESTful completo (model, controller, serializer, testes unitários e testes E2E) sem boilerplate nenhum
No fim, os controllers ficam só com a lista de atributos permitidos pela API, porque as ações RESTful são geradas automaticamente. É um pouco difícil explicar por completo, mas o poder da metaprogramação em Ruby torna coisas realmente impressionantes fáceis de fazer
Funciona tendo o model de domínio como referência?
Estou numa situação parecida
Gosto de Go e Rust, e ambas são ótimas linguagens com seus prós e contras. Mas infelizmente não consegui construir um app SaaS com nenhuma das duas. É como enfiar uma peça quadrada num buraco redondo
Posso estar muito errado, mas ferramentas SaaS vêm com um monte de traquitanas embutidas e eu não quero reinventar isso tudo
RoR é “bom o suficiente”. Você pode introduzir tipos quando quiser, dá para construir rápido e as ferramentas são razoáveis
Meu primeiro trabalho profissional foi com PHP, mas havia armadilhas demais. Ruby parecia um pouco mais voltado para e-commerce, o que achei interessante, e se é bom o bastante para a Shopify, então para mim está ótimo
Se faz sentido trocar de Rust para Ruby, então ter escolhido Rust no começo já foi um erro
Quem acha que Ruby é mais lento que Rust provavelmente se surpreenderia ao descobrir que Ruby hoje em dia na prática é mais rápido que Python, embora ainda seja mais lento que Go ou Rust
Mas quando você tem vários workers em background e cada um começa a consumir mais de 2 GB de memória, isso se acumula muito rápido
Escrevi um serviço Rust em produção, e mais impressionante do que a velocidade foi o fato de ele rodar com 30 MB de memória
É um argumento provocativo, mas embora possa servir para ostentar um QI 900+ para os camponeses ao redor, muita gente inteligente e talentosa em desenvolvimento não gosta muito de Rust. Alguns prefeririam criar a própria linguagem de programação e o próprio compilador a escrever uma linha de Rust
Lembro de Jonathan Blow com Jai e Ginger Bill com Odin
Há ainda muitos outros com criatividade e profundidade comprovadas, que criaram bibliotecas e frameworks bonitos e amplamente usados, mas não quero desperdiçar espaço aqui com isso
Só que Rust tem um clube machão bem legal e uma irmandade muito unida
Claude funciona muito bem com apps Rails. Como o autor do texto também apontou, Ruby permite fazer muita coisa com pouco código, e Rails usa convenção sobre configuração, então apps Rails ficam ainda mais concisos
Uma hipótese para Claude escrever tão bem apps Rails é a eficiência de tokens
Vi um projeto que tentava medir e comparar a eficiência de tokens por projeto, e Rails se saiu bem
https://felipemrvieira.github.io/SyntaxTax/dashboard/
Às vezes me surpreendo com o tamanho dos projetos. Uma base de código de 30 mil linhas é pequena? Eu sei que o teto pode ser muito alto, mas 30 mil linhas já conseguem concentrar uma quantidade enorme de informação e sutilezas de comportamento
Talvez seja por causa da minha formação mais focada em backend/rede com Go. Quando passa de 10 mil a 15 mil linhas, normalmente já fica bem difícil manter o modelo mental do codebase inteiro na cabeça, e isso sempre me pareceu bem pesado