paint-brush
Fazendo uma jornada para a migração de microfrontend - Parte 1: Designpor@isharafeev
1,323 leituras
1,323 leituras

Fazendo uma jornada para a migração de microfrontend - Parte 1: Design

por Ildar Sharafeev13m2023/07/12
Read on Terminal Reader

Muito longo; Para ler

A migração para uma arquitetura de microfrontend exigiu um investimento significativo em termos de estrutura organizacional e base operacional. Seria melhor começar com uma arquitetura monolítica distribuída que aproveitaria o carregamento lento (importações dinâmicas). Haveria uma necessidade essencial de dividir a base de código em diferentes áreas de propriedade controladas por equipes diferentes.
featured image - Fazendo uma jornada para a migração de microfrontend - Parte 1: Design
Ildar Sharafeev HackerNoon profile picture

No mundo digital acelerado de hoje, onde agilidade e escalabilidade são cruciais, as empresas estão constantemente buscando maneiras de melhorar o desempenho e a capacidade de manutenção de seus aplicativos da web.


Uma abordagem popular para alcançar esses objetivos é migrar de uma arquitetura monolítica para uma distribuída (ou micro-frontend). Esta série de artigos, “Micro-frontend Migration Journey”, compartilha minha experiência pessoal ao realizar tal migração durante meu tempo na AWS.


ISENÇÃO DE RESPONSABILIDADE : Antes de começarmos, é importante observar que, embora este artigo compartilhe minha experiência pessoal, não posso divulgar nenhum detalhe proprietário ou interno de ferramentas, tecnologias ou processos específicos na AWS ou em qualquer outra organização.


Estou empenhado em respeitar as obrigações legais e garantir que este artigo se concentre apenas nos conceitos e estratégias gerais envolvidos na jornada de migração de microfrontend.


O objetivo é fornecer insights e lições aprendidas que possam ser aplicáveis em um contexto mais amplo, sem divulgar nenhuma informação confidencial.

Motivação para Migração

Aprendi sobre micro-frontends (acho que como muitos de vocês) no artigo do blog de Martin Fowler. Ele apresentou diferentes maneiras de compor a arquitetura de micro-frontend de maneira independente de framework.


Conforme me aprofundei no assunto, percebi que nossa arquitetura monolítica existente estava se tornando um gargalo significativo para a produtividade de nossa equipe e impedindo o desempenho geral de nosso aplicativo.


Um dos principais fatores que me levou a considerar uma migração foi o aumento do tamanho do pacote de nosso aplicativo.


Depois de conduzir uma análise completa do pacote no verão de 2020, descobri que desde seu lançamento inicial no início de 2019, o tamanho do pacote (gzipado) aumentou de 450 KB para 800 KB (quase 4 MB analisados) - quase o dobro do tamanho original.


Considerando o sucesso de nosso serviço e prevendo seu crescimento contínuo, ficou claro que essa tendência persistiria, impactando ainda mais o desempenho e a manutenção de nosso aplicativo.


Embora estivesse entusiasmado com o conceito de micro-frontends, também reconheci que ainda não estávamos prontos para adotá-los devido a desafios específicos que enfrentamos:


  1. Estrutura organizacional pequena: na época da minha análise, nossa organização era relativamente pequena e eu era o único engenheiro de front-end em tempo integral na equipe. A migração para uma arquitetura de microfrontend exigiu um investimento significativo em termos de estrutura organizacional e base operacional.


    Era crucial ter uma estrutura madura que pudesse efetivamente lidar com a arquitetura distribuída e refletir as dependências entre os diferentes componentes frontend.


  2. Domínio de negócios limitado: embora os microfrontends possam ser divididos com base em contextos limitados e recursos de negócios (saiba mais no post “ Design orientado a domínio na arquitetura de microfrontend” ), nosso domínio de negócios principal não era extenso o suficiente para justificar uma separação completa em vários micro-frontends. No entanto, havia limites visíveis dentro do aplicativo que faziam sentido esculpir e fazer a transição para uma arquitetura distribuída.


Considerando esses fatores, percebi que uma abordagem gradual era necessária. Em vez de uma migração completa para micro-frontends, meu objetivo era identificar áreas específicas em nosso aplicativo que poderiam se beneficiar de uma arquitetura distribuída.


Isso nos permitiria abordar questões de desempenho e escalabilidade sem interromper a estrutura organizacional geral ou comprometer a integridade de nosso domínio de negócios. Também nos daria algum tempo para aumentar a equipe e observar as direções do negócio.


