Voltar aos projetos
PodcastBFF PatternMicrofrontends

Arquitetura de Micro Front-end

Episódio do podcast da DBC Company sobre arquitetura de Micro Front-end — Single-SPA, BFF, eventos customizados e migração de monolito.

2023~60 minTech Lead
Capa do projeto Arquitetura de Micro Front-end

O contexto

Esse é o segundo episódio do podcast da DBC Company em que eu participei, ainda em 2023, enquanto eu liderava tecnicamente a reconstrução de um canal digital de um cliente. O tema era Arquitetura de Micro Front-end.

A conversa foi conduzida pela Cristina Jung e pelo Alisson Campos — dois instrutores da trilha de front-end do programa Vem Ser. O outro convidado era o Anderson Costa, apelidado de "Montanha" (carinhosamente, pela equipe), arquiteto de software que atuava comigo no mesmo cliente.

Foi o episódio mais técnico que eu fiz nesse formato. Sem "lição de vida", sem discursinho — só gente que estava, naquele momento, no meio de uma reconstrução de plataforma, trocando o que estava aprendendo na marra.

🔗 Ouvir no Spotify

O desafio real

Quando você está reconstruindo um canal crítico em produção, falar sobre a arquitetura em voz alta é um ato de coragem.

A gente estava naquele momento em que toda decisão tinha custo real — testes de carga rodando, primeira release oficial chegando em poucos dias, primeira squad plugando no novo modelo, BFF em produção pela primeira vez. Não era uma conversa sobre teoria. Era o que estava vivo.

A regra implícita do papo foi a mesma do primeiro podcast: só entrava no episódio o que passava pelo crivo de "isso está rodando aqui, do meu lado".

O que é Micro Front-end — e por que a gente precisou

A gente começou pelo básico porque a audiência não era só técnica. Micro Front-end surgiu como resposta à mesma coisa que originou microsserviços: monolitos de front-end ficaram grandes demais pra escalar. Um repositório com milhares de módulos, deploy arriscado, refatoração que exigia rodar a suíte inteira pra trocar um botão.

A primeira tentativa do time, lá em 2020, foi um fracasso. A aplicação legada era gigantesca, com CoffeeScript, anos de dependências, e o modelo escolhido (baseado na arquitetura da Zalando) era oneroso demais pra puxar as camadas do legado.

A virada veio em 2021: parar de tentar migrar o monolito, começar do zero e ir substituindo fatia por fatia — o que depois passou a ser conhecido como Strangler Fig aplicado ao front-end. Manter dois sistemas rodando em paralelo, com o legado só recebendo correção de vulnerabilidade, enquanto o novo crescia módulo a módulo.

Foi essa abordagem que sobreviveu aos testes de performance e entrou em produção.

Single-SPA, Module Federation e a escolha de stack

Foi onde o papo pegou. A gente tinha feito prova de conceito com várias abordagens antes de cravar.

Module Federation (Webpack 5) era a mais badalada na comunidade. Mas o Anderson foi cirúrgico: a abordagem da Zalando, baseada em MF, era poderosa, mas complexa demais pro nosso contexto. O time estava contratando gente nova, era necessário onboarding rápido, e o framework tinha que caber em júnior, pleno e sênior sem fricção.

Single-SPA + importmap foi a escolha. Os motivos, do meu lado:

  • Curva de aprendizado menor. Júnior consegue entrar, pleno consegue se desenvolver dentro, sênior consegue pular as abstrações e ir direto na API core quando precisa de algo mais fino.
  • Documentação rica. Cursos, exemplos, repositórios abertos e várias aplicações funcionais e rodando, mantida pelo time do single-spa-js.
  • Pragmatismo com Webpack. O time do Webpack estava migrando pra Turbopack/Rust, mas o ecossistema ainda vivia em cima do Webpack. Single-SPA acompanhava bem.
  • Caminho de saída. Se a ferramenta morresse amanhã, o código continuava sendo React padrão — você conseguia extrair os componentes pra um monolito sem reescrever nada. Com três linhas de configuração no entry point, uma parcela virava um standalone React: subia sozinha, sem o shell, sem o host.
    Foi uma escolha defensiva. Não a mais hype. A mais sustentável.

BFF — o que decidiu pra gente

O Anderson liderou essa parte e foi onde ele brilhou. A decisão era: cada microsserviço com seu micro front-end, ou BFF agregando?

A conta foi simples. Se cada micro front-end fosse par-a-par com seu microsserviço, teríamos que ter múltiplas squads mantendo projetos pequenos — ou quebrar a regra de "uma squad mantém o produto inteiro". As duas opções eram inviáveis.

BFF virou padrão. Agregador de microsserviços por domínio, com camadas extras de segurança (token validation, rate limiting, validação de payload) que ficam isoladas do front. O front consome um endpoint /pessoa que já vem com todos os dados agregados de N microsserviços.

E a regra de ouro que ele cravou: BFF não conecta em banco, não tem regra de negócio. É só gateway. Quem cruza regra de negócio é microsserviço. Quem decide o que expor é o BFF.

Isso virou uma das nossas decisões mais estruturantes.

Qualidade — onde a régua ficou alta

Esse bloco eu e o Anderson falamos juntos, porque era onde o projeto tinha mais peso.

  • Testes unitários com cobertura mínima de 95%. Abaixo disso, build não passa.
  • Testes de integração com Cucumber, organizados por features de negócio. Se a feature não tem critério de aceite, não entra.
  • Sonar como gate final — bad smells, código deprecado, bibliotecas com vulnerabilidade conhecida.
  • Code review estruturado com aprovação obrigatória.
  • Playground de desenvolvimento (criado pelo Anderson) pra evitar que cada dev subisse o ecossistema inteiro na máquina. Você sobe só seu micro front-end local, pluga na URL compartilhada via HTTPS, e o resto do sistema já está rodando com a última versão. Subir o serviço dos outros virou opcional.
    O ganho veio rápido. Em um ano, estabilizamos os produtos. As aberturas de problema por bug básico caíram pra zero. O time começou a entender que teste não era burocracia — era menos trabalho depois.

