Dev & EngARTIGO

Seu frontend virou uma camada de integração?

Seu frontend virou uma camada de integração?
Imagem: John Calistro

Quando uma tela precisa conhecer várias APIs, controlar o cache, reconciliar estados e ainda entender algumas regras do negócio, talvez seja hora de olhar com mais atenção para o que estamos carregando no navegador.

Pense em uma tela de aprovação de pedidos.

A pessoa abre uma lista, escolhe um pedido, confere as informações e decide se aprova ou devolve para correção.

Por trás dessa tela pode estar acontecendo bastante coisa.

O frontend↳Front-end60 conteúdosFront-end em larga escala: quando seu projeto vira um Frankenstein (e como evitar)Dev (Back & Front) · mar 2026Build e bundling no front-end: 7 decisões que impactam performance de verdadeDev (Back & Front) · abr 2026Como modelar APIs pensando no front-end: 8 práticas para evitar retrabalho entre timesDev (Back & Front) · abr 2026Ver tudo em Dev (Back & Front) → busca os pedidos em um serviço e consulta os dados do cliente em outro, procura o limite comercial em uma terceira API e combina essas informações para decidir o que será mostrado.

Quando o pedido é aprovado, ainda precisa atualizar a lista, atualizar ou invalidar o detalhe, recalcular algum resumo e tomar cuidado para que uma resposta antiga não chegue atrasada e coloque na tela um estado que já não existe mais.

No fim das contas, a funcionalidade continua sendo “aprovar um pedido”, mas o frontend agora conhece vários serviços e participa da coordenação entre eles.

Não há nada de errado em fazer composição de dados no cliente, fazemos isso há muito tempo, o problema aparece quando manter essa composição começa a dar mais trabalho do que a própria funcionalidade a que ela atende.

É isso que eu chamo de fadiga do SPA.

Não estou dizendo que uma aplicação chegou nesse ponto porque usa React, Vue, Angular ou qualquer outro framework e também não usaria isso como desculpa para reescrever tudo.

Antes disso, eu tentaria entender por que cada responsabilidade foi parar no navegador.

Algumas estarão ali porque precisam estar, já outras podem ter chegado porque colocar mais um hook, mais uma chamada e mais um estado local era mais rápido do que parar para discutir o contrato da API.

Alguns anos depois, alguém abre a tela e encontra tudo isso junto, código legado na sua mais linda forma.

Tem coisa que realmente precisa ficar no cliente

Um editor gráfico precisa responder enquanto a pessoa arrasta um objeto. Uma planilha mantém alterações locais o tempo todo. Um editor colaborativo precisa lidar com seleção, digitação, desfazer, refazer e várias outras interações sem consultar o servidor a cada movimento.

Nesses casos, faz sentido ter muita lógica e estado no navegador. Se cada arraste de um objeto precisasse esperar uma resposta do servidor, a experiência seria péssima.

A tela de aprovação de pedidos provavelmente tem outro tipo de necessidade.

Boa parte das informações importantes já está persistida no servidor. A aprovação também ocorre no backend, seguindo regras que pertencem ao sistema responsável pelo pedido.

O navegador continua cuidando da interface, claro, mas não precisa necessariamente reconstruir toda a visão do negócio consultando vários serviços.

Um texto que a pessoa ainda está digitando é um bom exemplo de estado local. Já o resultado oficial de uma aprovação pertence ao sistema que executou a operação.

Podemos manter uma cópia dessa informação no frontend, e muitas vezes isso melhora bastante a experiência. Precisamos apenas saber quando ela deixará de ser válida e como será atualizada.

Bibliotecas de consulta e cache ajudam muito nesse trabalho. Uma SPA bem construída consegue fazer chamadas em paralelo, reaproveitar dados e evitar uma série de problemas.

Eu tentaria descobrir se estamos usando todos esses mecanismos porque a interação realmente precisa deles ou se estamos compensando APIs que não entregam os dados da forma como a tela precisa.