Observe que, se você deseja resolver o problema de desempenho do aplicativo (tamanho do pacote) apenas usando a arquitetura mciro-frontend, pode não ser a melhor ideia. Seria melhor começar com uma arquitetura monolítica distribuída que aproveitaria o carregamento lento (importações dinâmicas).


Além disso, acho que lidaria com problemas de tamanho de pacote de maneira mais elegante do que a arquitetura de microfrontend, considerando que é muito provável que a arquitetura de microfrontend tenha algum código compartilhado que não seria separado em partes do fornecedor e seria incorporado ao pacote de aplicativos ( esse é um dos contras dessa arquitetura distribuída — você precisa ter uma compensação entre o que compartilhar, quando e como).


No entanto, a arquitetura monolítica distribuída não será dimensionada tão bem quanto o microfrontend. Quando sua organização cresce rapidamente, sua equipe provavelmente também crescerá no mesmo ritmo.


Haveria uma necessidade essencial de dividir a base de código em diferentes áreas de propriedade controladas por diferentes equipes.


E cada equipe precisará ter seus próprios ciclos de lançamento independentes dos outros, cada equipe apreciará se sua base de código for focada exclusivamente em seu domínio e será construída rapidamente (isolamento de código -> melhor capacidade de manutenção/menos código para manter e build -> melhor testabilidade/menos teste para manter e executar).

O começo

Para obter o apoio da liderança, elaborei um documento de visão técnica persuasiva que englobava uma análise de desempenho abrangente, incluindo métricas vitais da web, e descrevia as várias fases da migração para front-ends distribuídos.


Uma das fases intermediárias dessa migração foi estabelecer uma arquitetura monolítica distribuída, na qual vários módulos/widgets poderiam ser entregues de forma assíncrona por meio de técnicas de carregamento lento, aproveitando a infraestrutura compartilhada, como um balde S3 e CDN, entre o serviço principal e os widgets .


Como descrevi em meu artigo anterior, a ideia principal desse tipo de documento é descrever o futuro como você gostaria que fosse, uma vez que os objetivos foram alcançados e os maiores problemas resolvidos. Não é sobre o plano de execução!


Quase 1 ano depois, finalmente chegou a hora de colocar meu plano de migração de micro-frontend em ação. Com a expansão iminente para um novo domínio e uma equipe maior à nossa disposição, estávamos bem equipados para executar a migração.


Parecia uma oportunidade de ouro que não podíamos perder.


Afinal, permanecer confinado à arquitetura monolítica significaria lutar perpetuamente com suas limitações.


O cronograma limitado para expandir para um novo domínio serviu como um catalisador, impulsionando-nos a construir uma arquitetura mais escalável e sustentável imediatamente, em vez de ter iterações curtas e lentas!


Para executar a migração e simultaneamente lidar com o trabalho no novo domínio, dividimos as equipes em dois grupos dedicados. O trabalho de recurso, que tinha maior prioridade, exigia mais recursos e precisava iterar em um ritmo mais rápido.


Para garantir a integridade e compreensão abrangente do processo de migração, fazia sentido designar uma pequena equipe dedicada especificamente responsável por lidar com a migração.


No entanto, não poderíamos prosseguir com o trabalho do recurso sem primeiro garantir que o conceito de microfrontend fosse bem-sucedido.


Para mitigar os riscos e fornecer um roteiro claro, era crucial criar um documento de design de baixo nível que incluísse estimativas precisas e uma avaliação de risco completa. Este documento serviu como um modelo, descrevendo as etapas e considerações necessárias para a migração.


O marco fundamental nesse processo foi o desenvolvimento de uma prova de conceito que demonstraria a integração bem-sucedida de todos os componentes de acordo com o projeto.


Este marco, apropriadamente chamado de “Ponto sem retorno”, teve como objetivo validar a viabilidade e a eficácia da arquitetura de micro-frontend.


Embora eu estivesse otimista com o sucesso da migração, era essencial me preparar para as contingências. Consequentemente, elaborei um Plano B, que funcionou como uma estratégia de backup caso o conceito inicial não produzisse os resultados desejados.


Isso incluiu alocar sete dias adicionais nas estimativas especificamente para me fazer chorar no travesseiro, mais alguns dias para ter uma nova entrada de módulo de recurso conectada ao núcleo por meio de carregamento lento (lembra-se do monólito distribuído?).

