DEV Community

Cover image for Interface de Usuários como uma reflexão
Eduardo Rabelo
Eduardo Rabelo

Posted on

Interface de Usuários como uma reflexão

Uma pergunta que as pessoas me perguntam regularmente: "Como todos os novos recursos do React (context, hooks, suspense) afetam a maneira como desenvolvemos aplicativos (web) no futuro? Eles tornam bibliotecas de gerenciamento de estado como Redux ou MobX obsoletas?"

Com este post, tentarei responder a essa pergunta de uma vez por todas! Para entender verdadeiramente a questão, precisamos fazer um pouco de trabalho. Vamos voltar atrás e deixar o React, Redux e MobX sozinhos enquanto respondemos a uma pergunta mais fundamental.

O que é um aplicativo da web? Para o propósito deste post: Um aplicativo da Web é uma interface de usuário que permite aos clientes interagirem com sua empresa. A chave aqui é que é uma interface de usuário. Não a interface. O objetivo de um bom front-end: fornecer uma experiência agradável e sem atrito a seus clientes para interagir com seus processos de negócios. Mas o front-end não é o negócio em si!


Como um experimento, imagine que o inbox.google.com pare de funcionar (ah, espere, ele já parou... 😭). Teoricamente, os usuários poderiam pegar o telefone, ligar para o google, identificar-se e perguntar a um funcionário do google: por favor, diga-me quais mensagens você tem à minha espera? Este exercício mental é uma ótima maneira de descobrir o que é o seu negócio. Se um cliente passasse pelo seu escritório, que perguntas eles fariam? Que informações você tentaria salvar se o escritório estivesse prestes a queimar? Quais interações do usuário geram dinheiro para sua empresa?

Percebo que, no desenvolvimento de front-end, muitas vezes abordamos as interfaces de usuário pelo ângulo oposto: partimos de alguns mock-ups e adicionamos pedaços de estado em lugares quase arbitrários para fazer a coisa toda ganhar vida. Basicamente, o estado e os dados são uma reflexão tardia, um mal necessário que cria esse belo trabalho de interface de usuário. Trabalhando sua aplicação desse lado inevitavelmente leva à conclusão: o estado é a raiz de todo mal. É aquela coisa horrível que faz tudo que era lindo no começo, feio e complicado. Mas aqui está um contra-pensamento:

Estado é a raiz de todo o fluxo de rendimento.

Informação. A oportunidade de os clientes interagirem com os processos de negócios é, em última análise, a única coisa que gera dinheiro. Sim, uma melhor experiência na interface do usuário provavelmente levará a mais dinheiro. Mas não é o gerador de dinheiro em si.

Portanto, na minha humilde opinião, devemos abordar a criação de aplicativos da web na direção oposta e codificar primeiro as interações que nossos clientes terão com nossos sistemas. Quais são os processos. Qual é a informação que ele precisará? Qual é a informação que ele irá enviar? Em outras palavras, vamos começar com a modelagem do domínio do nosso problema.

As soluções para esses problemas são coisas que podemos codificar sem precisar de uma biblioteca de interface do usuário. Podemos programar as interações em termos abstratos. Testá-los. E construir uma compreensão profunda de em quais estados diferentes todos esses processos podem estar.

Modele e desenvolva a lógica do seu aplicativo como se ele fosse usado em muitas UIs diferentes (por exemplo, web, CLI, nativo etc.), mesmo que não seja. Isso forçará você a evitar o acoplamento da lógica com a apresentação, que os frameworks mainstream (React, Angular, Vue) involuntariamente encorajam. - David K. Piano

Neste ponto, não importa qual é a natureza da ferramenta que os clientes usam para interagir com o seu negócio. Um aplicativo da web? Um aplicativo nativo do React? Um SDK como módulo NPM? Um CLI? Não importa! Assim:

Inicialmente, projete seu estado, armazene, processe como se estivesse construindo uma CLI, não um aplicativo da web.

Agora você pode estar se perguntando: "Você não está exagerando na engenharia? Por que devo criar meu aplicativo como se estivesse prestes a lançar uma CLI? Eu claramente nunca farei isso… Você está me vomitando unicórnios?"