O servidor nunca foi embora

Nos últimos anos apareceram várias abordagens tentando mudar um pouco essa divisão de trabalho.

O htmx, por exemplo, permite atualizar partes da página usando HTML gerado pelo servidor. A arquitetura de ilhas do Astro deixa JavaScript de interface apenas onde há necessidade de interação.

Nos React Server Components, parte dos componentes pode ser executada fora do navegador sem enviar para o cliente o código usado somente por eles.

São soluções diferentes, e eu não colocaria tudo no mesmo pacote.

O que acho interessante é que nenhuma delas obriga a escolher entre uma aplicação inteira no navegador e páginas que recarregam a cada clique. Podemos ter HTML vindo do servidor e usar JavaScript onde ele realmente melhora a experiência.

Existe também um problema que não é exatamente técnico.

Imagine que o frontend precise de uma informação diferente para melhorar uma tela, mas todas as mudanças da API passam por outro time e entram em uma fila de prioridades. Até uma pequena alteração pode virar uma negociação.

Uma camada de backend voltada àquela experiência pode dar mais autonomia ao time de frontend. Essa é uma das ideias por trás do padrão Backend for Frontend, o BFF, descrito por Sam Newman.

Isso não quer dizer que SPAs estejam acabando. Temos apenas outras formas de dividir o trabalho, e para mim essa discussão é mais útil do que tentar decidir se SPA é boa ou ruim.

SPA, SSR, Server Components, SDUI e BFF são coisas diferentes

Press enter or click to view image in full size

Cinco cartões distinguem as responsabilidades tratadas por SPA, SSR, React Server Components, server-driven UI e BFF.
Os padrões podem coexistir e não são substitutos diretos.

Esses termos aparecem juntos com tanta frequência que, às vezes, parecem partes da mesma solução. Não são.

Uma SPA organiza a navegação e a atualização da interface sem carregar um novo documento completo a cada mudança de tela.

Isso não quer dizer que o primeiro HTML precise obrigatoriamente ser criado no navegador. Uma aplicação pode começar com HTML gerado no servidor e depois continuar navegando como SPA.

SSR, Server-Side Rendering, é renderização no servidor. No caso do React, as APIs de renderização no servidor podem gerar o HTML inicial antes de enviá-lo ao navegador.

Isso não elimina automaticamente o JavaScript usado na interação e também não resolve sozinho o cache, a autorização ou a coordenação entre APIs.

Os React Server Components tratam de uma outra separação. Alguns componentes podem ser executados durante o build ou quando uma requisição é atendida, sem enviar o código desses componentes ao navegador.

Quando há interação, entram os componentes do cliente. SSR e Server Components podem trabalhar juntos, mas não são a mesma coisa.

Em uma server-driven UI, ou SDUI, o servidor envia uma descrição da interface que o cliente sabe interpretar. Não precisa ser HTML.

No artigo do Airbnb sobre a Ghost Platform, por exemplo, há descrições de seções, layouts e ações usadas entre web, iOS e Android.

Isso é diferente de retornar um trecho de HTML, como acontece com htmx. Nesse caso, não precisamos, obrigatoriamente, criar uma infraestrutura de schemas, renderizadores e componentes compartilhados entre várias plataformas.

O BFF, Backend for Frontend, resolve outro tipo de problema.

Ele adapta o backend para uma experiência específica, pode consultar vários serviços, juntar informações e entregar para o frontend um contrato mais adequado para aquela tela sem precisar renderizar HTML.

Uma SPA pode continuar sendo SPA e consumir um BFF normalmente.

Eu gosto de separar esses conceitos porque fica mais fácil escolher alguma coisa quando sabemos qual problema estamos tentando resolver.

Se o frontend sofre porque precisa coordenar cinco APIs diferentes, trocar apenas a forma como o HTML é renderizado talvez não ajude muito. Se o problema é JavaScript demais no navegador, criar um BFF e manter o mesmo frontend provavelmente também não mudará isso.

