3 pontos por GN⁺ 2024-10-23 | 1 comentários | Compartilhar no WhatsApp
  • Rwf é um framework abrangente para criar aplicações web em Rust, baseado no padrão clássico MVC, e traz por padrão os recursos necessários para construir apps web rápidos e seguros
  • Os recursos básicos incluem servidor HTTP, ORM para consultas PostgreSQL, templates dinâmicos, autenticação e sessões de usuário, middleware, tarefas em background e tarefas agendadas, além de migrações de banco de dados
  • Também oferece um framework REST integrado com suporte a serialização JSON, WebSockets, hospedagem de arquivos estáticos, configurações por ambiente, logging e métricas, além de CLI
  • Integra-se estreitamente ao Hotwired Turbo para criar SPAs orientadas pelo backend, e oferece um servidor WSGI para migração de Django/Flask e um servidor Rack para migração de Rails
  • Atualmente em estado beta, busca early adopters; afirma que a maioria dos recursos está em bom estado e que a documentação já é utilizável

Framework web MVC para Rust

  • Rwf é um framework abrangente para construir aplicações web em Rust
  • Foi escrito com o padrão clássico MVC(model-view-controller)
  • Seu objetivo é incluir por padrão os recursos necessários para facilitar a criação de apps web rápidos e seguros
  • A documentação está disponível na documentação oficial

Recursos oferecidos

  • Servidor e processamento de requisições
  • Dados e estrutura da aplicação
    • Oferece um ORM amigável para criar consultas PostgreSQL com facilidade
    • Suporta migrações de banco de dados
    • Oferece Dynamic templates
    • Inclui Authentication e sessões de usuário integradas
  • API e processamento de tarefas
  • Operação e ferramentas de desenvolvimento
    • Suporta configurações por ambiente
    • Oferece logging e métricas
    • Inclui uma CLI

Hotwired Turbo e suporte a migração

Início rápido

  • Crie uma aplicação binária em Rust e adicione rwf às dependências para usá-lo
cargo add rwf
  • Um app básico usa rwf::prelude::* e rwf::http::Server para definir controllers e rotas
use rwf::prelude::*;
use rwf::http::Server;

