Porque essa é uma das melhores alternativas ao Ruby on Rails

Set 8 | Henrique F. Teixeira

Se você é dev Ruby, está pensando em desenvolver um projeto novo e buscando alternativas ao Rails, seja por questões de performance ou arquitetura, considere o framework Roda.

Roda foi criado por Jeremy Evans, core commiter do Ruby e um dos desenvolvedores mais influentes da comunidade, e na minha opinião, o framework é o mais bem escrito considerando as características da linguagem: ele consegue tirar vantagem da sintaxe e metaprogramação de forma inteligente e simples ao mesmo tempo que traz extrema produtividade, extensibilidade e alta performance.

Através desse artigo te explico o porquê.

Performance

Quando Ruby foi criada por Yukihiro Matsumoto (conhecido como "Matz") em 1993, o objetivo principal não era desempenho máximo, mas sim tornar o desenvolvimento de software mais agradável e eficiente, e isso se traduz em:

  • Sintaxe expressiva e legível.
  • Menos código para resolver problemas.
  • Preferência por produtividade e manutenibilidade em vez de performance bruta.

Hoje, mais de 30 anos depois, podemos dizer que o Matz atingiu (e continua atingindo) seu objetivo, com uma adoção muito forte entre startups de alto crescimento, especialmente através de Ruby on Rails.

Porém, em troca desses benefícios, a linguagem traz algumas limitações importantes:

  • CPU: Ruby é uma linguagem interpretada e altamente dinâmica. Métodos podem ser redefinidos em tempo de execução, classes podem ser alteradas a qualquer momento e a resolução de chamadas acontece de forma mais complexa do que em linguagens estaticamente compiladas. O JIT do Ruby moderno (YJIT) melhorou bastante o cenário, mas Ruby ainda costuma ser significativamente mais lento em tarefas intensivas de CPU.

  • Garbage Collector: Ruby utiliza um GC (Garbage Collector) geracional e incremental relativamente avançado, mas ainda existem pausas de coleta que podem impactar a latência. Aplicações com muitas alocações de objetos podem passar uma parcela considerável do tempo executando o GC em vez da lógica de negócio.

  • Fragmentação de memória: Mesmo após o GC liberar objetos, o processo Ruby nem sempre devolve essa memória ao sistema operacional de forma eficiente. Em aplicações que executam por longos períodos, é comum observar crescimento gradual do consumo de memória.

De forma resumida, um sistema escrito em Ruby com muitas abstrações, objetos alocados e metaprogração pode acabar custando mais caro e exigindo mais hardware.

Tendo isso em vista, vamos comparar alguns frameworks. Utilizei a classe ObjectSpace para identificar quantos objetos temos criados em uma aplicação web Ruby, comparando Rails (modo "minimal"), Hanami e Roda criada com roda-project (a forma mais rápida de criar uma aplicação Roda fullstack com diversos plugins habilitados). Isso significa que comparei 3 ferramentas que incluem funcionalidades equivalentes, não somente um sistema de roteamento, e ainda dei vantagem para o Rails utilizando seu modo mais "leve".

Para ambas as aplicações, adicionei uma rota /home/index e uma view com o seguinte código:

<% @objects = ObjectSpace.count_objects %>
Total (slots): <%= @objects[:TOTAL]  %>
Free (free slots): <%= @objects[:FREE] %>
Objects (active objects): <%= @objects[:T_OBJECT] %>

Para tornar os testes um pouco mais reais, também enviei uma carga alta de requisições para os endpoints utilizando o Apache Benchmark (ab) e para ambos utilizei o Puma com 1 worker e 3 threads.

Esses foram os resultados:

  • Rails (minimal): Total: 409268, Free: 47989, Objects: 25264
  • Hanami: Total: 346016, Free: 47648, Objects: 10682
  • Roda (com roda-project): Total: 239621, Free: 14515, Objects: 7661

Em memória (verificado com top -p), esses objetos alocados representaram:

  • Rails (minimal): 222MB
  • Hanami: 139MB
  • Roda (com roda-project): 136MB

E aqui a quantidade de requisições por segundo:

  • Roda (com roda-project): 939.89rqs
  • Hanami: 376.38rqs
  • Rails (minimal): 242.81rqs

Com uma lógica simples, podemos traduzir os resultados dos benchmarks para dinheiro gasto: Imagine que temos a mesma aplicação do benchmark rodando para diversos usuários e atualmente gastamos $3000 com servidores utilizando Ruby on Rails. Gastaríamos aproximadamente $1937 se estivessemos utilizando Hanami, e somente $775 utilizando Roda. Claro que é um exemplo simplório e hipotético, a performance pode variar drásticamente dependendo do código que escrevemos e o problema que estamos resolvendo. Além disso, o banco de dados geralmente costuma ser o maior ofensor de performance em aplicações web.

