Arquiteturas escaláveis para SPAs com Angular
Programar com componentes é muito produtivo, surge uma task, você cria um novo componente pelo cli,
joga as regras dentro do html, faz o bind com 2way data bind e vai pra próxima task. Assim, nascem aqueles projetos indomáveis que vão nos assombrar a cada nova sprint.👻
Para resolver alguns problemas de arquitetura de uma aplicação SPA, podemos utilizar a técnica de Statefull e Stateless components, vamos exemplificar isso construindo um pequeno app que calcula a diferença entre tempos.
- Código fonte: https://github.com/caina/angular4-timesheet-architecture
- Aplicação rodando: www.time-sheet.surge.sh
Statefull e Stateless components
Resumindo: Statefull são componentes que contém a lógica de negócio. Em geral não possuem estilos, apenas a construção dos componentes de tela, já os stateless são components de tela e não possuem lógica de negócio, são utilizados para montar as telas como blocos de lego, este artigo explica mais a fundo este tema.
Indo para a arquitetura da nossa aplicação, quebramos ela da seguinte maneira:
- Scenes: nossos componentes Statefull, cada componente é uma tela do sistema
- Scenes/Componentes: Componentes de tela que não são reaproveitados fora da cena
- Components: nossos componentes genéricos usados entre as Cenas
Perceba que Time-sheet(scene/time/time-sheet)agrupa os componentes que montam nossa tela principal, enquanto time-history é uma tela que lista os históricos gerados pelo app, sendo assim, são componentes Statefull importando componentes de tela da pasta components.
Em time-sheet instanciamos o componente app-time-line, que possui dois inputs, a hora de início a hora de fim e emite um evento ao clicar em “Ok”. Este evento é capturado pelo nosso componente de lógica time-sheet, que manipula estes valores resultando em um valor em horas da diferença, este valor em hora é disparado como outro evento, que por sua vez é capturado pelo componente que exibe o total de horas app-time-result, o qual arredonda este valor e formata ele em um formato de “HH:mm”.
Percebeu que cada componente trabalhou de forma autônoma? Sem a necessidade do componente time-sheet passar uma referência de um objeto para os demais, a vantagem desta técnica, é que quando desenvolvemos o botão de “summarize”, o resultado do cálculo emite o mesmo evento das linhas de tempo, nos dando a liberdade de refatorar este componente como bem queremos pois ele não possui nenhum vínculo com o componente pai!
Vamos rever o que este componente está fazendo:
- <app-card> é um componente Stateless que monta a tela na forma do cartão.
- <app-time-result> está recebendo um Observable com o pipeline
async
que quando recebe um evento, repassa para o componente como input. - <div class=”card-list”>
#timeLines
é usado para passar a referencia desta div para o componente poder instanciar novos <app-time-line> no componente Statefull
Observe que nosso componente de Time-sheet está apenas agregando outros componentes e delegando ações para eles, mantendo suas lógicas desacopladas e reativas. Além disso, conseguimos ter uma arquitetura “Flat”, ou seja, poucas camadas de componentes.
Mas o que é Programação Reativa?
Em poucas palavras, todos os componentes que estavam esperando ações por listners
são reativos!
Programação reativa é programar com fluxos(streams) de dados assíncronos. Assíncrono significa que não se realiza ao mesmo tempo ou no mesmo ritmo de desenvolvimento (em relação a outra coisa).
Nosso componentes são independentes e não compartilham o mesmo ciclo de vida que seus componentes irmãos, podem ser reaproveitados fora deste eco-sistema de calculo de tempo e ainda conseguem delegar responsabilidades de maneira coerente.
Revisando
Separando nossos componentes entre apresentação e lógica, nos tornamos mais eficientes e escaláveis, temos mais confiança na hora de refatorar uma tela e temos como melhorar a performance de renderização deles mudando o modo do mesmo.
Um pouco sobre minha experiência desta forma de desenvolvimento: Trabalhei em um projeto em que os seus componentes não se distinguiam entre Stateless e Statefull, cada componente controla os dados que recebia e obedeciam lógicas de negócio vinculadas à tela em que estavam inseridos. Reaproveitar um componente fora do ciclo de vida que ele havia sido originalmente desenhado era muito complexo e muitas vezes não valia a pena. Além do pouco reaproveitamento de código, debugalos era muito complexo pois a lógica fica distribuído entre os componentes.
Para este exemplo usamos Angular, mas poderia ter sido feito com qualquer Framework ou Library, se tiver alguma sugestão ou duvida deixe um comentário!