Como defender o fim do padrão SPA + REST?
Contexto
Recentemente tive o privilégio de conversar com um programador com quase 40 anos de carreira em tecnologia que já escreveu livros e deu palestras sobre o assunto. Alguém com muita experiência, certamente. Enquanto conversava com ele, me espantei quando ele começou a dizer que advogava pelo fim dos SPAs e do REST, dizendo que eles só resolviam problemas que eles mesmos criavam.
Ele afirmava que hoje a internet como um todo, navegadores e protocolos, já estão muito mais modernos e não carecem das funcionalidades que não existiam na época em que os SPAs foram inventados. Para ele, deveria haver um movimento de volta para o monorepo SSR, ainda que implementando componentes frontend modernos para enriquecer a UX.
Aquilo não era totalmente novo pra mim: já tinha encontrado outras pessoas com essa mesma ideia. Pela minha experiência, por algum motivo que não compreendi totalmente até hoje, pythonistas têm aversão a frontend. Ele, por coincidência, era justamente um especialista em Python e entusiasta do HTMX. Não por acaso você vai ver um pythonista sempre indo para o Vue quando é obrigado a fazer front, já que das 3 principais frameworks ele é o único progressivo e que aproveita mais dos recursos nativos do JS ao invés de reinventar a roda como fazem o React e o Angular.
Como enxergo
Se o ponto de quem advoga pelo fim dos SPAs é que eles são desnecessários para websites simples, meu ponto é que isso não significa que sejam piores para estes cenários. Em projetos onde o frontend é basicamente CRUD com forms e tables (como era a internet antigamente), sim, um HTMX vai dar conta. Isso não significa que um projeto full CSR não seria uma boa escolha. Isto porque:
É falsa a premissa de que um SPA é mais lento
Um SPA só demora para carregar no loading inicial do bundle, e a partir daí é cacheado pelo navegador até que a versão do projeto mude. Toda atualização de tela é instantânea. Um projeto SSR, por outro lado, terá carregamentos e dependerá da conexão para toda troca de página e para muitas atualizações da DOM. Antes que se possa reclamar do bundle size disso: um SPA grande terá apenas alguns megas, o que para a internet de hoje é um tamanho irrisório. Além disso, todos frameworks de SPA (e mesmo o Next) implementam lazy-loading de páginas e componentes, então o bundle inicial nunca é o projeto inteiro: o usuário espera o carregamento apenas do que ele precisa ver.
Inclusive, se experiência pessoal conta, na empresa onde trabalho passamos por uma refatoração de 3 projetos legados em Angular 12 para 3 projetos em Next 14. São projetos com praticamente o mesmo número de páginas e funcionalidades, mas apenas com design diferente (além da própria stack, obviamente). Os 3 projetos Next são muito mais lentos em qualquer troca de página, enquanto os 3 projetos Angular não apresentam delay perceptível em qualquer troca de página ou atualização de DOM.
Optar por um não-SPA significa se comprometer com a visão de que aquele projeto nunca evoluirá ao ponto de necessitar de mais recursos
É uma aposta que se faz para anos e arrisca uma eventual refatoração completa e manutenção de um legado. Todos sabemos como um negócio (com sua natureza e necessidades) evolui rapidamente e pode ser bem diferente em poucos anos. Abrir mão de um gerenciamento de estado global significa, na prática, duas coisas:
- depender do local-storage, session-storage e cookies para manter estado entre componentes, o que limita a estrutura de dados que você poderá guardar a apenas "JSON-serializables";
- transmitir estado entre páginas apenas via query-params, o que limita em muito o tipo de informação que pode ser transmitida.
SPA + REST torna um sistema mais eficiente
Usar o REST significa que uma mesma página não terá que ser inteiramente re-computada pelo servidor (que está ocupado com outras N requisições simultâneas). Por exemplo: em uma página de um SPA onde é necessária, além do template, a consulta de 3 tabelas diferentes para hidratá-lo, caso apenas um dos dados precise ser atualizado, o SPA buscará apenas aquele dado específico e re-renderizará a DOM (que já está carregada localmente) com ele. Um não-SPA teria que recomputar todo o conteúdo da página, perdendo este poder de buscar apenas a informação necessária de forma granular.
Em um dado momento, este programador com quem conversava disse que os SPAs que inauguraram o problema dos longos loading spinners em uma tela e que isso não existia antes. Ora, é óbvio que um projeto onde o servidor consegue apenas servir a tela inteira de uma vez não apresentará loading spinners: ao trocar de página, enquanto a página seguinte não é inteiramente renderizada e servida o usuário fica preso naquele estado. Um SPA, entretanto, consegue exibir imediatamente tudo que não depende de um carregamento específico que hidradará apenas uma seção, preenchendo aquele espaço em branco com um spinner ou um skeleton. Isso, como é sabido, é importantíssimo para a UX por evitar rage clicks e por ocupar o usuário com seções que ele pode querer ver enquanto espera.
Um Web App não é apenas uma interface para manipular o banco de dados
O nome disso é Insomnia ou Postman. Segregar um sistema em dois repositórios diferentes permite que cada um foque em responsabilidades diferentes: o backend na manipulação e consistência dos dados; o frontend na apresentação do negócio e no direcionamento do usuário. Embutir os dois em um mono repo significa jogar para um mesmo repositório dois projetos distintos (cada um com suas dependências e pipes de qualidade específicas), o que aumenta a complexidade, não o contrário.
Quando muitos advogam pela segregação de responsabilidade entre camadas de um backend, que se comunicarão apenas por contratos, por que a mesma ideia não se aplicaria para dois projetos tão distintos na natureza? Enxergar a view como apenas mais uma camada do backend significa ter em mente apenas os tipos de templates que existiam há 15 anos.
Conclusão
Todo programador deveria saber que na nossa área a única coisa que é sempre mentira é que uma única solução será sempre verdade. Em nenhum momento defendo que SPA + REST é o melhor jeito de se programar. Se eu tivesse que chutar, acredito que o padrão REST tenha se tornado a lingua franca do desenvolvimento web apenas porque é o que mais acomodou a separação entre backend e frontend para que pudessem evoluir de maneira independente.
De qualquer modo, para defender que o JS é apenas um adicional irrelevante para um sistema e que o REST mais prejudica do que beneficia num projeto é preciso antes provar que não existe nenhum caso onde um projeto SPA poderia ser completamente reescrito desta forma sem aumentar sua complexidade e preservando todos seus comportamentos. Será que sem o conceito de SPA o Facebook, Instagram ou o Spotify existiriam da mesma forma? Ainda que o produto final fosse possível de ser replicado integralmente desta forma, o código necessário seria maior ou menor; mais complexo ou menos complexo? Um código escalável e organizado é tão importante quanto a viabilidade do produto final. Então, para além da afirmação de que "é possível reescrever muitos apps sem ser como SPA", eu coloco uma questão: "e o que ganhariamos com isso? O usuário, a empresa ou mesmo o programador ganharia algo com isso?".
Apesar de tudo, minha experiência não é tão vasta assim (e certamente bem menor que a do nosso colega com 40 anos de carreira). Em frontend, minha experiência se limita a SPAs em Angular e Next. Na verdade, já tive que trabalhar em um projeto mono-repo não-SPA, Django+Vue, e quando olho para trás não enxergo nenhum ganho nisso. É possível que existam outras frameworks e/ou estratégias que resolvam estes problemas que apontei. Adoraria aprender mais sobre.
Qual sua opinião sobre o assunto? Discorda de algo que eu disse? Tem algum material para indicar que tenha bons argumentos para defender o fim dos SPAs?