O design

Ao projetar micro-frontends, geralmente existem 3 abordagens para composição, cada uma focando onde ocorre a resolução do aplicativo em tempo de execução. A beleza dessas abordagens é que elas não são mutuamente exclusivas e podem ser combinadas conforme necessário.

Composição do lado do servidor

A ideia básica é aproveitar um servidor proxy reverso para dividir os pacotes de micro-frontend por página e fazer um recarregamento físico da página com base na URL da rota.

Prós:

  • Simples de implementar


Contras:

  • O estado global não será sincronizado entre os aplicativos de microfrontend. Este foi um claro ponto proibido para nós, porque tínhamos operações de segundo plano de longa duração executadas no lado do cliente.


    Você pode argumentar que poderíamos manter um instantâneo da “fila” dessa operação no armazenamento local e lê-lo após o hard-reload, mas, devido a motivos de segurança, não conseguimos implementar isso.


    Este é apenas um exemplo de um estado global, mas aqui está outro exemplo de como pode ser: estado dos painéis de navegação lateral (expandido/recolhido), mensagens do sistema, etc.


  • A atualização difícil ao navegar pelos microaplicativos não é muito amigável ao cliente. Existe uma maneira de armazenar em cache o HTML compartilhado usando service workers, mas é uma complexidade adicional para manter.


  • Custos operacionais e de manutenção adicionais para a infraestrutura: servidor proxy para cada aplicativo microfrontend (isso pode ser evitado se for lido diretamente do CDN), infraestrutura separada para implantar dependências comuns (do fornecedor) a serem reutilizadas por várias páginas e armazenados em cache pelos navegadores.

Composição lateral

Outra abordagem para composição de microfrontend é a composição de borda, que envolve a combinação de microfrontends na camada de borda, como um CDN. Por exemplo, o Amazon CloudFront oferece suporte à integração Lambda@Edge , permitindo o uso de um CDN compartilhado para ler e servir o conteúdo do microfrontend.

Prós:

  • Menos peças de infraestrutura para manter: não há necessidade de servidores proxy, CDNs separados para cada microaplicativo


  • Escala virtualmente infinita usando tecnologia serverless


  • Melhor latência em comparação com servidores proxy autônomos


Contras:

  • O tempo de inicialização a frio pode se tornar um problema


  • O Lambda@Edge não é compatível com todas as regiões da AWS se você precisar de uma infraestrutura multirregional (isolada)

Composição do lado do cliente

A composição do lado do cliente é outra abordagem para a arquitetura de microfrontend que utiliza técnicas de orquestração de microfrontend do lado do cliente, dissociadas da implementação do servidor.


O principal participante dessa arquitetura é um aplicativo de contêiner (shell) que tem as seguintes responsabilidades:


  • Abordando preocupações transversais: o aplicativo de contêiner lida com layout de aplicativo centralizado, navegação de site, rodapé e painel de ajuda. A integração com micro-frontends que possuem preocupações transversais ocorre através de um Event Bus, onde os eventos sintéticos são enviados e tratados dentro do escopo da janela global.


  • Orquestração de microfrontends: o aplicativo contêiner determina qual pacote de microfrontend carregar e quando com base nos requisitos do aplicativo e nas interações do usuário.


  • Composição de dependências globais: o aplicativo contêiner compõe todas as dependências globais, como React, SDKs e bibliotecas de interface do usuário, e as expõe como um pacote separado (vendor.js) que pode ser compartilhado entre os microfrontends.


A ideia geral é que cada pacote de micro-frontend produziria 2 tipos de arquivos assets:

  • {hash}/index.js: serve como ponto de entrada para o aplicativo de microfrontend, com o hash representando um identificador exclusivo para toda a compilação.


    O hash atua como uma chave de prefixo para cada pacote no bucket S3. É importante observar que podem existir vários pontos de entrada, mas o hash permanece o mesmo para todos eles.


  • manifest.json: Este é um arquivo de manifesto que contém caminhos para todos os pontos de entrada para o aplicativo de microfrontend. Esse arquivo sempre sairia na raiz do bucket S3, assim o container conseguiria descobri-lo facilmente.


    Recomendo ativar o versionamento deste arquivo no bucket do S3 para ter uma melhor observabilidade das mudanças. Se você estiver usando o Webpack para criar seu projeto, recomendo o WebpackManifestPlugin , que faz todo o trabalho pesado para você.