Voltando ao exemplo dos pedidos

Na nossa tela de aprovação, parte da coordenação poderia ficar no backend.

Em vez de a interface conhecer vários contratos, ela poderia receber uma resposta preparada para aquele fluxo, com os dados do pedido, as informações necessárias do cliente e as ações disponíveis naquele momento.

Isso não quer dizer que tudo precise vir em uma única requisição. Se existe uma informação secundária que demora mais para chegar e não impede a pessoa de começar a trabalhar, ela pode ser carregada depois.

Press enter or click to view image in full size

Fluxo mostra o navegador consumindo uma visão composta e o backend de domínio verificando a autorização e o estado do pedido ao aprovar.
Compor a experiência não significa duplicar a regra de negócio.

Não se trata apenas de diminuir a quantidade de requests que aparecem no DevTools. O que me interessa é reduzir o conhecimento sobre integração que aquela tela precisa carregar.

Tem também uma questão de segurança que não muda.

Imagine que o backend envie uma informação dizendo que o botão Aprovar deve aparecer. Isso serve para montar a interface, não para autorizar a operação.

Quando a pessoa clicar no botão, o serviço responsável pela aprovação ainda precisa conferir identidade, permissão e o estado atual daquele pedido.

A informação exibida pode ter ficado velha, e nada impede alguém de fazer a mesma chamada sem passar pela interface.

A regra que decide se um pedido pode ou não ser aprovado continua pertencendo ao domínio responsável por aquela operação. Copiar essa regra para um BFF criaria duas versões da mesma coisa para manter.

Eu também não criaria um serviço separado logo de cara.

Antes verificaria se uma rota de composição dentro do backend que já existe resolve o problema.

Um BFF separado começa a fazer mais sentido quando existe uma razão clara para ter contrato, responsabilidade e evolução independentes. Se essa necessidade não existe, podemos terminar com mais um deploy, mais logs, mais alertas e mais uma aplicação para cuidar quando uma rota dentro do sistema atual teria resolvido.

Com um contrato melhor organizado, talvez a SPA atual já fique simples o suficiente. Ela recebe os dados de que precisa e continua cuidando de seleção, filtros, mensagens e feedback imediato.

Dependendo da tela, isso pode ser tudo.

A complexidade não desaparece quando muda de lugar

Mover a composição para o backend pode simplificar bastante o código do frontend, mas os serviços que precisavam ser consultados continuam existindo. Agora o BFF precisa lidar com eles.

Se um BFF consulta vários serviços, precisamos pensar em timeout e em falhas parciais.

Por exemplo, se o serviço de histórico comercial estiver fora do ar, a lista de pedidos ainda pode abrir? A pessoa pode aprovar mesmo assim ou aquela informação é necessária para a operação?

A interface também precisa saber diferenciar uma consulta que voltou sem resultado de outra que falhou.

Essas decisões continuam existindo, só passaram para outro lugar.

Juntar chamadas no backend pode diminuir a comunicação entre navegador e servidor, mas existe outro lado. Se uma resposta depende de quatro serviços, ela pode acabar esperando pelo mais lento.

A documentação da Microsoft sobre BFF menciona questões como salto adicional de rede, custo operacional e duplicação de código.

Por isso eu não usaria apenas a quantidade de chamadas no DevTools para concluir que uma mudança melhorou a aplicação.

Com renderização no servidor também aparecem outras preocupações. Cache é uma delas.

Se estamos trabalhando com conteúdo personalizado, uma chave de cache errada pode entregar para um usuário dados que pertencem a outro, ou para um tenant informações de outro tenant.

O problema mudou, mas continua sendo sério.

Em uma SDUI baseada em schema existe outra limitação. O servidor só consegue pedir para o cliente montar aquilo que o cliente já sabe montar.