#[controller]
async fn index() -> Response {
    Response::new().html("Welcome to Rwf!

")
}

#[tokio::main]
async fn main() {
    Server::new(vec![
        route!("/" => index),
    ])
    .launch()
    .await
    .unwrap();
}

Exemplos e status do projeto

  • Casos de uso comuns podem ser consultados em examples
  • O Rwf está atualmente em estado beta e busca early adopters
  • Afirma que a maioria dos recursos está em bom estado e que a documentação já é utilizável
  • Contribuições são bem-vindas; o guia está em CONTRIBUTING, a orientação sobre a estrutura do código está em ARCHITECTURE, e a lista de recursos desejados está em ROADMAP

1 comentários

 
GN⁺ 2024-10-23
Opiniões do Hacker News
  • O lançamento deve parecer bastante irreal, parabéns. A maior coisa que aprendi fazendo MVC web com Rails por muito tempo é que o framework precisa conter fortemente a lógica de negócios na camada de modelo
    Acho melhor não colocar no modelo de dados callbacks como os de que o Active Record fala, por exemplo hooks como afterCreate. Ainda não está no ORM, mas se estiver no roadmap, acho melhor que continue fora
    No entanto, isso só funciona direito quando se recomenda fortemente uma camada de serviço, ou seja, de lógica de negócios. A maioria dos meus apps Rails organiza objetos de comando/serviço com gems como Interactor
    Só MVC, e portanto só a configuração padrão do Rails, não me parece ideal para escrever um app operável, por causa da ausência de uma camada de serviço. Também fico curioso sobre por que não aproveitaram ORMs ou query builders existentes da comunidade. Ainda não escrevi uma única linha de Rust, mas estou ficando cada vez mais curioso

    • Fico curioso de onde vem essa perspectiva. Meu pensamento é exatamente o oposto: o máximo possível de lógica de negócios deve ficar no modelo
      Acho que serviços deveriam ser quase sempre trechos de código mais complexos e específicos disparados a partir do modelo. Controllers finos e modelos gordos foram o melhor para depuração, organização e descobribilidade, e, pela minha experiência, usar muitos serviços gera muito código espaguete
      Mesmo de uma perspectiva puramente orientada a objetos, o modelo é o objeto fundamental que define a entidade. User deve saber tudo o que precisa saber sobre si mesmo e se comunicar com outras entidades por mensagens
      Mas concordo quanto aos callbacks. Callbacks criam muitos efeitos colaterais estranhos e tornam a depuração realmente difícil
    • Se não há lógica de negócios, não sei o que exatamente seria um modelo. Parece que você quer uma configuração em que chama structs de modelos e procedimentos de serviços
      Dá para fazer isso, mas fica bem difícil raciocinar sobre de que maneiras uma entidade pode ser atualizada. Isso porque qualquer número de procedimentos pode atualizá-la e cada um pode ter suas próprias regras de negócio. Se for assim, os procedimentos poderiam escrever diretamente no banco de dados e eliminar o modelo
    • Concordo que modelos não deveriam ter lógica de negócios. Martin Fowler e Robert C. Martin chamam isso de modelo de domínio anêmico, e é o oposto do antigo estilo de desenvolvimento empresarial pesado em orientação a objetos e padrões
      Mas, depois de mais de 20 anos desenvolvendo, cheguei à conclusão de que encapsulamento é um fardo, não um recurso, e que dados devem ser separados das operações realizadas sobre esses dados. Isso é chamado de design orientado a dados ou programação orientada a dados, e não sou o único a ter chegado à mesma conclusão
    • Dizer que MVC sozinho é insuficiente para apps em nível de produção é uma afirmação bem forte. Pessoalmente, não gosto de objetos de serviço, porque ficam espalhados por toda parte e prejudicam a descobribilidade
      Há outras formas de modelagem que escalam bem, e também alguns textos relacionados. Há este artigo de alguém da Basecamp: https://dev.37signals.com/vanilla-rails-is-plenty/
      Claro, isso é muito orientado a objetos, então também não gosto tanto. Por exemplo, o framework Phoenix, do Elixir, usa contextos para agrupar funcionalidades relacionadas; em termos simples, dá para vê-los como uma fachada
      Se você gosta de serviços, pode usá-los, mas acho um pouco fora do alvo dizer que MVC não é suficiente para produção. Tratar processos de negócio pesados com callbacks de modelo não é bom, mas para pequenas tarefas de ajustar dados para o formato correto, funciona muito bem
    • Interessante. Na empresa, criamos nosso próprio ORM em PHP, porque era proibido usar bibliotecas open source como Laravel, e achei hooks muito úteis
      Talvez eu tenha um viés, especialmente porque minha experiência de programação começou com PHP para Wordpress, que usa hooks extensivamente
      O que criei tem uma especificação de tabelas que pode ser convertida para definições SQL ou cuspir formulários HTML bem formatados. Um controller separado lida com todas as conexões ao DB e operações CRUD, e há hooks antes e depois que permitem, se necessário, referenciar facilmente outras tabelas e restrições
      Funciona bem, mas, se pudesse, eu migraria para Laravel imediatamente
  • Se é um framework REST, eu esperaria que, por padrão, ele conseguisse gerar definições Swagger/OpenAPI. Vejo isso como um dos recursos matadores do FastAPI
    Também não entendo bem por que criaram o próprio ORM em vez de integrar com um ORM existente como diesel.rs, e por que fizeram a própria linguagem de templates em vez de escolher um engine de templates existente e popular
    Fora isso, o projeto parece realmente interessante e pretendo continuar acompanhando
    [0] https://diesel.rs/
    [1] https://crates.io/categories/template-engine

    • Usei Diesel alguns anos atrás e, para mim, pareceu Rust demais. Era preciso definir o schema duas vezes e não dava para usar a mesma struct para inserção e consulta, então, na prática, era como defini-lo três vezes
      No geral, foi uma boa primeira tentativa de ajustar tipos de banco de dados a tipos Rust, mas um ORM precisa ser mais flexível e fácil de usar. Ele deve tornar consultas mais fáceis, não mais difíceis :)
      Na parte de templates, criar a própria linguagem é quase um rito de iniciação no clube dos nerds de 30 anos ou mais. Não li o Dragon Book, mas sempre quis ter feito aquela disciplina na faculdade. Sempre há várias implementações para a mesma coisa, e pareceu certo usar esta implementação que imita bem de perto o que o ERB do Rails faz
    • https://github.com/poem-web/poem é um framework Rust que oferece definições Swagger por padrão
    • Fico curioso se alguém conhece um framework parecido que funcione no sentido inverso. Quero dizer, mantendo a definição OpenAPI como fonte da verdade e validando se o servidor a segue
    • Gerar OpenAPI a partir do servidor é 100% um recurso matador. Temos usado Dropshot com bons resultados
    • Eu também esperaria que um framework REST gerasse definições Swagger/OpenAPI por padrão. Pelo que entendi, porém, este não é um framework para construir APIs web, mas sim um framework MVC que retorna HTML
  • Do ponto de vista de SRE, https://levkk.github.io/rwf/migrating-from-python/ chamou minha atenção. Por um lado, é realmente incrível terem conseguido fazer isso, mas, do ponto de vista de um SRE olhando para estabilidade, isso me faz gritar por dentro
    Quando a escala cresce, isso precisa ser tratado por um proxy reverso como Caddy, Nginx ou Traefik

    • Eu pensei a mesma coisa, mas, com essa abordagem, o engenheiro de aplicação consegue testar mudanças localmente sem ficar indo e voltando. No fim, voltamos ao velho debate de monólito versus microsserviços
      É possível escrever um servidor WSGI estável e, com um pouco de atenção a detalhes como número de threads, vacuum e reiniciar a cada n requisições como o antigo php-fpm, não é tão difícil. Basicamente, se você implementar a maioria das opções que o uwsgi tem, está no caminho certo. Está no roadmap tornar o Rwf comparável a executar com Gunicorn
    • Acho que o autor presumiu que, se o leitor for técnico, não precisa explicar a necessidade de um proxy reverso na frente do servidor WSGI
  • A escolha do nome é realmente impressionante. É uma forma de aparecer no topo dos resultados de busca :P
    Falando sério, ficou bem feito. Criar um bom framework é um trabalho surpreendentemente grande, e é sempre bom ver pessoas explorando o espaço de design e testando novas ideias

    • Projetos Rust tendem a escolher esses nomes amplos, genéricos e um tanto autoelogiosos; sinceramente, acho um grande erro. O Crates.io vai virar um cemitério de projetos abandonados que reservaram nomes plausíveis
    • “Row” também é um bom nome e acho que seria mais fácil de falar do que rwf
      RustOnWeb.com também pode ser comprado por US$ 10 :) só comentando
  • Gostei da expressão “pense em Rails, não em Flask”. Linguagens de tipagem estática precisam ter mais, ou melhores, frameworks opinionated como Rails/Django

  • Ficou bem feito. Vale tentar fazer com que seja apresentado em https://www.arewewebyet.org/

    • É bem surpreendente que loco.rs não esteja nessa página. Mesmo parecendo o mais “Rails” entre os frameworks Rust, ficou de fora
  • Legal! Um Django/Rails feito em uma linguagem de primeira linha
    Como sugestão, talvez async-trait já tenha sido estabilizado, então a macro pode não ser mais necessária; e seria bom adicionar uma integração com OpenTelemetry para obter métricas e tracing por padrão. Para targets Linux, também seria bom usar jemalloc

    • Obrigado. Tentei usar traits assíncronas padrão, mas elas não dão suporte ao despacho dinâmico que o Rwf usa extensivamente
      Pretendo adicionar tags do OpenTelemetry às funções do crate tracing. O jemalloc pode ser adicionado ao app binário que usa Rwf e não precisa entrar como dependência de biblioteca
      [1] https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-trait...
    • Fiquei curioso sobre por que se deve usar jemalloc em targets Linux. Ou também por que ele não seria necessário em outros targets
  • Tentei aprender Rust, mas desisti logo no começo. Vindo de C#, C/C++, Java e Python, Rust me pareceu estranho
    O que me derrubou não foi a estranheza em si, mas o fato de a velocidade para concluir uma tarefa ser menor do que em linguagens como C#, Java e Python
    Hoje em dia faço principalmente desenvolvimento web, então facilidade de uso e produtividade são prioridade máxima. Rust pode ser um pouco melhor em throughput e velocidade, mas, olhando benchmarks modernos de frameworks web, C# e Java também se saem muito bem nesse aspecto
    Espero que isso não seja lido como crítica ao Rust nem como uma forma de diminuir a grande conquista de criar um framework MVC do zero. Está mais para “a ferramenta certa para o trabalho”

    • Entendo totalmente o que você quer dizer. Muita gente, inclusive eu, teve uma experiência parecida no começo
      Para superar a curva de aprendizado, é preciso uma motivação forte. Pode ser porque você precisa usar a linguagem, porque se sente atraído pelo sistema de tipos e pelos benefícios de segurança, ou por algum motivo concreto próprio
      Se você não tem essa motivação, tudo bem. Eu também não tinha no início, e por isso minhas primeiras tentativas de aprendizado não foram muito longe. Como muita gente sente, Rust leva mais tempo do que Java ou Python para terminar as coisas e exige pensar mais antecipadamente. Em certas situações isso vale a pena, mas, se não estiver claro por que aceitar esse trade-off, não há um motivo forte para continuar
  • Recentemente abandonei o loader JS do webpack e passei a usar um loader em Rust 50 vezes mais rápido, e eu também me apaixonei por Rust. Rust tem um grande impacto em ganhos de desempenho e, hoje, C++ e Rust são minhas linguagens favoritas

    • Ah, você pode compartilhar o que passou a usar depois de abandonar o webpack?
  • Avaliei todos os candidatos comumente mencionados para trabalho de backend em Rust e fiz pequenos protótipos. Até agora, embora seja de nível mais baixo do que eu gostaria, acabei concordando, a contragosto, com a conclusão coletiva de que Axum é a melhor opção no geral
    Os outros candidatos eram Loco e Rocket. O Loco era parecido demais com Rails, e, no Rocket, as macros só começaram a me incomodar depois de eu ter usado mais Rust
    Este framework parece se encaixar perfeitamente no meu critério de “baterias incluídas, mas não prescritivo demais”. É uma boa adição ao ecossistema

    • E o Actix? Pelo que lembro, houve uma discussão no HN há algum tempo sobre Actix e Axum