O contêiner está ciente apenas da URL do domínio de origem do recurso de microfrontend (origem da CDN) com base no estágio e na região. Durante o carregamento inicial da página, o contêiner baixa o arquivo de manifesto para cada aplicativo de microfrontend.


O arquivo de manifesto tem um tamanho pequeno (cerca de 100 bytes) para evitar o impacto no tempo de carregamento da página e é bem dimensionado mesmo ao agregar vários micro-frontends em um contêiner. É crucial considerar o arquivo de manifesto como imutável no armazenamento de cache do navegador para evitar cache agressivo.


Escolher a biblioteca de orquestração certa é o maior desafio nessa composição e será discutido no próximo capítulo.

Prós:

  • Implementação independente de servidor: essa abordagem pode ser implementada sem nenhum requisito específico de servidor, oferecendo flexibilidade na tecnologia de back-end usada. Como mostrado na foto acima, você pode até não ter nenhum servidor


  • Preservando o estado global: ao usar um aplicativo de contêiner (shell), o estado global pode ser mantido ao alternar entre microfrontends. Isso garante uma experiência de usuário perfeita e evita a perda de contexto durante as transições.


  • Abordagem descentralizada: cada microfrontend pode decidir independentemente quais dados enviar para o navegador para autoinicialização. O aplicativo container simplesmente segue um contrato bem definido, permitindo maior autonomia e modularidade.


  • Configuração local simples: as fontes de ativos podem ser facilmente ajustadas entre produção e URLs locais com base nas necessidades de desenvolvimento. O arquivo de manifesto ajuda o aplicativo de contêiner a descobrir e carregar os microfrontends necessários. Os desenvolvedores podem se concentrar em executar apenas o contêiner e os micro-frontends específicos em que estão trabalhando.


Contras:

  • Mais saltos de rede para buscar o arquivo de manifesto: como o contêiner precisa recuperar o arquivo de manifesto para cada microfrontend, pode haver solicitações de rede adicionais e latência potencial em comparação com outras abordagens de composição. Isso pode ser atenuado carregando todo o manifesto antecipadamente no carregamento da página inicial ou introduzindo algumas técnicas de pré-carregamento.


  • Cumprimento do contrato comum: Todo micro-frontend precisa aderir a um contrato comum para a produção de compilações. Isso pode ser facilitado por meio de configurações compartilhadas e práticas de desenvolvimento padronizadas para garantir a consistência entre os microfrontends (mais sobre isso nas próximas partes).

Composição Híbrida

Como mencionei anteriormente neste capítulo, todos esses padrões de composição podem ser misturados e combinados dentro do mesmo aplicativo shell. Aqui está um exemplo de como pode ser:

Recomendação

Eu recomendo começar com uma abordagem homogênea no começo — selecione um padrão de composição que seja mais adequado para você e comece a construir a infraestrutura em torno dele.


Para nós, a composição do lado do cliente era a melhor opção, mas, para o futuro, consideramos mudar algumas regiões para a orquestração do lado da borda (com base na disponibilidade do Lambda@Edge).

Escolhendo a biblioteca de orquestração

Quando se trata de implementar a composição do lado do cliente em uma arquitetura de microfrontend, selecionar a biblioteca de orquestração certa é uma decisão crítica.


A biblioteca escolhida desempenhará um papel crucial no gerenciamento do carregamento dinâmico e na coordenação de microfrontends no aplicativo de contêiner.


Existem várias bibliotecas de orquestração populares, cada uma com seus próprios pontos fortes e considerações.

Spa individual

Single-spa é uma biblioteca de orquestração amplamente adotada que fornece uma abordagem flexível e extensível para composição de microfrontend. Ele permite que os desenvolvedores criem um aplicativo shell que orquestra o carregamento e o descarregamento de vários microfrontends.


O Single-SPA fornece controle refinado sobre eventos de ciclo de vida e oferece suporte a diferentes estruturas e tecnologias.


Prós:

  • Agnóstico de estrutura: a biblioteca funciona bem com várias estruturas de front-end, como React, Angular, Vue.js e muito mais.


  • Configuração flexível: oferece opções de configuração poderosas para roteamento, carregamento lento e dependências compartilhadas.


  • Ecossistema robusto: o Single-SPA possui uma comunidade ativa e um rico ecossistema de plug-ins e extensões.


Contras:

  • Curva de aprendizado: começar com um spa único pode exigir algum aprendizado inicial e compreensão de seus conceitos e APIs.


  • Complexidade da personalização: à medida que a arquitetura de microfrontend cresce em complexidade, configurar e gerenciar a orquestração pode se tornar um desafio.