Mudar o JSON enviado pelo servidor não faz aparecer magicamente um componente que ainda não existe no aplicativo instalado. Dependendo da mudança, continua sendo necessário atualizar o cliente, e a plataforma precisa cuidar de versões, compatibilidade e algum tipo de fallback.

O próprio artigo do Airbnb sobre a Ghost Platform mostra quanto trabalho existe em schemas, frameworks de cliente e documentação.

É uma arquitetura interessante, mas eu não partiria da ideia de que, porque funcionou para o Airbnb, necessariamente deixará uma aplicação menor mais simples.

Até atualizar HTML parcial tem seus detalhes. Trocar um pedaço do DOM não resolve automaticamente o histórico de navegação, o foco do teclado ou o feedback para quem utiliza leitor de tela.

Cada escolha resolve alguns problemas e traz outros.

E agora temos IA escrevendo essas camadas

Hoje podemos pedir a um assistente de código para criar hooks, stores, adaptadores, endpoints e testes a partir de uma descrição. Ele provavelmente fará isso bem rápido.

Só que criar código não explica por que cada uma dessas peças precisa existir.

Podemos receber um PR muito bem escrito, com testes passando e código aparentemente organizado, que cria mais uma cópia de um dado que já estava no servidor, repete uma transformação existente ou coloca uma regra de negócio no frontend porque era o lugar mais fácil de fazê-la funcionar.

O código pode funcionar normalmente e, mesmo assim, deixar a arquitetura pior.

Também dá para exagerar na outra direção. Peça para uma IA↳Inteligência artificial440 conteúdosUX e IA: Transformando Experiências Digitais com Inteligência ArtificialProduto & UX · jan 2025MCP: O que é e por que você vai ouvir falar disso em breve?AI · jul 2025IA generativa e a urgência de reconstruir nossa relação com a verdadeAI · jun 2025Ver tudo em AI → “modernizar” uma aplicação usando BFF, React Server Components e server-driven UI e provavelmente aparecerá uma solução usando tudo isso.

Eu perguntaria se havia necessidade de tudo aquilo antes de aprovar a mudança.

Durante uma revisão, tentaria responder algumas perguntas:

  • Qual estado realmente precisa existir no cliente?
  • Onde fica a regra que decide se uma operação pode acontecer?
  • O que a tela faz quando uma dependência falha?
  • O que acontece se uma resposta antiga chegar depois de uma nova?
  • Que informação precisa ser atualizada depois de uma operação?
  • O que deixou de existir depois que criamos essa nova camada?

Gosto especialmente da última.

Se criarmos uma abstração nova, mas continuarmos mantendo toda a estrutura anterior, eu gostaria de entender o que ganhamos. Pode existir uma ótima explicação, só precisa estar clara.

Os testes também deveriam refletir esse tipo de preocupação.

Testar somente se um payload foi transformado de A para B não cobre problemas de autorização, cache e concorrência.

Na tela de pedidos, eu testaria uma sessão expirando no meio da operação, duas pessoas tentando alterar o mesmo pedido e uma aprovação que funcionou no backend, mas cuja atualização falhou no frontend.

A IA pode ajudar a criar esses testes. A escolha dos cenários continua com o time.

Eu testaria a mudança em uma tela

Se eu pegasse hoje uma aplicação com esse tipo de problema, não começaria desenhando uma nova arquitetura para o produto inteiro.

Escolheria uma tela difícil de manter e mapearia as APIs que ela chama, o estado local, as regras que conhece e os lugares onde o mesmo dado aparece duplicado.

Depois tentaria encontrar a menor mudança capaz de resolver aquilo que apareceu nesse levantamento.

Eu organizaria as opções mais ou menos assim:

