1 pontos por GN⁺ 20 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • 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 curta
      VCR.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::test e outros
    • É criado um MockProvider para gerenciar a lista de respostas e a contagem de chamadas, depois implementa-se o match do trait Provider e, no teste, validam-se o resultado e o número de chamadas
  • 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...”

    • Estar em 1º na página inicial agora significa que não importa se o projeto realmente funciona. Os leitores provavelmente também nem leram direito o texto
      Claro, isso se não tiver sido impulsionado por bots
    • 2016: vejam esta nova biblioteca JavaScript!
      2026: vejam este trabalho que eu não escrevi!
      2036: como escrevi 200 linhas em C, uma antiga língua latina
    • Mais do que “difícil de acreditar”, isso está bem perto de ser algo bastante normal em 2026
    • Mas ele revisou por 5 horas. Então ¯\(ツ)
  • 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

    • O maior problema é que o autor nem sequer validou. Já vi ferramenta grande combinando vários modelos rodar uma conversão por 6 horas e, quando você verifica manualmente como ela tratou cálculo ou lógica complicada, aparecem stubs ou retornos true hardcoded
      Aí, se você só roda um smoke test, pode parecer que deu tudo certo
    • Um problema ainda maior é que é assim que o desenvolvimento de software vai seguir daqui para frente
      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
    • O ponto não é se ele escreveu o código com as próprias mãos, e sim que ele viu as diferenças e fez uma escolha que provavelmente não era a ótima
      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

    • Raramente fui tão infeliz quanto quando trabalhei em projetos Rails. Você vê um bug no site, roda um grep tentando achar a view que está renderizando errado. Encontra a chamada do método que renderiza aquela seção, faz grep de novo pelo nome do método e o resultado é zero
      É 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
    • Tenho uma sensação parecida com Elixir e Phoenix, mas sem o dispositivo de atirar no próprio pé chamado method_missing
    • Mesmo que não pareça atraente em comunidades com gosto de Vale do Silício, já trabalhei de forma bem satisfatória com frameworks Java e .NET
      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
    • No máximo, é felicidade de curto prazo, e quase sempre ao custo de todas as outras características arquiteturais: manutenção, desempenho, confiabilidade, escalabilidade etc.
  • 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

    • Isso parece uma forma refinada de CRUD
      Funciona tendo o model de domínio como referência?
    • Dá para encontrar no rubygems, mas o link para GitHub apontado lá retorna 404
  • 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

    • Isso resume muito bem o texto, e também é o motivo de eu ter decidido compartilhá-lo
  • 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

    • Normalmente o que mais me importou foi o uso de memória, não a velocidade. A maioria das aplicações Ruby acaba limitada pelo banco de dados, não pelo Ruby em si
      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
    • Não entendo por que alguém que acha Ruby mais lento que Rust deveria se surpreender com o fato de ele ser mais rápido que Python. O que uma coisa tem a ver com a outra?
  • É 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

    • A comunidade Rust é o mais distante possível de um “clube machão”
  • 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

    • Depende muito do que você está construindo. Um app SaaS com vários frontends chega fácil a 30 mil linhas