Qiankun

Qiankun é uma poderosa biblioteca de orquestração desenvolvida pela equipe Ant Financial (Alibaba). Ele usa uma abordagem HTML parcial para composição. No lado do aplicativo micro-frontend, ele produz um trecho de HTML simples com todos os pontos de entrada a serem carregados.


Depois de consumir esse arquivo HTML, o contêiner faz toda a orquestração e monta o aplicativo. Nesta configuração, o HTML parcial desempenha o papel de um arquivo de manifesto sobre o qual falei no capítulo anterior.


Prós:

  • Agnóstico de estrutura: Qiankun oferece suporte a várias estruturas de front-end, incluindo React, Vue.js, Angular e muito mais.


  • Integração simplificada: Qiankun fornece um conjunto de APIs e ferramentas fáceis de usar para criar e gerenciar microfrontends.


  • Escalabilidade e desempenho: Qiankun oferece mecanismos eficientes para sandboxing de código, isolamento de estado e comunicação entre microfrontends.


Contras:

  • Conflitos de dependência: gerenciar dependências compartilhadas e garantir compatibilidade entre microfrontends pode exigir configuração e consideração cuidadosas.


  • Curva de aprendizado: embora o Qiankun forneça documentação extensa, a adoção de uma nova biblioteca pode envolver uma curva de aprendizado para sua equipe de desenvolvimento.


  • Dados redundantes enviados pela rede: o trecho HTML parcial contém dados redundantes (body, meta, tags DOCTYPE) que precisam ser enviados pela rede.

Federação de módulos

A Federação de Módulos , um recurso fornecido pelo Webpack, ganhou atenção e destaque significativos na comunidade de desenvolvimento da web. Essa tecnologia permite que os desenvolvedores compartilhem código entre vários aplicativos em tempo de execução, tornando-se uma opção atraente para a construção de micro-frontends.


Com sua integração perfeita com Webpack e flexibilidade de tempo de execução, o Module Federation tornou-se uma escolha popular para gerenciar e orquestrar micro-frontends.


Prós:

  • Integração perfeita com o Webpack: Se você já estiver usando o Webpack como sua ferramenta de construção, aproveitar a Federação de Módulos simplifica o processo de configuração e integração.


  • Flexibilidade de tempo de execução: A federação de módulos permite o carregamento dinâmico e o compartilhamento de dependências, proporcionando flexibilidade no gerenciamento de microfrontends.


Contras:

  • Suporte limitado à estrutura: embora a Federação de módulos seja compatível com várias estruturas de front-end, ela pode exigir configuração adicional ou soluções alternativas para casos de uso específicos.


  • Suporte da comunidade: Module Federation é uma tecnologia relativamente nova, lançada como um plug-in principal no Webpack 5 (e posteriormente portado para v4 ). A biblioteca Next.js também é mais recente, sendo lançada como código aberto recentemente. Como acontece com todas as novas ferramentas, pode haver uma comunidade menor e menos suporte disponível. É importante considerar esse fator se você tiver prazos apertados ou antecipar perguntas sem respostas prontamente disponíveis.

Conclusão

Nesta primeira parte da série “Micro-frontend Migration Journey”, discutimos a motivação por trás da migração de um monólito da web para uma arquitetura distribuída e as etapas iniciais tomadas para vender a ideia à liderança.


Exploramos a importância de um documento de visão técnica que apresentasse uma análise de desempenho detalhada e descrevesse as diferentes fases da migração.


Em seguida, nos aprofundamos nas considerações de design para microfrontends, discutindo três abordagens: composição do lado do servidor, composição do lado da borda e composição do lado do cliente.


Cada abordagem tem seus prós e contras, e a escolha depende de vários fatores, como sincronização do estado global, experiência do cliente, complexidade da infraestrutura e armazenamento em cache.


Além disso, exploramos bibliotecas de orquestração populares, como single-spa, qiankun e Module Federation, destacando seus recursos, benefícios e possíveis desafios.


Junte-se a mim nas próximas partes da série enquanto continuamos nossa jornada de migração de microfrontend, descobrindo insights mais interessantes e valiosos ao longo do caminho!


Originalmente publicado em https://thesametech.com em 18 de abril de 2023.


Você também pode me seguir no Twitter e se conectar no LinkedIn para receber notificações sobre novos posts!