Taverna /dev/All

Gerenciamento de estado é uma dor de cabeça bruta

Opa, belezas?

Disclaimer: eu sou dev backend há uns bons anos mas fui “full stack” na época em que os frameworks baseados em servlets e JSP eram dominantes no mundo Java. Ou seja, tem muito tempo que não tenho experiências com front.

Recentemente decidi experimentar ClojureScript e fazer uma app web pequena que pesquisa eventos usando a API pública da Ticketmaster, exibe os eventos para o usuário, permite marcar favoritos, tem paginação básica e algumas opções de ordenação. O sistema ainda não tá pronto mas já posso dizer que de todos os PITAs que eu tive, gerenciamento de estado (mutação) foi de longe o pior até agora. Imagino que a experiência no backend, especialmente com serviços stateless, contribuiu para que eu achasse manutenção de estado particularmente complicado.

Quem tem experiência em desenvolvimento frontend tem essa mesma impressão? Se sim, têm dicas para tornar essa gerenciamento de estado menos complicado? Além disso, o que mais “pega” em desenvolvimento frontend? Testes, talvez?

Quem tiver curioso e quiser dar uma olhada no código (WIP), ele tá em https://github.com/matheusemm/lab-events/tree/focus-on-tests.

Abraços

1 Curtida

O que é “PITA”?
O que por exemplo precisa guardar o estado?

Foi mal pela sigla. :slight_smile: PITA - pain in the ass.

O que eu tenho visto nessa experiência é que existem diferentes ações que alteram não apenas um elemento do estado mas um conjunto de elementos. Por exemplo: depois de uma pesquisa eu preciso alterar no estado a lista de eventos, a página corrente (para paginação), e a lista de favoritos (para poder salvar o estado de “favorito” entre paginações). A ação de paginar também toca nesse mesmo conjunto de atributos do estado.

Quanto maior o número de ações maiores as chances de existirem essas interconexões entre atributos do estado e mais complicado pode ficar o seu gerenciamento.

não lido cmo frontend tem um tempo mas acredito que o que vc busca é algo tipo “redux architecture”, existem várias implementações por ai.

já trabalhei em empresa que tinha frontend com cljs, acho que usaram esse framework p/ isso: https://github.com/omcljs/om

Gerenciamento de estado foi uma das razões que nos levou a dar mais atenção ao Angular ao invés do Vue.

Um problema que vimos no Vue (e que se repete de certa forma no React também a partir do uso do Redux) era justamente o momento no qual você precisava de ter estado compartilhado. Conforme seus reducers vão crescendo em tamanho, vimos que não raro topavamos com um “módulo global contendo um amontoado de variáveis globais”.

E não adiantava muito ter a coisa organizada por funções bem definidas, algo assim. Não adiantava, conforme a coisa crescia, a manutenibilidade ia se ferrando.

O Angular nos mostrou o caminho quando a gente começou a usar injeção de dependências num modelo muito parecido com o do Spring e CDI. O estado necessário fica no serviço, centralizado, bem colocado, isolado. O “módulo global” sumiu aí.

Aí indo um pouco além comecei a estudar a fundo React e percebi que na realidade o modelo que ele adota ajuda a evitar estes problemas também em uma abordagem baseada em componentes. O estado fica no componente e apenas nele.

Se existe um estado a ser compartilhado, aí há dois caminhos.

  • Você cai no seu reducer padrão (Vuex, Redux da vida), mas limita ao máximo o que este tem. NO meu caso tento limitar a apenas informações de autenticação e olhe lá, mesmo isto eu tiro daí.
  • Implemento serviços que, se não podem armazenar os dados em memória, o fazem em persistênica como um localstorage bobo da vida ou algo similar.
1 Curtida

Acho que experimentarei esse caminho do local storage…

No meu caso uso ClojureScript com reagent e o padrão é ter um atom (similar a uma atomic reference em Java) que armazena o estado da aplicação. Quando o atom muda, ocorre uma re-renderização dos componentes (segundo o modelo do React, já que reagent é um wrapper em ClojureScript para React).

Vi alguns exemplos de componentes reagent com estado local, por exemplo, um contador que mantém o número de vezes em que foi clicado. Mas coisa muito simples. Por outro lado, já vi críticas ao estado distribuído em vários lugares porque impediria que você tivesse uma visão global do estado da sua aplicação, ou o que seria o conjunto total de propriedades que definiriam um “snapshot” da aplicação.

Fato é que de tudo o que eu tive que fazer, desde setup, entender ferramentas de ClojureScript e JavaScript, etc, essa gestão de estado é a parte que mais deu dor de cabeça, até para uma app pequena como a que estou fazendo.

Entendi. No meu caso o estado da página corrente fica no próprio elemento html, bem direto e simples.

É bom verificar se esta complexidade que está imaginando realmente vai ser necessário.

1 Curtida

este papo de “impedir uma visão global” é no mínimo estranho, né?
Seria uma defesa do clássico módulo global ou da classe “só pode ter um” que tem tudo? :smiley:

Acho que fica no meio caminho entre os dois. Infelizmente desenvolvimento front-end se tornou muito mais complexo do que qualquer um podia imaginar.

Pessoalmente, comparando com as ferramentas do passado (pensando em desktop aqui) acredito que tivemos um retrocesso de décadas.

este papo de “impedir uma visão global” é no mínimo estranho, né?

Verdade… só penso que seria útil ter uma visão holística de um sistema mas isso pode ser capturado em algum tipo de documentação, talvez seja a forma mais adequada de expressar esse tipo de característica.

Tentarei pensar na minha app sob essa perspectiva de que cada componente cuida de um pedaço do estado, verei o que dá. A primeira impressão é que terei que mudar a forma de tratar eventos, não apenas pendurando o event handler mas tratando isso mais como um pub/sub ou observer/observable…

Tô quase voltando pro Clojure backend, heheh.

No final das contas não existe bala de prata. Se uma visão global atende o projeto, é uma solução e não há nada de errado com isto.

Hoje mesmo a gente tava conversando sobre isto: não é por que a solução de um é diferente da sua que uma delas está errada.

O bicho REALMENTE pega nesta questão de estado é quando a aplicação cresce. Várias cicatrizes aqui com isto, especialmente no caso do Vue.

Conhecem o https://xstate.js.org/docs/?

1 Curtida

Eu não, conheço muito pouco de frontend. Darei uma olhada, valeu! :slight_smile:

Várias cicatrizes aqui com isto, especialmente no caso do Vue.

Por conta de algo inerente ao Vue ou o resultado seria o mesmo se usasse React, por exemplo?

No caso dos dois frameworks: o uso de um reducer muitas vezes gera este comportamento global, em que todo mundo vê tudo e torna as coisas muito mais complexas.

Pegamos diversas aplicações legadas que cresceram com o tempo e sofrem deste problema nos dois frameworks (mais no caso do Vue, com quem tivemos mais contato, React é mais recente).

Por isto o modelo do Angular de injeção é mais interessante: o estado nos serviços é melhor localizado, específico, encapsulado. Evita acidentes, como, por exemplo, alguém querer implementar uma funcionalidade específica e furar o isolamento de um estado pra uma implementação e quebrar várias outras.

itexto