Front-end de microsserviço - uma abordagem moderna para a separação da frente

spa muito gordo


A arquitetura de microsserviço tem sido o padrão de fato no desenvolvimento de sistemas grandes e complexos. Ele tem várias vantagens: é uma divisão estrita em módulos, conectividade fraca e resistência a falhas, e a saída gradual para a produção e versões independentes de componentes.

É verdade que, muitas vezes, falando da arquitetura de microsserviço, apenas a arquitetura de back-end é mencionada e o front-end permanece monolítico. Acontece que fizemos um grande apoio e a frente nos puxa para trás.

Hoje vou contar como fizemos a frente do microsserviço em nossa solução SaaS e quais problemas encontramos.

Edição


Inicialmente, o desenvolvimento em nossa empresa era assim: existem muitas equipes envolvidas no desenvolvimento de microsserviços, cada qual publica sua própria API. E há uma equipe separada que desenvolve o SPA para o usuário final, usando a API de diferentes microsserviços. Com essa abordagem, tudo funciona: os desenvolvedores de microsserviços sabem tudo sobre sua implementação e os desenvolvedores de SPA conhecem todos os meandros das interações do usuário. Mas havia um problema: agora cada front-end deve conhecer todos os meandros de todos os microsserviços. Existem cada vez mais microsserviços, mais e mais fornecedores front-end - e o Agile está começando a desmoronar, à medida que a especialização dentro da equipe aparece, ou seja, a intercambiabilidade e a universalidade desaparecem.

Então chegamos ao próximo estágio - desenvolvimento modular. A equipe de front-end foi dividida em subcomandos. Cada um era responsável por sua parte do aplicativo. Tornou-se muito melhor, mas com o tempo, essa abordagem se esgotou por vários motivos.

  • Todos os módulos são heterogêneos, com suas próprias especificidades. Cada módulo é mais adequado à sua própria tecnologia. Ao mesmo tempo, a escolha da tecnologia é uma tarefa difícil nas condições do SPA.
  • Como o aplicativo SPA (e no mundo moderno, isso significa compilar em um único pacote ou pelo menos um conjunto), apenas o aplicativo inteiro pode ser emitido ao mesmo tempo. O risco de cada extradição está aumentando.
  • Está ficando mais difícil o gerenciamento de dependências. Módulos diferentes precisam de versões de dependência diferentes (possivelmente específicas). Alguém não está pronto para mudar para a API de dependência atualizada e alguém não pode criar um recurso devido a um bug na ramificação de dependência antiga.
  • Devido ao segundo ponto, o ciclo de liberação para todos os módulos deve ser sincronizado. Todo mundo está esperando pelos retardatários.

Frontend de corte


Houve um momento de acumulação de massa crítica, e eles decidiram dividir o front-end em ... microsserviços do front-end. Vamos definir o que é um microsserviço front-end:

  • uma parte completamente isolada da interface do usuário, de forma alguma dependente de outras pessoas; isolamento radical; literalmente desenvolvido como um aplicativo independente;
  • cada microsserviço front-end é responsável por um determinado conjunto de funções de negócios do início ao fim, ou seja, é totalmente funcional por si só;
  • pode ser escrito em qualquer tecnologia.

Mas fomos mais longe e introduzimos outro nível de divisão.

Conceito de fragmento


Chamamos um fragmento de pacote configurável que consiste em js + css + . De fato, essa é uma parte independente da interface do usuário, que deve obedecer a um conjunto de regras de desenvolvimento para que possa ser usada em um SPA geral. Por exemplo, todos os estilos devem ser tão específicos quanto possível para o fragmento. Nenhuma tentativa deve ser feita para interagir diretamente com outros fragmentos. Você deve ter um método especial para o qual possa passar o elemento DOM para o qual o fragmento deve ser desenhado.

Graças ao descritor, podemos salvar informações sobre todos os fragmentos registrados do ambiente e ter acesso a eles por ID.

Essa abordagem permite colocar dois aplicativos escritos em estruturas diferentes em uma página. Também permite escrever código universal que permitirá carregar dinamicamente os fragmentos necessários na página, inicializá-los e gerenciar o ciclo de vida. Para estruturas mais modernas, basta seguir as "regras de higiene" para tornar isso possível.

Nos casos em que o fragmento não tem a oportunidade de "coabitar" com outras pessoas na mesma página, existe um script de fallback no qual desenhamos o fragmento em um iframe (a solução para os problemas relacionados está além do escopo deste artigo).