Agora, pare de ler este blog por um momento e volte para o projeto em que você está procrastinando, e acione seus testes…. Agora me diga novamente: seu aplicativo tem uma CLI ou não? Todo desenvolvedor da sua equipe tem uma CLI (espero): o framework de testes. Ele interage e verifica seus processos de negócios. Quanto menos níveis de indireção seus testes de unidade precisarem para interagir com seus processos, melhor. Testes de unidade são a segunda interface do usuário para o seu sistema. Ou até mesmo o primeiro se você aplicar TDD.

O React faz um trabalho realmente incrível para permitir que os testes de unidade entendam uma interface do componente e interajam com ela (sem ter um navegador e tal). Mas ainda assim, você deve ser capaz de testar sem as indireções introduzidas por conceitos como "mount", "render" ("shallow" ou não?), "despachando eventos", "snapshots". Esses são todos os conceitos que não importam para o domínio de negócios e vinculam desnecessariamente sua lógica ao React.

Nada supera a simplicidade de invocar seus processos de negócios diretamente como um conjunto de funções.

Nesse momento, você pode ter alguma idéia de por que sempre fui contrário à capturar o estado do domínio diretamente no estado do componente React. Isso torna o desacoplamento de processos de negócios e a interface do usuário desnecessariamente complicada.

Se eu fosse criar uma CLI para meu aplicativo, provavelmente usaria algo como yargs ou commander. Mas isso não significa que, devido a CLI ser a minha interface do usuário, essas bibliotecas devem gerenciar o estado dos meus processos de negócios. Em outras palavras, eu estaria disposto a pagar por uma reescrita completa, apenas para alternar entre yargs e commander. O React é para mim como uma biblioteca de CLI, uma ferramenta que ajuda a capturar a entrada do usuário, o executar processos e a transformar dados corporativos em uma boa saída. É uma biblioteca para construir interfaces de usuário. Não são processos de negócios.


Somente quando você capturou os processos do cliente, os testou e os verificou, começa a importar qual deve ser a interface do usuário real. Com qual tecnologia ela é construída. Você se encontrará em uma posição muito confortável: quando começar a construir componentes, descobrirá que eles não precisam de muito estado. Alguns componentes terão algum estado próprio, já que nem todo estado da interface do usuário é relevante para seus processos de negócios (todos os estados voláteis, como seleção atual, guias, roteamento, etc.). Mas:

A maioria dos seus componentes serão de apresentação (dumb components)

Você também descobrirá que o teste se torna mais simples; você escreverá muito menos testes que montam os componentes, disparam eventos etc. Você ainda quer alguns, para verificar se você ligou tudo corretamente, mas não há necessidade de testar todas as combinações possíveis.

Esse grande desacoplamento permite uma iteração muito mais rápida nas ua UI, testes A/B, etc. Uma vez que o estado do domínio e a UI foram desacoplados, você está muito mais livre para reestruturar sua interface do usuário. Falando a verdade, até mesmo mudar para uma UI ou paradigma completamente diferente se torna mais barato. Porque o estado não é afetado por ela. O que é ótimo, já que na maioria dos aplicativos que vi, a interface do usuário se desenvolve em um ritmo muito mais alto do que a lógica de negócios real.

Por exemplo, no Mendix, usamos o modelo acima com grande sucesso. Essa separação se tornou o paradigma que todos seguem naturalmente. Um exemplo: o usuário precisa fazer o upload de uma planilha do excel, depois executamos algumas validações do lado do cliente, depois interagimos com o servidor e, finalmente, iniciamos alguns processos. Esse novo recurso resultaria primeiro em um novo armazenamento (apenas uma classe JS simples) que captura o estado interno e os métodos para cada etapa do processo. Isso capturaria a lógica para verificação. As interações com o back-end. E criaríamos testes de unidade para verificar se as mensagens de validações corretas foram geradas e se o processo inteiro funciona corretamente em todas as permutas de estado e condições de erro. Somente depois disso, as pessoas começam a criar a interface do usuário. Escolha um bom componente de upload, crie formulários para todas as etapas, etc.

