Quebrando o lado obscuro das aplicações monolíticas — Parte 1

Ricardo Bin
Tech@Grupo ZAP
Published in
5 min readNov 23, 2016

Ahhh, aplicações monolíticas… O que não faltam são artigos e artigos falando de microservices VS monolithics e todo esse lance. Até mesmo aqui no blog do VivaReal tem esse post do meu querido Nykolas Lima. Esse assunto é tão fervoroso que sempre aparece nas famigeradas perguntas clichês de entrevistas técnicas (tá, eu sempre mando dessas também).

Mas o que vou falar aqui é incomum. É a outra parte dos monolíticos. É sobre um assunto pouco falado. É a camada onde as piores práticas acontecem. Um lugar tão maldito que não é responsabilidade nem do front-end e nem do back-end. É onde os corpos inertes levantam de suas tumbas e ganham vida através de magia obscura e antiga de necromantes profanos.

Sim, é onde os templates estáticos recebem os dados através de serviços, renderizam e tomam forma através dos assets.

A layer que fica de cara pro mundo, que toma porrada, que precisa ser rápida e performática, que se der qualquer probleminha todo mundo vai ver (e lógico, vão vir direto no seu pescoço). Onde tudo acontece, ou como eu chamo: o “back do front”.

Assets, Templates e Render Engine

Essa é a tríade de toda essa treva. Nos populares monolíticos
“MV*” que vemos por aí (Rails, Django, Spring, etc), todos esses três caras estão dentro da aplicação toda. Ou seja, se eu mudar a cor de um botão, toda uma aplicação inteira terá que ser 'deployada'. Enfim, sem novidades por aqui certo?

Agora vou fazer algumas revelações sobre como conseguimos separar todo esse mal do nosso back-end aqui no VivaReal.

Back to 2005 — The Dark Ages

Vamos voltar a um período nebuloso do desenvolvimento web, onde tínhamos a maravilhosa alcunha de webmaster, onde controle de versão era praticamente inexistente, onde o IE6 era o navegador mais utilizado, onde o deploy para produção era um drag-drop. Para quem viveu (e sobreviveu) a essa época, não temos saudades de praticamente nada (tá, talvez bate aquela saudade do marquee ou do blink — ok, já passou), mas uma coisa era fato: o deploy das coisas era extremamente simples e rápido.

E com todo o aparato de técnicas e ferramentas que temos hoje, tal como testes de unidade/integração/aceitação, containers, clouds e PaaS, CI/CD, etc como que caímos no problema que falei antes?

Eu consigo fazer o deploy em produção de uma API, com um OS embutido (em alguns casos com 10, 20 mb usando alpine+go) em segundos e demoro vários e vários minutos compilando centenas de arquivos de front e subindo um ambiente inteiro, sendo que só mudei uma linha de html e uma de css.

WTF?!

Passo 1 — Dissecar os Assets

Dos três que comentei cima, sem dúvida, separar apenas os assets é a tarefa mais fácil e comum.

Seguindo a mentalidade de que as coisas tem que ser simples, podemos separar em 4 etapas o processo de um deploy (considerando que seu arquivos já estão bonitinho em um repositório à parte e com toda integração continua na agulha):

1- Compilar (compile);

2- Versionar (versioning);

3- Armazenar (save);

4- Consolidar e notificar (consolide and notify);

Compilar

Antes de tudo, você precisa compilar todos esses caras. A stack de front-end hoje está bem mais complexa do que há alguns anos e cada um tem seu arsenal de preferência para chegar ao resultado final. O que importa aqui é o estado bruto do seu código lindo e legível de outrora: um monte de arquivos js e css minificados e ofuscados, imagens, svgs, fontes e afins.

Versionar

Tendo esse emaranhado em suas mãos, você precisa agora versioná-lo, ou seja, dar um nome pro seu monstrinho. De preferência, esse versionamento precisa ter uma certa afinidade com seu código, para possíveis rebuilds ou algo do tipo. Geralmente usar uma git tag gerada automaticamente no momento de build (o npm tem o version que é lindo pra isso) ou simplesmente um 'git rev-parse — short HEAD' é o suficiente.

Armazenar

Agora você precisa armazenar tudo isso em algum lugar, que provavelmente estará sendo servido pro mundo através de um cdn. Como você vai salvar, siga o que seu coração mandar (s3, ceph, scp, qualquer coisa), mas um detalhe é muito importante aqui: a sua versão será como um namespace. Todos os seus arquivos deverão ser colocados nessa pasta seguindo a sua hierarquia.

Ex: cdn.dominio.com/1.0.0/*

Um detalhe importante que talvez você tenha notado: sim, a cada deploy todos seus usuários precisarão fazer o download de todos seus arquivos no front novamente. Mas, com todos as layers de cache que temos dentro e fora dos nossos domínios (ex: varnish, akamai, cloudfront, nginx microcache, cloudfare, etc etc), o cache do client não é um problema. Trust me. Aliás, com essa técnica você nem precisa se preocupar com cache busters e coisas do tipo.

Consolidar e Notificar

Assim que seu deploy (aka upload) terminar, você precisa consolidar aquela versão e notificar a sua aplicação original. Esse passo pode ser quebrado em dois momentos, mas em geral não tem muito segredo. Quando o deploy terminar, você precisa chegar e falar “ok, aplicação, a versão atual é a 1.0.1”. E o rollback é tão simples quanto isso.

Lógico que aqui a implementação muda bastante de acordo com suas tecnologias e arquitetura. Você precisará implementar esse evento no seu back-end, para saber que os links não apontam mais para cdn.dominio.com/1.0.0/ e sim para cdn.dominio.com/1.0.1/

Outra preocupação é salvar essa versão como a atual em algum lugar. Seu back-end precisa saber qual é a versão atual independente do evento (quando uma nova máquina subir, é a primeira coisa que ele deve consultar). A estratégia atual que usamos aqui no VivaReal para os ambientes que precisam ser mais confiáveis (QA/STAGING/PROD) foi o seguinte: a gente primeiro 'carimba' a versão num arquivo do S3 e avisa a aplicação para ler a "current version”. Lógico, tem toda aquela preocupação de salvar a versão anterior, histórico de deploy e tudo mais. Caso você queira algo mais refinado pode salvar essas versões até em um banco.

Sobre a notificação, nós utilizamos o Pub/Sub do Redis, assim ela chega sempre a todos back-ends, independente de quantas máquinas estão por trás do nosso load balancing.

Como eu disse, nesse ponto existem muitas maneiras de consolidação e notificação. Dá pra pirar bastante nesse ponto.

Finalizando

Bom, essa é a primeira parte dos 3 passos para a separação de arquivos estáticos e do render de seu monolítico. A dissecação completa ainda está por vir.

Se pararmos por aqui, vamos ganhar agilidade e simplicidade no deploy dos assets, mas ficamos vulneráveis em relação aos templates: com eles ainda dentro do seu monolítico, haverá vários momentos que resultarão em deploys casados e, algumas vezes, isso pode gerar alguns problemas.

Por exemplo: um componente novo no header. Se o deploy do monolitico+templates for antes, você corre o risco de ficar com um negócio sem estilo no header até o deploy dos assets acontecer. E quando for uma mudança no comportamento que esse header já tem? Os assets podem ir antes sem problemas ou vai quebrar o atual? E a coisa complica considerando caches na jogada — eu não vou nem me alongar nesses cenários de caos que já to até triste aqui.

Por isso, a separação dos templates junto com os assets é essencial nesse plano maléfico, que será consolidado na cerejinha do bolo: o render apartado. Mas sobre esses próximos passos eu deixo para um novo post.

Cya!

--

--