Tudo o que um desenvolvedor que deseja usar um snippet existente em uma página precisa fazer é:

  1. Conecte o script da plataforma de microsserviço à página.
     <script src="//{URL to static cache service}/api/v1/mui-platform/muiPlatform.js"></script> 

  2. Chame o método de adicionar um fragmento à página.

     window.MUI.createFragment( // fragment name "hello-label", // fragment model { text: "HelloLabelFragment text from run time" }, // fragment position { selector: ".hello-label-placeholder", position: "afterend" }) .then(callback); 


Além disso, para comunicação entre fragmentos, há um barramento construído no Observable e no rxjs . Está escrito em NativeJS. Além disso, o SDK vem com invólucros para várias estruturas que ajudam a usar esse barramento nativamente. Um exemplo para o Angular 6 é um método utilitário que retorna rxjs/Observable :

 import {fromEvent} from "@netcracker/mui-platform/angular2-factory/modules/shared/utils/event-utils" fromEvent("<event-name>"); fromEvent(EventClassType); 

Além disso, a plataforma fornece um conjunto de serviços que geralmente são usados ​​por diferentes fragmentos e são básicos em nossa infraestrutura. São serviços como localização / internacionalização, serviço de autorização, trabalho com cookies entre domínios, armazenamento local e muito mais. Para seu uso, o SDK também fornece wrappers para várias estruturas.

Combinando o frontend


Por exemplo, podemos considerar essa abordagem na área de administração do SPA (ela combina diferentes configurações possíveis de diferentes microsserviços). Podemos fazer o conteúdo de cada marcador como um fragmento separado, que será entregue e desenvolvido separadamente por cada microsserviço. Graças a isso, podemos criar um "cabeçalho" simples que mostrará o microsserviço correspondente ao clicar em um marcador.

imagem

Desenvolvemos a ideia de um fragmento


O desenvolvimento de um marcador com um fragmento nem sempre nos permite resolver todos os problemas possíveis. Geralmente, é necessário desenvolver uma certa parte da interface do usuário em um microsserviço, que será reutilizado em outro microsserviço.

E aqui os fragmentos também nos ajudam! Como todas as necessidades de fragmento são um elemento DOM para renderização, fornecemos a qualquer microsserviço uma API global através da qual ele pode colocar qualquer fragmento dentro de sua árvore DOM. Para fazer isso, basta passar o ID do fragmento e o contêiner no qual ele precisa ser desenhado. O resto será feito por si só!
Agora podemos construir uma "boneca de aninhamento" de qualquer nível de aninhamento e reutilizar partes inteiras da interface do usuário sem a necessidade de suporte em vários lugares.

Muitas vezes acontece que em uma página existem vários fragmentos que devem mudar de estado ao alterar alguns dados comuns na página. Para fazer isso, eles têm um barramento de eventos global (NativeJS) através do qual eles podem se comunicar e responder a mudanças.

imagem

Serviços Compartilhados


Em uma arquitetura de microsserviço, os serviços centrais aparecem inevitavelmente, dados dos quais todos os outros precisam. Por exemplo, um serviço de localização que armazena traduções. Se cada microsserviço individualmente começar a escalar esses dados para o servidor, receberemos apenas um eixo de solicitações durante a inicialização.

Para resolver esse problema, desenvolvemos implementações de serviços NativeJS que fornecem acesso a esses dados. Isso tornou possível não fazer solicitações e dados em cache desnecessários. Em alguns casos, até imprima esses dados para uma página em HTML antecipadamente, para se livrar completamente das solicitações.

Além disso, os wrappers foram desenvolvidos sobre nossos serviços para diferentes estruturas, a fim de tornar seu uso muito natural (DI, interface fixa).

Profissionais de microsserviços front-end


A coisa mais importante que temos ao dividir um monólito em fragmentos é a capacidade de selecionar tecnologias para cada equipe individualmente e o gerenciamento de dependências transparente. Mas também fornece o seguinte:

  • áreas de responsabilidade muito claramente divididas;
  • emissão independente: cada fragmento pode ter seu próprio ciclo de liberação;
  • aumentar a estabilidade da solução como um todo, uma vez que a emissão de fragmentos individuais não afeta outros;
  • a capacidade de reverter facilmente os recursos, distribuí-los parcialmente para o público;
  • o fragmento é facilmente colocado na cabeça de cada desenvolvedor, o que leva a
intercambiabilidade dos membros da equipe; além disso, cada front-end pode entender melhor todos os meandros da interação com o back-end correspondente.

Uma solução com um front-end microseris parece boa. De fato, agora cada fragmento (microsserviço) pode decidir por si próprio como implantar: se você precisa do nginx para distribuir estática, um middleware completo para agregar solicitações de apoio ou suporte a websockets ou outras especificidades na forma de um protocolo de transferência de dados binários dentro de http. Além disso, os fragmentos podem escolher seus próprios métodos de montagem, métodos de otimização e muito mais.

Contras de microsserviços front-end


Você nunca pode ficar sem uma mosca na pomada.

  • A interação entre fragmentos não pode ser garantida por métodos de tubo padrão (DI, por exemplo).
  • O que fazer com dependências compartilhadas? Afinal, o tamanho do aplicativo aumentará aos trancos e barrancos, se não forem retirados dos fragmentos.
  • De qualquer forma, apenas um deve ser responsável pelo roteamento na aplicação final.
  • O que fazer se um dos fragmentos estiver inacessível / não puder ser desenhado.
  • Não está claro o que fazer com o fato de que diferentes microsserviços podem estar em domínios diferentes.

Conclusão


Nossa experiência com essa abordagem comprovou sua viabilidade. A velocidade de saída dos recursos em produção aumentou significativamente. O número de dependências implícitas entre partes da interface foi reduzido para quase zero. Temos uma interface do usuário consistente. Você pode testar os recursos com segurança sem envolver um grande número de pessoas.

Infelizmente, em um artigo, é muito difícil cobrir toda a gama de problemas e soluções que podem ser encontrados no caminho de repetir essa arquitetura. Mas para nós, os profissionais claramente superam os contras. Se Habr mostrar interesse em revelar detalhes da implementação dessa abordagem, escreveremos uma sequência!

Source: https://habr.com/ru/post/pt420753/


All Articles