Estado global — onde eu fui contra a corrente

Esse foi meu momento do papo. A pergunta da Cristina foi direta: qual o melhor gerenciador de estado global?

Respondi com o que eu defendia internamente: nenhum, se der pra evitar.

A premissa do Micro Front-end é que cada parte é isolada e autônoma. Meu micro front-end não conversa com o front-end da outra área. Não sei o DOM dele, ele não sabe o meu. Se eu instalar Redux na raiz, quebra a premissa — e quebra a vida de quem for manter.

A solução que funcionou foi usável com o que o navegador já dá:

  • Eventos customizados (new CustomEvent) despachados via window.dispatchEvent quando algo acontece — "saldo foi escondido", "fatura foi atualizada". Quem precisar escuta, quem não precisar ignora.
  • sessionStorage e localStorage pra preferências com vida útil maior (tema, idioma).
  • Context API do React pra estado local dentro de cada parcela.
    A frase que cravou a posição: "Se eu precisar de Redux pra esconder um saldo na tela, tá errado."
    O Anderson complementou com algo que eu subscrevi: evento em escala derruba aplicação. Usamos muito poucos. Tínhamos desenhado 6-7, usamos 1. O resto virou utilitário compartilhado — uma biblioteca interna de métodos comuns (autenticação, segurança, alerta de violação). Você importa o método, usa, não dispara evento global.
    Foi, talvez, a decisão mais contraintuitiva do projeto. E a que mais pagou depois.

Empoderamento de áreas e Kanban

O Anderson trouxe uma metáfora que ficou: modelo de franquias.

A empresa-mãe dá a regra do jogo. A marca é essa, o prédio é esse, o cardápio é esse, com adaptação regional. Você não vende o que a franqueadora não permite.

No nosso contexto, isso virou arquiteturas de referência obrigatórias + opcionais:

  • Mandatórias: cobertura de testes, HTTPS mesmo local, Sonar, code review, segurança.
  • Opcionais: framework, biblioteca de UI, gerenciador de estado local, organização de pastas.
    Dentro desses limites, cada área tem autonomia pra entregar seu pacote JavaScript compilado desde que respeite os contratos. Sem aprovar componente por componente com o core. Sem esperar pelo time central.
    No meu lado, falei do método: Kanban com iteração contínua. Sem prazo de sprint fixo, sem "pacotão" no final. MVP incrementado, validação no caminho, escopo ajustado conforme o cliente descobre o que precisa.

O que eu não falei nesse episódio

Tem um detalhe técnico que ficou de fora do papo, mas que pesa quando olho pra decisão com olhar de hoje.

A escolha de importmap foi, talvez, a melhor que tomei naquele projeto. Mas a escolha teve um custo que eu não verbalizei na entrevista: na época, importmap não era amplamente suportado pelos browsers. E mais do que isso — o React em si ainda não era distribuído nativamente como ES Modules. A distribuição padrão era UMD. Existiam forks como @esm-bundle que empacotavam o React como ESM, mas isso adicionava uma camada de fragilidade que a gente não queria assumir em produção.

A gente cogitou ir pra ES Modules nativo desde o início. Foi avaliado. Foi descartado conscientemente: o trade-off entre pagar o custo de manter um fork desatualizado de React vs. aceitar SystemJS + UMD como camada transitória não compensava. Foi uma decisão aceita, não uma surpresa.

SystemJS com fallback pra UMD virou o caminho. Funcionou, amarrou o projeto a um formato de bundle que o ecossistema já estava deixando pra trás, mas manteve tudo em produção.

A conta está chegando agora: React 19 já dropou suporte pra UMD. Isso significa que a stack que a gente montou em 2023 vai ter que ser revista. E é exatamente isso que estamos conduzindo — um estudo pra migrar pra ES Modules nativo, sustentado por importmap moderno, sem o andaime de SystemJS que a gente precisou usar na época. Com React 19 exigindo ESM e importmap amplamente suportado pelos browsers, o caminho está finalmente viável.

Esse é o tipo de detalhe que raramente entra em podcast. Decisão boa não é decisão sem custo — é decisão cujo custo você aceita pagar sabendo que vai ter que pagar de novo quando o cenário mudar.

Se eu colocasse isso no episódio, eu teria dito: importmap foi a decisão certa. A forma como precisamos implementar importmap na época foi o preço que pagamos pelo estado do ecossistema naquele momento — e foi um preço que aceitamos pagar de olho aberto.

O que ficou desse papo

Esse episódio é diferente do primeiro. Não é sobre como liderar gente — é sobre como decidir arquitetura com gente real, em projeto real, com prazo real.

O Anderson e eu estávamos no meio do caminho. Não sabíamos se a abordagem ia sobreviver à primeira release oficial. Ela sobreviveu. E virou a fundação de tudo que veio depois na minha trajetória em canais digitais críticos.

Se eu ouvir hoje, ouço o mesmo que ouviria no podcast anterior: uma versão anterior de mim, pensando em voz alta, tomando decisão que eu ainda sustentaria.

A ferramenta mudou. O raciocínio continua.

Esse projeto é um registro de um episódio de podcast técnico, não um case de implementação. Os detalhes técnicos foram preservados como conversa — o foco aqui é o raciocínio que sustentou as decisões, não a especificação da arquitetura em produção.