Necessidade dominante O que eu avaliaria Onde eu prestaria atenção Muita interação local, edição contínua ou funcionamento offline Manter bastante lógica no cliente, provavelmente usando uma SPA Sincronização e conflitos Conteúdo com poucos pontos realmente interativos HTML estático ou renderizado no servidor, adicionando interação onde necessário Carregamento e resposta real da interface Formulários, consultas e operações muito ligadas ao servidor HTML com melhorias progressivas ou atualizações parciais Navegação, acessibilidade↳Acessibilidade11 conteúdosO que é Acessibilidade Web e como tornar seu site mais acessívelDev (Back & Front) · mar 2019Design para veteranos digitais: acessibilidade para nós mesmosProduto & UX · jan 2020Dicas de Front-End para usabilidade, acessibilidade, performance e responsividadeProduto & UX · fev 2025Ver tudo em Produto & UX → e mensagens de erro Frontend precisando coordenar várias APIs Composição no backend e, quando fizer sentido, um BFF Não duplicar regras e não criar infraestrutura sem necessidade Mesma composição de interface em várias plataformas SDUI com contratos conhecidos pelos clientes Compatibilidade, versões e fallback

Nada impede que essas abordagens convivam.

Um editor pode ter bastante lógica no navegador enquanto a área administrativa do mesmo sistema trabalha de outra forma. Nem dentro da mesma tela tudo precisa seguir a mesma regra.

Informações principais podem chegar primeiro e recursos menos importantes podem carregar depois.

Antes de mudar qualquer coisa, eu tentaria medir como aquela tela funciona hoje.

Eu olharia quanto JavaScript está sendo transferido e executado, quanto tempo demora para a informação que interessa aparecer, como a interface responde às interações e qual é a taxa de erro daquele fluxo.

No backend acompanharia latência, dependências e custo, tentando comparar situações parecidas.

Cache quente e conexão rápida fazem praticamente qualquer demonstração parecer boa. Uma rede ruim e cache frio contam outra história.

Depois da mudança, eu voltaria ao código para ver quantos contratos a tela ainda conhece, se uma alteração de regra continua exigindo mudanças em vários lugares e se ficou mais fácil descobrir onde está o problema quando alguma coisa quebra.

Se reduzimos JavaScript, mas agora a resposta ficou mais lenta e criamos um serviço que ninguém quer manter, não tenho certeza de que melhoramos muita coisa.

Se apenas ajustar os contratos das APIs resolver o problema, ótimo.

Nem toda melhoria precisa terminar com um framework novo ou com um diagrama de arquitetura maior.

Press enter or click to view image in full size

Quadro conecta experiência no navegador, comportamento do servidor e esforço de manutenção como critérios conjuntos de decisão arquitetural.
Retirar custo do cliente não basta para provar uma simplificação.

Alguém precisa conseguir explicar por que cada coisa está ali

Eu manteria tranquilamente uma SPA que atende bem ao produto e tem responsabilidades claras. Não vejo motivo para mudar só porque apareceu outra abordagem interessante.

O que me faria olhar com mais atenção para a arquitetura seria não conseguir explicar por que aquela tela precisa conhecer tantos serviços, manter várias cópias da mesma informação e coordenar estados que pertencem ao backend.

Eu começaria pelos contratos, olharia para a divisão das responsabilidades e só depois pensaria em tecnologia.

BFF, renderização no servidor e server-driven UI são algumas das opções. Pode ser que nenhuma delas seja necessária.

Depois da mudança, eu gostaria de conseguir dizer o que ficou mais fácil de entender, testar e manter.

Se a dificuldade apenas foi parar em outro serviço, ela continua lá.

Com código gerado por IA, eu usaria o mesmo critério. Ela consegue escrever a camada. Nós é que vamos ter de mantê-la.

Se você pegasse hoje uma tela do seu produto para revisar, o que tiraria do navegador e o que deixaria nele?

John Calistro é mentor de empregabilidade em tecnologia e autor de conteúdos práticos sobre portfólio que contrata, IA para estudar e revisar código, entrevistas e posicionamento no LinkedIn. Ajuda iniciantes e migrantes a sair da estagnação e conquistar o 1º emprego com projetos que mostram impacto real.

Mais de John Calistro
Ver perfil →