WTF?

As rotas do flutter

03 Jul 2022

Eu continuo aprendendo

No meu post anterior falei sobre estar aprendendo Flutter, meu jeito de aprender é intenso. Meu aplicativo vai para loja essa semana, em beta fechado por enquanto, e nessa altura projeto eu fico pistola e penso em reestruturar tudo.

Eu me sinto muitas vezes como os desenvolvedores iniciantes que sou mentor, meu perdido, olhando para o lado errado das coisas e acreditando que as coisas aconteceram magicamente, a diferença é que estou ciente e sempre penso “Não existe mágica, deve ter um bom motivo para acontecer”.

Não sei se já falei, mas eu odeio ‘Getting Started’, ‘Getting Started’ são tutorias normalmente para iniciante se familiarizar com uma tecnologia. Documentar é difícil e se o que temos em tecnologia em relação à documentação fosse aplicado aos jogos, você ficaria nos tutoriais inicias para sempre. ‘Getting Started’ são importantes, mas nunca são suficientes, e a documentação de mais baixo nível muitas vezes é obscura.

Desde quando eu comecei a aprender Dart e Flutter, me deparo com algo que me causa uma certa estranheza, eu não sou um cara de mobile, e isso pode fazer total diferença aqui, porque, além disso, eu gosto de Restful, principalmente do critério relacionado ao Resource-based, se você for de mobile leve em consideração sobre quem escreve.

Sobre as rotas

Dado o disclaimer acima, as formas de rotear uma aplicação Flutter é um pé no caso, uma opção é simples de mais, a outra é complexa e exige muito código. Sem contar que nenhuma chega perto de ser Resource-based. Mas antes deixa eu tentar tornar as coisas um pouco mais claras aqui.

O Flutter tem dois mecanismos de roteamento, um imperativo o outro declarativo. A seção Navigation and routing fala exatamente isso com mais detalhes, não vou repetir tudo aqui.

Para entender a forma imperativa, segue os tutoriais oficiais do Navigation, eles são um ‘Getting Started’ sobre rotas e navegação.

Essa forma é a mais simples, funciona bem em toy projects e projetos mais simples, o pushNamed tenta trazer um pouco de sanidade, mas a forma que os parâmetros são passados leva ela embora, para mim o nome da rota e os parâmetros deveriam estar juntos.

Agora, se você quiser entender a forma declarativa, tem um post chamado Leaning Flutter’s new navigation and routing system que detalha bem todo o funcionamento, e introduz o Navigator 2.0.

Eu li e implementei tudo que está no post, entendi muito melhor a navegação e esse estudo me ajudou bastante para construir o que eu quero apresentar para você logo abaixo, mas infelizmente o Navigator 2.0 requer muitas linhas de códigos para, resumidamente, fazer um “botãozinho” funcionar, apesar de ser poderoso é insano, ter que controlar as telas e o stack do aplicativo em um State não é bem o trabalho que vai me dar o resultado de entrega, fico imaginando o tamanho da manutenção nos aplicativos Flutter por ai.

Better router

Após entender bem todo o problema, eu resolvi pensar em como eu gostaria de declarar minhas rotas no Flutter, no Ruby on Rails isso é feito de forma tão simples no routes.rb, apesar do que está implícito é tão fácil de entender.

Rails.aplicativolication.routes.draw do
  get '/', to: "home#index"
  resources :books, only: [:index, :show] do
end

Inspirado em tudo que eu li, nas horas que eu passei com o Leaning Flutter’s new navigation and routing system, e nas formas declarativas que os framework web normalmente nos oferece, resolvi criar uma interface que seria simples e suficiente para minhas necessidades.

Pensando no Developer experience escrever um State, Navigator, RouterDelegate, etc estava fora de questão, minha primeira ideia é melhorar a forma imperativa, que já é bem simples e clara, a segunda sair com um código que poderia ser usado em qualquer projeto, Deus me livre ficar escrever centenas de linhas para tratar rotas em cada projeto que eu fizer.

get routes => <String, WidgetBuilder>{
  "/": (_) => const HomeScreen(),
  "/books": (_) => const BookListScreen(),
  "/books/(?<id>.+)": (_) =>const BookScreen(),
  '-catchAll': (_) => const ErrorScreen()
};

Ou seja, se for para criar um código complexo de rota eu quero escrever ele apenas uma vez.

Pois foi assim que nasceu o better_router, um pacote que traz um pouco de sanidade para as rotas e navegação do flutter.

A principal ideia aqui é deixar as rotas e os requisitos para elas executarem, no caso os parâmetros, num mesmo lugar, e assim meus widgets podem navegar sem precisa conhecer os detalhes das telas.

Eu sei que ainda tem muitas coisas para melhorar, o pacote ainda não cobre todos os casos de uso, mas para uma primeira versão está boa demais.

Para matar a cobra e mostrar o pau, segue um exemplo de uma pequena aplicação usando o Better Router.

Para instalar basta rodar:

$ flutter pub add better_router

Mais detalhes no Github do projeto

Por enquanto acredito ser isso. E você, o que me conta? Tô la no twitter em @emersonalmeidax ou LinkedIn em linkedin.com/in/dukex

Abraços.