Facade para organização de Microservices

Fachada

Com a ascensão dos microservices surgiram diversos desafios como overhead de rede e recursos, transações distribuídas, granularidade dos serviços, rastreabilidade de transações, operação e administração de sistemas, padronização e organização, ressonância de erros, tolerância a falhas, versionamento de APIs e muitos outros.

Aqui pretendo demonstrar as vantagens de extrapolar o famigerado Design Pattern Facade para o mundo dos microservices, principalmente para organização dos serviços, prevenção de dependências cíclicas entre eles e otimização de recursos, evitando alguns dos problemas acima.


Dependências cíclicas

Uma das piores práticas (ou acontecimento, na maioria das vezes é sem querer) em engenharia de software.

Se temos um sistema com diversos componentes (podem ser módulos de um sistema monolítico, serviços de uma arquitetura SOA, microservices, enfim, qualquer unidade de código), sem um facade responsável por encadear chamadas, completar detalhes de entidades e descrever programaticamente o fluxo de um processamento, a chance de criarmos dependências cíclicas é bem grande.

Esse componente não pode conter nenhuma regra de negócio específica (num mundo ideal, não deveria conter nenhum if), apenas as chamadas para outros componentes especializados em determinada tarefa necessária para aquele fluxo de processamento.

Aqui temos um exemplo fictício de um sistema sem o facade:

Note que temos diversas dependências cíclicas nesse exemplo (diretas e indiretas), também percebemos uma alta complexidade na comunicação entre os componentes, a chance de existirem chamadas repetidas para obtenção de um mesmo dado é grande.

Nada impede (em termos de desenho da solução) que mais dependências cíclicas sejam criadas, e isso vai acontecer conforme esse exemplo se tornar mais complexo, com adição de mais componentes e mais fluxos. O troubleshooting do fluxo também é bastante espalhado, o fluxo não parece claro num simples desenho, o código então, nem se fala.

Facade ao resgate

Vamos reorganizar esse sistema utilizando uma camada a mais, o facade:

Com essa nova organização, conseguimos:

  • Ver o fluxo com mais clareza.
  • Os componentes especializados não precisam conhecer outros componentes especializados, apenas os dados que eles fornecem.
  • O fluxo é descrito programaticamente.
  • As chamadas podem ser feitas paralelamente.
  • Se um dos componentes falhar, o facade pode decidir se é uma falha catastrófica ou se é uma falha tolerável.
  • O facade pode controlar uma transação se necessário, de forma a encapsular essa complexidade e muitas outras!

São diversos benefícios! Esse desenho incentiva também o SRP (Single Responsibility Principle).

Organização dos serviços

Com o facade a tendência passa a ser pensar em componentes com menos responsabilidades e com a simplificação das dependências entre eles para apenas dados, obtemos uma organização natural do fluxo de processamento. Como os componentes não se integram diretamente o foco passa a ser em receber os dados necessários, efetuar um processamento e fornecer uma saída relevante para ser utilizada por outros componentes do sistema.

Otimização de recursos

O facade ajuda a reduzir o overhead de rede, principalmente se ele for posicionado como ponto de entrada público para um processamento. Tráfego público é mais caro e mais lento do que tráfego privado.

Por exemplo, fazer 10 chamadas diretamente do front-end, indo e voltando será mais lento e caro do que fazer apenas uma chamada para o facade e receber todos os dados necessários de uma vez só, principalmente se os seus servidores estiverem longe, nos EUA ou em algum outro país em que o preço deles seja mais barato do que no Brasil.

Não existe receita pronta!

Esse artigo foi inspirado em como organizamos um sistema para fornecer todas as informações necessárias para os sites e aplicativos do Grupo Zap. Tanto as utilizadas diretamente no frontend quanto no backend ou em workers que enviam e-mails, por exemplo.

Cada situação deve ser analisada individualmente! Existem casos em que não vale a pena seguir o modelo proposto aqui:

  • Um CRUD simples.
  • Sistemas com apenas uma dependência externa.
  • Sistemas especializados em uma tarefa específica e delimitada (cálculos, renderização…).

Devemos sempre primar pela simplicidade!

Conclusão

Apesar de estarem fora de moda, alguns Design Patterns ainda podem ser muito úteis mesmo nos dias de hoje.

O facade introduz um nível de organização extremamente alto a qualquer código em qualquer nível: design, arquitetura lógica e física. Mas o seu maior benefício, na minha opinião, está relacionado a prevenir dependências cíclicas, elas acabam com a vida útil de qualquer sistema, pois a cada nova funcionalidade ele fica mais complexo e mais difícil de manter.

Mais informações

https://en.wikipedia.org/wiki/Facade_pattern

https://en.wikipedia.org/wiki/Single_responsibility_principle