Neste ponto, você também pode entender por que eu não sou fã das coisas que misturam interação de back-end diretamente na interface do usuário. Tal como as ligações do react-apollo como meio de interagir com o GraphQL. A interação de back-end, como o envio de mutações ou a busca de dados, é de responsabilidade do meu domínio. Não da camada da interface do usuário. react-apollo até agora, me parece um atalho que facilmente leva a uma configuração fortemente acoplada.


Finalmente! É hora de voltarmos à nossa pergunta original: "Como todos os novos recursos do React (context, hooks, suspense) afetam a maneira como desenvolvemos aplicativos (web) no futuro? Eles tornam bibliotecas de gerenciamento de estado como Redux ou MobX obsoletas?"

A resposta para mim é: os novos recursos não mudam o jogo do gerenciamento de estado. context e hooks não permitem que o React faça novos truques. Estes são apenas os mesmos truques, significativamente melhor organizados, mais fácil de compor e de uma maneira menos propensa a erros (claramente, eu sou um fã!). Mas o React, fora da caixa, só pode responder ao estado que pertence aos componentes. Se você quiser que seu estado de domínio viva fora de sua árvore de componentes, precisará de um padrão de gerenciamento de estado separado, abstração, arquitetura, biblioteca, para organizar tudo isso.

As recentes adições ao React não mudam fundamentalmente nada no jogo de gerenciamento de estado.

Em outras palavras: se você percebeu que não precisa mais do Redux ou do MobX desde a introdução do context e hooks, então você não precisou deles desde começo. Essa é uma reflexão tardia do acoplamento da lógica com a apresentação.

Observe que com hooks, há menos motivos para usar o MobX para gerenciar o estado do componente local. Especialmente considerando que observables ​​do MobX como estado de componente não serão capazes de utilizar os benefícios do suspense.

Falando sobre suspense vs gerenciamento de estado em geral: Eu acho que isso apenas prova a sanidade da separação de interesses. Suspense + estado local do React são ótimos para gerenciar todo o estado da interface do usuário, para que possa haver renderização concorrente e tudo mais. A renderização concorrente faz muito sentido para o estado volátil, como interface de usuários. Mas e para meus processos de negócios? Os processos de negócios devem estar exatamente em apenas um estado em todo o momento.

Com isso, espero responder à pergunta sobre as novidades no React vs o gerenciamento de estado:

O React deve gerenciar o estado volátil da interface do usuário, não seus processos de negócios. E por essa razão, nada realmente mudou.

Uma nota rápida sobre MobX e mobx-state-tree, você pode entender melhor seus objetivos gerais. Eles foram projetados para:

  • Ser capaz de gerenciar o estado independentemente de qualquer abstração da interface do usuário.
  • Uma maneira descente e transparente de adicionar o estado que eles criam a uma interface de usuário
  • Evitar os erros comuns ao cuidar de otimizações manuais para subscriptions, selectors e outras funcionalidades, garantindo que os eventos não causem a re-renderização de muitos componentes.

Se você quer saber como é legal trabalhar com um estado de domínio organizado e separado, assista minha palestra Complexity: Divide & Conquer, ou leia: "How to decouple State and UI". Olufemi Adeojo escreveu sobre isso recentemente também: "The curious case of reusable state management".

Antes de irmos embora: todo blogueiro sabe que um blog precisa de imagens para envolver os usuários. Este blog não apresenta nenhuma imagem ainda e, portanto, tem uma interface do usuário ruim e insatisfatória. Mas ainda pode realizar todos os seus "objetivos de negócios": Compartilhando os pensamentos acima com você. Porque, apesar de extremamente crucial, a partir de uma perspectiva de implementação:

A interface do usuário é apenas uma reflexão.

Depois que os processos de negócios são capturados, você também pode usá-los para direcionar sua interface do usuário!

Dica final: Usando o MobX com o React 16.8.0 ou superior? Confira os hooks do MobX, que são muito menores que as originais!

Atualização, 25-Fev-2019: Intrigado por esse artigo? Eu recomendo a palestra "Architecture the Lost Years" de Robert C. Martin!

Créditos ⭐️

Top comments (0)