Professional Documents
Culture Documents
1. Introdução
No passado, um grande número de aplicações web adotava a arquitetura monolítica
devido à baixa complexidade de requisitos da época [1]. Essa arquitetura orientava o
tratamento de módulos funcionais e a transmissão de dados como um todo, sendo
uniformemente configurados, desenvolvidos e implementados [2]. Porém, a partir do
2. Contexto
Nas subseções seguintes serão descritos os fundamentos teóricos que deram suporte a
concepção da ferramenta.
nota fiscal referente ao pedido. Esses dois serviços têm suas bases de código separadas e
se houver necessidade de comunicação entre eles, a comunicação é feita por meio das
APIs [19].
Devido ao pequeno tamanho e foco em apenas um contexto de negócio, os
microsserviços tornam possível alcançar uma boa modularidade na base de código. O
objetivo é ter serviços fracamente acoplados e altamente coesos, para assim sua
simplicidade tornar a modificação e adição de funcionalidades relativamente rápidas e
diminuir os ciclos de desenvolvimento.
Empresas como Amazon, LinkedIn e Netflix fizeram a transformação de suas
camadas de serviço em microsserviços. Suas experiências positivas e de longo prazo
com este estilo de arquitetura atraiu o interesse de muitas outras empresas e
desenvolvedores.
2.3.1. Definição
Mesmo com a evolução arquitetural dos últimos anos e redução de limitações de
grandes backends e monolíticos, as bases de código frontend continuavam complexas e
dificilmente escaláveis [6].
Dado esse contexto, foi imaginado como se tirar proveito dos benefícios de
modularização e escalabilidade presentes na arquitetura de microsserviços e replicar
seus efeitos no frontend. Desse “mix” foi originada a arquitetura de micro frontends.
Cam Jackson define a arquitetura como um “estilo” no qual aplicações frontend
são entregues de maneira independente e são compostas em uma aplicação maior [6].
Krishnamurthy, por sua vez, descreve o micro frontend como uma abordagem de
microsserviços, porém aplicado no frontend, onde a ideia é decompor a aplicação web
em unidades menores e segmentadas por funcionalidade [20].
Yang et al. [20] dizem que a ideia do micro frontend é tratar uma aplicação
web como uma combinação de recursos onde cada time cuida de uma parte desta
aplicação e atende a um negócio ou função específico.
Se comparada a orientação de arquitetura de “web mashups”, definida como
aplicação que combina conteúdos (como dados e código) de várias fontes em uma
experiência integrada para um usuário [18], a diferença estaria no controle e
direcionamento das aplicações externas presentes na aplicação contêiner. A arquitetura
de micro frontends dita que a equipe de desenvolvedores deve ter total controle de
acesso a escrita do código fonte das micro aplicações, e estas devem na maioria das
vezes limitar a liberação de acesso a uma única origem (a da aplicação contêiner).
Enquanto isso, os “web mashups” utilizam artefatos públicos que permitem acesso de
qualquer tipo de origem e que os desenvolvedores em suma maioria não terão controle
de acesso a escrita do código fonte das micro aplicações.
Cada micro aplicação deve ser implementada de forma autônoma, modular e
bem delimitada, sendo possível alcançar uma evolução independente [8]. Assim,
alterações de tecnologias antigas deixam de ser dependentes de uma reescrita integral
do código base.
Podemos reunir as ideias principais da arquitetura de micro frontends nos
seguintes tópicos [8]:
● Modelagem em torno de domínios de negócio;
● Abstração de detalhes de implementação;
● Deployments independentes;
● Isolamento de falhas.
2.3.2.1. Separação
O parâmetro de separação refere-se a distribuição do modo de exibição e ao escopo de
trabalho dos times dentro de cada fragmento. As comuns escolhas de discussão são:
● Separação horizontal, com múltiplos micro frontends por página;
● Separação vertical, com apenas um micro frontend por página.
2.3.2.2. Composição
Por sua vez, a composição refere-se à forma de renderização da aplicação. As comuns
escolhas de discussão estão nas seguintes opções:
● Composição no lado do cliente;
● Composição central;
● Composição no lado do servidor.
adicioná-los dinamicamente aos nós do Document Object Model (DOM), em caso de ser
um HTML, ou inicializar a aplicação JavaScript. Uma outra possibilidade é a utilização
de iframes.
Já utilizando a composição central, o conteúdo da página será montado e
armazenado em múltiplos CDN que utilizam um tipo de Extensible Markup Language
(XML) chamado Edge Side Include (ESI) que possibilitará a escalabilidade da
infraestrutura da aplicação provida pela exploração de pontos de CDN espalhados pelo
mundo, assim aumentando de capacidade de hosting do data center comparada a uma
aplicação comum. Porém, uma das desvantagens é que a utilização do ESI não é feita da
mesma forma para cada CDN e, portanto, uma estratégia multi-CDN poderia resultar
em vários re-trabalhos de implementação [10].
Por sua vez, a composição no lado do servidor detém seu conteúdo
primariamente de sua origem e armazena a informação no CDN, servindo ao cliente a
tela final em tempo de execução ou compilação.
2.3.2.3. Comunicação
A comunicação entre micro frontends ocorrerá de acordo com o modelo de separação
escolhido. No caso da separação horizontal, um método é a utilização de disparadores
de evento providos pelo browser ou por objetos construídos pelo usuário dentro de cada
micro frontend. Dessa maneira, quando um fragmento emitir um evento, o outro
conseguirá obter a informação a partir de subscrições realizadas naquele evento em
específico. Outras propostas de utilização são os eventos customizáveis, que são visíveis
apenas nos contextos de janela em que foram emitidos.
2.4. Single-SPA
Atualmente, a biblioteca single-spa é uma das principais ferramentas construídas em
JavaScript, de código aberto, para construção de interfaces de usuário na web que
desejem utilizar a arquitetura de micro frontends. Foi desenvolvido pelo grupo Canopy
com o objetivo de reunir vários micro frontends em uma única aplicação. Hoje, o
single-spa é utilizado por diversas companhias como Canonical, Zup, Scania e outras.
Uma aplicação desenvolvida com o single-spa consiste na criação de um projeto
contêiner e vários outros projetos de diferentes tecnologias.
Logo após os primeiros estudos de exemplos e da documentação da ferramenta,
foi percebida a seguinte condição: Todas as micro aplicações desenvolvidas eram
obrigadas a utilizar um plugin específico que desse suporte a sua stack de
desenvolvimento, permitindo a configuração dos métodos de ciclo de vida e o
integrando a aplicação contêiner. Esse plugin só considera como artefatos de micro
aplicações as ferramentas desenvolvidas com conteúdo renderizável no lado do cliente e
que descentraliza parte do processo de configuração de ciclo de vida e integração. Com
isso, dificulta a utilização da tecnologia em ferramentas antigas que majoritariamente
trabalhavam com renderização no lado do servidor e que hoje almejam realizar a
migração de seu sistema para alguma solução mais moderna.
É dessa identificação de suporte restritivo, descentralização de configuração e
pequeno acervo de soluções atacando este tema que nasce como objetivo deste trabalho
o desenvolvimento de uma solução que seja capaz de abstrair a integração dos
fragmentos em um único contêiner sem a instalação de dependências obrigatórias, como
os plugins, nos fragmentos, focando em um tipo de construção que dê às micro
aplicações uma maior liberdade de escolha de tecnologias e facilite a configuração de
aplicações com esse tipo de arquitetura.
3. Metodologia de trabalho
Este trabalho compreende uma proposta de desenvolvimento prática realizada com base
nas diretrizes teóricas compreendidas na seção anterior. Assim, nas subseções seguintes
serão descritos os passos práticos que auxiliaram o processo de desenvolvimento e
validação da ferramenta.
3.2. Brainstorming
O propósito de se realizar o “brainstorming”, técnica utilizada para propor soluções a
um problema específico, foi garantir uma maior diversidade de opções para a escolha da
solução final.
Dado esse contexto, foram pensadas algumas arquiteturas. As soluções que
demonstraram estar fora do esperado, não contendo todos os parâmetros orientadores
definidos ou que não conseguiriam ser executados em tempo hábil, foram eliminadas,
garantindo assim a permanência das que realmente estavam alinhadas à proposta. Ao
final desse processo, dentre as opções pensadas, a de codinome Roll Cake foi escolhida.
A relação completa das soluções pensadas e excluídas pode ser encontrada no apêndice
A.
3.3. Solução
A solução de codinome Roll Cake contemplaria três módulos JavaScript com
responsabilidades únicas e suas próprias interfaces de programação de aplicativos
(API), sendo eles:
● Roll Cake MF-Broker: um mediador de micro frontends;
● Roll Cake Router: um mediador de rotas;
● Roll Cake SPA: um renderizador de elementos e integrador de módulos.
qual possui uma versão desktop que utiliza uma arquitetura de micro frontends com
forte similaridade aos parâmetros orientadores da ferramenta proposta por este trabalho.
Utilizando um modelo de separação voltado para a horizontalização de equipes,
realização da composição da aplicação no lado do cliente com auxílio de iframes e
comunicação por eventos no modelo publish / subscribe[8]. As seguintes Figuras 11 e
12 representam as páginas do Spotify que esperam ser minimamente implementadas.
4. Resultados
Esta seção fornece uma descrição funcional dos artefatos implementados a partir das
diretrizes traçadas na seção anterior.
Seis artefatos foram necessários para realizar seu funcionamento, sendo eles:
● EventBus: uma classe que representa a interface de comunicação no modelo
publish / subscribe;
● GlobalStore: uma classe responsável pelo compartilhamento e persistência de
dados;
● Microfrontend: uma classe responsável pela identificação e tratamento de
Custom Elements com a tag “rollcake-microfrontends”;
● RollCakeMFBroker: uma classe dedicada a integração de serviços internos e
transmissão de eventos;
● Um armazenador de constantes para re-utilização de variáveis;
● Um arquivo exportador de itens.
Dentre os itens citados, apenas dois estão disponíveis para utilização pública: a
classe RollCakeMFBroker e as constantes referentes ao nome da variável de janela
criada pelo módulo, ao nome da Custom Tag referente aos micro frontend e ao nome
dos eventos públicos cabíveis de recebimento.
A partir da instalação do módulo, se o usuário quiser utilizar a ferramenta terá
que realizar a configuração da classe RollCakeMFBroker. A classe possuirá apenas um
parâmetro de entrada do tipo lista de objetos que deverá armazenar as declarações de
micro frontends que desejam ser atribuídas a aplicação. Nesse objeto devem ser
informados os atributos name e address.
Tabela 1. Exemplo de declaração e inserção de parâmetros da classe
RollCakeMFBroker
Após realizada a instância da classe, o construtor disponibiliza ao usuário um
método de inicialização chamado init que define como atributo interno o objeto que
conterá a lista de buckets e instância as classes EventBus e GlobalStore para,
posteriormente, compartilhá-los através das variáveis de janelas.
Tabela 2. Exemplo de execução do método init
MFBroker.init();
Criada a variável de janela, a classe Microfrontend passa a detectar a inserção de
elementos com a tag “rollcake-microfrontend” no HTML do cliente. A partir de sua
detecção, é lido o parâmetro name e dele é tentado achar alguma referência com a
declaração dos buckets feitas na instância da classe RollCakeMFBroker. Se passível de
pareamento, será criada uma resposta encapsulada em um iframe, que conterá uma
cópia da variável de janela compartilhável previamente descrita no parágrafo anterior, e
será feita uma requisição para adquirir o HTML content do address encontrado. Se a
requisição for respondida com sucesso, ela será integrada ao elemento encapsulador e
enviada ao cliente. Caso contrário, o processo encerra-se.
Tabela 3. Exemplo de custom element identificável pelo módulo
<rollcake-microfrontend name=”react-bucket”>
</rollcake-microfrontend>
// EventBus
window.RollCake.bus.publish(eventName,payload);
window.RollCake.bus.subscribe(eventName, callback);
// GlobalStore
window.RollCake.store.getState(stateName);
window.RollCake.store.setState(stateName, newState);
Modo URI
Hash https://server:port/#/home
History https://server:port/home
Router.init((props) => {
console.log(props.path);
console.log(props.item);
});
Ao ser instanciado, ele realiza a chamada de inicialização das classes
RollCakeMFBroker e RollCakeRouter.
Uma vez que o módulo MF-Broker seja inicializado, ele realizará a
disponibilização das mediações de micro frontends e a interface de comunicação entre
elas. Posteriormente, a partir da interface de comunicação, o SPA passará a escutar
eventos de requisição, para fazer a sobreposição de tela com o conteúdo do atributo
loadingContent, e solicitação de navegação, para requisitar ao módulo router uma
navegação forçada.
Logo em seguida, o router é inicializado para detecção de mudança de rotas.
Uma vez que algo seja detectado, ele fará uma verificação de existência perguntando a
seus atributos internos se existe alguma página atualmente visível para o usuário e, caso
exista, vai deletá-la para solicitar a renderização do novo item. Item este que deverá ser
do tipo função e ter como retorno referência ao artefato createPage disponibilizada
publicamente por este módulo.
O createPage irá realizar a criação da classe page que, ao ser instanciada, irá em
seu construtor fazer a atribuição de valores internos e realizar a execução de métodos de
renderização e destruição que irão ativar funções internas ao ciclo de vida da aplicação.
No caso do método render é disparada a ativação dos atributos do tipo função onInit e
content, o qual o content deverá ter como retorno obrigatório uma instância da classe
element que será responsável pela inserção de conteúdo no DOM.
Um ponto importante da exemplificação da Tabela 12 é a definição de um
elemento de micro frontends. Para seja realizada uma mediação do broker com sucesso,
é necessário solicitar a criação de um elemento que possua em sua declaração de tag
com o valor “rollcake-microfrontend” e no atributo attr adicionar a chave “name” com
um valor correspondente ao bucket declarado na referência de configuração da classe
RollCakeMFBroker.
id de qualquer valor que será utilizado como referência para o entryDOMNode da classe
RollCakeSpa.
Finalizado o pré-setup do ambiente é possível focar na estruturação e
implementação da pasta src com o arquivo index.js e seus derivados, criando os
seguintes artefatos: mf-broker.config.js, router.config.js, global.css, pasta components,
pasta pages e o próprio index.js.
Por fim, o arquivo index.js faz a importação dos artefatos de alto nível como o
global.css, que registra todas as estilizações globais da aplicação, o router.config.js, o
mf-broker.config.js e a classe RollCakeSpa, fazendo assim a declaração da classe e
colocando alguns dos itens importados como parâmetros de entrada.
Tabela 15. Exemplo de arquivo index.js
if (window.RollCake) {
window.RollCake.bus.publish("authorized-user-callback", {accessToken:
xXxXxXxXxXxXx});
}
if ((<any>window).RollCake){
const authorizedUser =
(<any>window).RollCakeMFBroker.store.getState('authentication');
}
(<any>window).RollCake.bus.publish('play-user-playback',context_uri);
foi o React [13] com as dependências comuns a projetos react e, novamente, o
spotify-web-api-node.
Foram criados alguns componentes básicos e todos foram agrupados em um
único componente pai. Esse componente de maior nível hierárquico estaria indexado a
página inicial da micro-aplicação que teria os mesmos propósitos que os módulos
anteriores: interação virtual com o usuário e semelhança visual com a página oficial de
WebPlayer do Spotify. Portanto, o fragmento deverá consumir os dados do módulo de
autenticação e, principalmente, disponibilizar uma lista de playlists recomendadas, que
poderá ser clicada e posteriormente transmitida para a micro-aplicação player pela
interface de comunicação da solução MF-Broker.
5. Discussão
Figura 19. Exemplo de segmentação por contexto de negócio e declaração de
variáveis
Realizada a declaração e segmentação dos contextos de negócio de cada micro
frontend, o usuário deverá, para cada contexto de negócio identificado, criar uma página
e rota com as tecnologias de construção de UI providas pela ferramenta escolhida. Logo
em seguida, deverá ir aos arquivos de criação e renderização de componentes e realizar
a declaração de um elemento com a tag “rollcake-microfrontend”. Essa tag deverá
conter um atributo “name” preenchido com um valor idêntico a um dos segmento de
contexto de negócio que foram declarados no parágrafo anterior, assim como
exemplificado na Tabela 3 da seção 4.1.
Uma vez que esteja funcionando a exibição, é hora de remover os artefatos de
reuso do sistema antigo, afinal já foram portados para a nova ferramenta, e utilizar os
serviços da interface de comunicação e dos dados compartilháveis disponibilizados pela
variável de janela “RollCake” exemplificados na Tabela 4 da seção 4.1.
Ao final, o usuário terá um portal em React.js suportando um ambiente
temporário com a arquitetura de micro frontends que possibilita a escrita de novas
funcionalidades ou reescrita de antigas, e a coexistência da versão legado (pelo menos
enquanto a aplicação não for totalmente reescrita).
● Utilização do @rollcakejs/rollcake-spa como aplicação contêiner e considerando
organização de repositório como mono-repositório;
● Utilização do @rollcakejs/rollcake-spa como aplicação contêiner e considerando
organização de repositório como multi-repositórios;
● Utilização de uma biblioteca de construção de UI qualquer como aplicação
contêiner auxiliado pelo @rollcakejs/rollcake-mf-broker e organização de
repositório como mono-repositório;
● Utilização de uma biblioteca de construção de UI qualquer como aplicação
contêiner auxiliado pelo @rollcakejs/rollcake-mf-broker e organização de
repositório como multi-repositórios;
Cada abordagem irá variar a depender das necessidades de cada projeto de
desenvolvimento. Portanto, para um cenário de exemplificação hipotético será abordado
apenas o primeiro caso o qual deve ser considerado o caminho mais curto para alcançar
o objetivo desta seção.
Em um ambiente em que se deseja utilizar o @rollcakejs/rollcake-spa como
aplicação contêiner e uma arquitetura de repositório organizado como um todo
(mono-repositório), basta utilizar o template de inicialização de projetos localizado no
repositório rollcake-spa-template.
A partir da transferência e instalação de dependências do template anteriormente
mencionado, o usuário deverá executar o desenvolvimento dos artefatos de reuso
(header, menu e footer) seguindo de exemplo a construção de componentes encontrados
na Tabela 10 da seção 4.3.
Uma vez que os componentes estejam prontos, o usuário deverá ir ao arquivo
mf-broker.config.js e realizar o mesmo passo-a-passo da seção 5.2.1, a qual refere-se a
declaração e segmentação dos contextos de negócio de cada micro frontend da
aplicação legado.
Logo em seguida, para cada contexto de negócio deverá ser criada uma página e
para cada página uma nova rota no arquivo router.config.js. Dentro de cada página
deverá ser realizada a declaração de um elemento de micro frontend. A criação de
páginas pode ser vista na Tabela 9 da seção 4.3 e a configuração de rota na Tabela 5 da
seção 4.2.
Assim como a seção 5.2.1, uma vez que a exibição da aplicação legado esteja
funcionando, remova os artefatos de reuso do sistema antigo e utilize os serviços da
interface de comunicação e dos dados compartilháveis disponibilizados pela variável de
janela “RollCake”.
Ao final, o usuário terá um portal de SPA construído sob utilização do
rollcake-spa suportando um ambiente com a arquitetura de micro frontends que
disponibiliza ao usuário a possibilidade de escrita de novas funcionalidades com suporte
a diferentes tecnologias, modernização de antigas ferramentas e coexistência com a
versão legado.
7. Referências bibliográficas
[1] Caifang Yang et al. “Research and Application of micro frontends”. IOP Conference
Series Materials Science and Engineering. 2019.
[2] Dragoni, Nicola, et al. "Microservices: yesterday, today, and tomorrow." Present and
ulterior software engineering. Springer, Cham. 2017.
[3] KALSKE, Miika et al. Transforming monolithic architecture towards microservice
architecture. 2018.
[4] Pavlenko, Andrey, et al. "micro frontends: application of microservices to web
front-ends." Journal of Internet Services and Information Security (JISIS). 2020.
[5] Newman, S., Building microservices. O’Reilly Media, Inc., 2015.
Criação de um módulo
responsável pela 1. Difícil manutenibilidade a longo
Wrapper renderização de elementos e prazo, devido a estrutura
micro frontends via iframe, e monolítica.
roteamento de página.
Criação de um módulo
responsável pela 1. Difícil manutenibilidade a longo
renderização de elementos e prazo, devido a estrutura
micro frontends via web monolítica;
components extensíveis de 2. Arquitetura de componentização
Atomic
iframes, e roteamento de (Atomic Design) não muito
página. Porém, com uma utilizado e conhecido pelos
arquitetura de construção de desenvolvedores frontend, assim
elementos voltada para o dificultando a aderência.
Atomic Design.