Como WebComponents transformaram uma empresa
Se prepara para chorar antes de comemorar, pois nesse artigo vou explicar como uma grande empresa que tinha problemas com bibliotecas prioritárias, versionamento, comunicação entre os times de Front-end e um alto acoplamento com o Angular se transformou com a criação de WebComponents.
Grandes empresas com muitas equipes de Front-end lidando com diferentes projetos acabam enfrentando um problema em comum: manter as aplicações com uma alta consistência no UI e UX (fica difícil manter até a mesma cor do botão Salvar).
O desafio de manter uma consistência é grande, e muitas empresas adotam diferentes estratégias:
- Criam um framework ou uma biblioteca
- Contratam uma equipe de Design
- Escrevem uma documentação gigante
- Incutem a validação do visual para os testers
- Customizam uma biblioteca (como um bootstrap da vida) para fins próprios
- e por aí vai…
Todas essas iniciativas gastam tempo, dinheiro e mesmo assim não garantem que os times terão desenvolvido uma aplicação no mínimo parecida uma com a outra.
Mas primeiro, o que são os WebComponents e qual a vantagem?
Um WebComponent, no fim das contas, é uma tag HTML criada por você mesmo e dentro dessa tag você possui uma DOM inteira para desenvolver o seu componente.
Então se hoje você já conhece as tags padrões do HTML (como <h1> para criar um título ou um <footer> para criar um footer) você também poderia criar a sua própria tag (chamada <datepicker> ou <best-name-ever> por exemplo), e ao incluir essa tag no seu projeto, toda uma estrutura pronta de CSS e HTML encapsulada dentro será renderizada de forma nativa no browser.
Para isso, os WebComponents se utilizam de uma funcionalidade do browser chamada ShadowDOM, que encapsula todo o HTML utilizado e o mais importante: evita conflitos de CSS (ou seja, se você definir uma classe CSS no seu projeto chamada .my-class ela não estará disponível dentro do seu WebComponent e o vice-versa). Isso torna seguro a criação de um componente com um CSS que nunca poderá ser sobrescrito, mantendo assim a consistência visual para todos os utilizadores desse componente (nenhuma aplicação poderá instalar o seu componente e tentar fazer modificações, a não ser que você permita através de parametrizações).
A ideia desse artigo não é se aprofundar em todos os detalhes técnicos do que é um WebComponent, mas é muito importante saber que quando você quer criar um componente visual para uma empresa, você provavelmente não vai querer que os times de projetos alterem tudo o que foi definido pela equipe de Design. Essa é uma grande vantagem dos WebComponents.
Desafios identificados
Quando comecei o projeto para inserir WebComponents nessa empresa supracitada, a primeira coisa que fiz foi levantar quais os desafios eu enfrentaria, foram eles:
Organização
Como o código seria armazenado? Como as equipes vão reportar problemas? Como as equipes podem sugerir e solicitar novas funcionalidades? Como evitar que um projeto que só precisa de 5 componentes tenha que instalar uma biblioteca gigante de coisas que não vai usar?
Tecnologias e Interoperabilidade
Quais as tecnologias no mercado? Qual a melhor se encaixa na empresa? Ela é fácil de integrar com outras tecnologias web? Tem performance? É fácil de mudar caso fique obsoleta?
Showroom
Como as equipes vão saber quais são os componentes disponíveis e suas variantes? Como deve ser a documentação? É possível mostrar uma demo do componente funcionando para ser simples de usar? Como instalar um componente em um projeto?
Breaking Changes e updates
Como evitar lançar uma Breaking Change em novas versões? Como estruturar o código de um componente para que seja simples de criar um parâmetro novo? E se for necessário alterar algum atributo CSS para atender alguma demanda específica?
Comunicação (mudanças, novos componentes, bugs)
Como novos componentes e novas alterações serão comunicadas para os times de projeto? Como manter um histórico de bugs resolvidos por cada componente? E se um time quiser criar o próprio WebComponent?
Qualidade
Os componentes devem possuir testes automatizados? A tecnologia escolhida possui regras de análise estática específicas para ela? Quais tecnologias podem ser usadas para análise estática local? É possível executar uma análise estática de itens específicos da tecnologia escolhida e enviar os problemas encontrados para o Sonarqube?
Calma, todas as perguntas acima têm resposta. Foram meses de aperfeiçoamento e quero detalhar aqui o use case para te auxiliar a tomar melhores decisões para uma possível implantação. Hoje esse projeto está em produção em mais de 100 aplicações (até a escrita desse artigo) dentro de uma empresa de grande porte nas mais variadas tecnologias web.
Soluções utilizando WebComponents
Organização
Esta é uma das primeiras coisas que precisava ser pensada, como os projetos vão consumir e como todo esse código ficará estruturado. Nessa empresa já havia uma biblioteca construída por eles em Angular, porém esta biblioteca já trazia alguns problemas:
- Só podia ser instalada em aplicações Angular (a empresa também utilizava React, AngularJS e .Net para Front-end)
- Ao instalar essa biblioteca, os desenvolvedores traziam para dentro da aplicação um pacote de 12 componentes diferentes, eles usando ou não, o que acabava inflando o bundle final à toa.
- A tecnologia era opinativa, ou seja, se o Angular ficasse obsoleto, a biblioteca teria que ser reescrita para outra tecnologia, fazendo que os projetos que utilizassem, tivessem também que reescrever.
- Preso a estrutura de versionamento do Angular, assim que os projetos atualizavam a versão, a biblioteca também precisava atualizar, fazendo assim que várias versões da biblioteca precisassem existir (para os que já atualizaram e para os que ainda não atualizaram).
A primeira decisão tomada foi: cada componente terá o seu próprio repositório.
Essa mudança já gerava algumas grandes vantagens:
- A aplicação só instala o que precisa
- Se precisar fazer alguma mudança, não é necessário gerar uma release nova com tudo (mais rápido de gerar novas versões)
- A documentação é de fácil acesso e padronizada pelo readme.md
- Fácil de criar tags, changelog, branch
- As issues são centralizadas para aquele componente específico, então fica fácil de se manter um histórico.
Já sabia como ia organizar, é claro que isso iria acabar gerando dezenas de repositórios no github da empresa, então já deixei tudo dentro de uma organization específica que o github enterprise nos permite criar.
Quanto menor era a minha estrutura, mais fácil seria de fazer uma mudança e criar uma versão.
Tecnologias e Interoperabilidade
Eu sabia que um problema eu queria resolver, o acoplamento que essa empresa tinha com a plataforma do Angular, que deixava os projetos não-Angular de fora e obrigava sempre a mover um elefante quando a equipe do Angular gerava uma nova versão. Apenas para curiosidade: quando comecei a trabalhar na empresa, o Angular estava na versão 9, mas era preciso dar manutenção nas versões 6, 7, 8 e 9 da biblioteca, pois atualizar os projetos era mais difícil do que alterar a biblioteca e essa situação piorava a cada nova versão).
Primeira coisa: escolher uma tecnologia agnóstica que ao final do build me entregasse apenas Javascript puro e não levasse consigo qualquer resquício da tecnologia que foi usada para escrever o código. O Angular pode ser usado para se criar WebComponents, mas o seu sistema de versionamento era de 3 versões por ano por serem uma plataforma gigante que faz tudo (http, forms, routes etc.) e eu só precisava de uma tecnologia para WebComponents, essas foram as cogitadas:
Essas 8 tecnologias foram escolhidas para passarem por uma análise SWOT e após a análise eu separei em dois grupos: as bibliotecas que foram criadas exclusivamente para WebComponents (mesmo que seja possível criar aplicações, elas foram criadas para um objetivo específico) e as que foram criadas para lidar com aplicações web inteiras.
Descartei todas que não eram focadas em WebComponents, pois elas demoravam para incluir algo novo para componentes e precisavam se preocupar com todo um ecossistema estrutural. O foco era pensar em pegar apenas algo pequeno, para transformar código em WebComponent.
Dentre essas 4 mais famosas, percebi que a manutenção, comunidade e maturidade das bibliotecas do Hybrids e Riot não eram tão grandes, principalmente por não ter uma grande empresa cuidando do repositório. O StencilJS possui a equipe do Ionic Framework e o LitElement é da equipe do Google, ambas tecnologias muito boas, maduras e com uma comunidade grande o suficiente para saber que já está sendo usada em produção por milhares de pessoas.
Ao fim da análise, mesmo achando o LitElement a melhor opção por ser de propriedade do Google e ter várias atualizações, a tecnologia escolhida foi o StencilJS por duas razões específicas:
A. Iria ser de fácil implantação na empresa (o Stencil usa TSX assim como o React, Typescript e anotações como o Angular), então teria baixa curva de aprendizado para os desenvolvedores que já estavam na empresa.
B. Já existiam muitos exemplos de componentes escritos dentro do repositório do Ionic Framework, que foi todo reescrito em Stencil na sua versão 4, o que poderia ajudar bastante a não passar por problemas já resolvidos por eles.
Uma grande vantagem também encontrada no Stencil é o seu padrão de Lazy Load, que carregava partes do WebComponent conforme o necessário, o que melhora a performance.
Então a segunda decisão tomada: StencilJS como ferramenta para criar componentes.
Showroom
Uma preocupação que eu tinha desde o início era A Comunicação. Eu precisava fazer que os times de desenvolvimento quisessem usar o novo padrão e os novos componentes, então eles precisariam sempre quando há algo de novo e que os componentes são fáceis de usar.
Se as equipes de projeto não usassem os componentes por qualquer motivo, isso poderia ser o fracasso desse projeto, eu precisava criar um Marketplace de WebComponents. Então, o primeiro passo foi arquitetar um Marketplace:
Esse Marketplace foi criado no Github pages para empresas, mas no fim, é apenas uma aplicação Web que se conecta no Github para obter os dados. Os pontos destacados são:
- Em um outro repositório (vou chamar de repositório de controle) criei apenas para manter uma lista com os dados de todos os componentes que possuímos (assim, a cada novo componente, eu só precisava fazer um novo commit que ele refletiria no menu automaticamente)
- Esse é o espaço da documentação, faço uma chamada na API do Github e vou ao repositório do componente obter o arquivo README.MD (onde deve ter a documentação do componente)
- Aqui é onde vai ficar a Demo com o componente funcionando. Cada repositório de componente deve ter um arquivo demo.html em que o Marketplace vai obter o conteúdo. Os binários dos componentes foram armazenados em um repositório central (também expostos com Github pages) em que o Marketplace apenas adiciona um import no HTML e ele já passa a funcionar.
- Header com os links úteis, centralizando assim os links para o Sonar, Pipeline e a Artifactory.
- Aqui também foi muito útil adicionar o número de issues no Github, com isso eu já saberia se o componente tem alguma pendência a ser resolvida. (Mais tarde também adicionei esse número ao lado de cada item no menu, para fácil identificação)
Estrutura final:
Com tudo configurado, raramente o Marketplace precisa de manutenção, pois tudo o necessário fica em repositórios externos \o/
- Repositório 1: marketplace (a aplicação Marketplace, nesse caso feita em Angular)
- Repositório 2: marketplace-control (onde fica um arquivo .json com todos os componentes e suas informações)
- Repositório 3: marketplace-components (os binários dos WebComponents)
- N Repositórios: os repositórios dos WebComponents (de onde obtemos a documentação e a demo)
E com isso, concluo a primeira parte desse artigo. Na próxima parte, vou ensinar como fizemos para evitar Breaking Changes nos componentes e como melhoramos a comunicação utilizando também os recursos do Github.