Mas não podemos negar um fato, Roda é o framework que entrega mais com menos quando o assunto é memória e performance, e muito se deve a sua arquitetura e sistema de roteamento:

  • A avaliação da requisição para no exato momento em que o caminho (path) encontra seu bloco correspondente.
  • O uso de cache em estruturas internas garante um overhead mínimo (Templates pré-compilados, tabelas de lookup para rotas estáticas, app freezing).
  • Sem meta-programação pesada: Muitos frameworks usam method_missing ou definem métodos dinamicamente durante o tempo de execução, o que piora a performance.

Veja também os benchmarks do techempower.com, onde Roda aparece constamentemente entre os frameworks melhor rankeados do ecossistema Ruby

Plugins / Extensibilidade

Roda foi projetado em torno de um sistema de plugins extremamente simples e previsível.

Diferentemente de outros frameworks que expõem dezenas de pontos de extensão espalhados por callbacks, middlewares, generators e convenções, o Roda concentra praticamente toda sua extensibilidade em plugins que modificam a classe da aplicação de forma explícita.

Quando escrevemos:

class App < Roda
  plugin :render
  plugin :json
  plugin :all_verbs
end

Cada plugin adiciona métodos, comportamento ou recursos diretamente à aplicação. Não existe mágica escondida. Você consegue rastrear exatamente de onde cada funcionalidade veio

Outro aspecto importante é que o núcleo do Roda é extremamente pequeno. O roteamento, que é a principal responsabilidade do framework, permanece separado de recursos adicionais. Isso permite que funcionalidades como renderização, autenticação, sessões, cache, CSRF, JSON e demais sejam implementadas como plugins independentes, sem aumentar a complexidade do core, permitindo também que nossa aplicação não desperdice recursos em funcionalidades que não iremos utilizar.

Por fim, o sistema de plugins do Roda é utilizado pelo próprio framework. Muitos recursos considerados "nativos" são implementados exatamente da mesma forma que plugins criados por usuários. Isso é um sinal de uma arquitetura extensível: os mecanismos usados internamente são os mesmos disponíveis para quem desenvolve aplicações.

Veja como é simples criar plugins para o Roda seguindo os passos descritos no repositório: github.com/jeremyevans/roda#label-Plugins

Produtividade

Apesar de ser um framework aparentemente "pequeno", ao analizarmos a quantidade de plugins nativos e plugins disponibilizados pela comunidade, temos recursos disponíveis para torná-lo similar ao Rails em features e desenvolver qualquer tipo de aplicação.

Existem mais de 100 plugins oficiais listados na documentação oficial, alguns essenciais como:

  • CSRF
  • Sessions e Cookies
  • I18n
  • Views / Renderização
  • Hooks
  • Logs
  • Envio de email

Além disso, das alternativas ao Rails, Roda é o único framework que conta com uma gem de autenticação própria e robusta. A gem rodauth adiciona um sistema de autenticação extremamente completo e seguro na nossa app, contendo diversos recursos, como:

  • Gerenciamento de contas
  • Recuperação de senha
  • JWT
  • SMS codes / Recovery codes
  • Passwordless Authentication

E para facilitar a criação e desenvolvimento de novas aplicações, temos a gem roda-project, que fornece um scaffold moderno para aplicações Roda, incluindo generators e várias tasks essenciais, tornando a experiência de desenvolvimento próxima ao Rails.

Não podemos deixar de falar que todo o ecossistema de gems do Ruby está a nosso dispor para o que precisarmos, incluindo sidekiq, dry-rb, rom, async e etc…

Maturidade

Roda existe há mais de 10 anos e tem mais de 20 milhões de downloads. O framework é uma escolha consolidada para empresas que já utilizam Ruby e querem extrair a máxima performance com baixo consumo de memória. Atualmente existem grandes projetos utilizando o framework em produção, com destaque para a Ubicloud. Além disso, o trabalho de Jeremy Evans é notório por sua política de tolerância zero a bugs e respostas rápidas no GitHub. Correções de falhas e implementações de segurança costumam receber atualizações (releases) em prazos extremamente curtos, garantindo uma base de código confiável.

Conclusão

Por muito tempo, a comunidade conviveu a premissa de que a agilidade de desenvolvimento no ecossistema Ruby exigia um sacrifício inevitável: alto consumo de infraestrutura, processos pesados e muita "mágica" nos bastidores. O Roda desconstrói essa ideia por completo, representando uma mudança de paradigma e unindo o que antes parecia impossível no mundo Ruby: a expressividade e a produtividade que amamos, com uma economia real de servidores e uma performance de alto nível.

Se o Rails foi a ferramenta que popularizou o Ruby permitindo criar negócios de forma rápida, o Roda é a resposta madura para a engenharia de software moderna, e quando falo engenharia, não quero dizer "camadas e camadas" de abstrações, falo sobre resolver problemas com as ferramentas certas, de forma inteligente, selecionando e utilizando apenas o necessário, mantendo a simplicidade e manutenabilidade (sem "overengineering" ou "underengineering").

Ei, o que achou desse artigo??

Compartilhe e dê sua opinião clicando em uma das redes abaixo:


Muito obrigado!