Notificação por eventos

De tempos em tempos, algumas abordagens de desenvolvimento parecem virar padrão recorrente. Depois de algum tempo vendo empresas adotarem (as vezes, sem justificativa real) arquiteturas baseadas em microsserviços, estamos percebendo interesse crescente em padrões baseados em eventos.

Nesse, e em outros posts, vamos apresentar alguns conceitos chaves e padrões recorrentes para adoção de eventos no desenvolvimento de software. Comecemos com sistemas que empregam notificações por eventos.

Entendendo a ideia principal

Imagine um sistema onde, toda vez que um componente (módulo, microsserviço, etc) conclui uma operação, precisa inicar uma operação associada em outro componente.

Por exemplo, considere um sistema de e-commerce, onde, após confirmada uma venda, seja necessário disparar o processo de separação e remessa de um produto.

Uma abordagem ingênua simples, seria fazer com que o primeiro componente acione ativamente o segundo componente (chamando um método, fazendo um request para algum endpoint específico, enviando uma mensagem “comando”, etc).

Ainda em nosso exemplo, poderíamos considerar que o sistema de vendas “chamaria”  o sistema de remessas com uma chamada a um endpoint, ou, em um cenário monolítico, executando um método.

Uma solução mais complexa sofisticada, entretanto, seria fazer com que o primeiro componente “disparasse” uma mensagem notificando a ocorrência de um evento de negócio. Caberia ao segundo componente”escutar” essa mensagem e realizar o processamento adequado. Nesse cenário, o primeiro componente acionaria passivamente o segundo componente.

Assim, ainda em nosso exemplo, poderíamos fazer com que o sistema de vendas “disparasse” um evento com dados relacionados a venda que acabou a ser realizada. Enquanto isso, o sistema de remessas “escutaria” esse evento e faria seu trabalho.

Essa abordagem possui o efeito colateral positivo de permitir que outros componentes “escutassem” um mesmo evento permitindo a adição de outros processamentos sem que exista a necessidade de alterar as partes que já estão funcionando no sistema.

Por que desenvolver sistemas com notificação por eventos?

Sistemas distribuídos (incluindo aqueles baseados microsserviços) estão ficando cada vez mais comuns. Nesses sistemas, um dos atributos arquiteturais mais importantes é o baixo acoplamento. 

Da Wikipedia:

Em engenharia de softwareacoplamento ou dependência é o grau de interdependência entre módulos de software; uma medida de quão intimamente ligadas estão duas rotinas ou módulos; a força das relações entre módulos.

O acoplamento é geralmente contrastado com coesão. O baixo acoplamento geralmente se correlaciona com alta coesão e vice-versa. O baixo acoplamento é frequentemente um sinal de um sistema de computador bem estruturado e de um bom design, e quando combinado com alta coesão, suporta os objetivos gerais de alta legibilidade e facilidade de manutenção.

Em termos práticos, queremos desenvolver, distribuir e manter sistemas, alterando suas partes, sem afetar as demais. A estratégia para comunicação entre componentes, empregando notificação por eventos, ajuda a desenvolver sistemas com baixo acomplamento.

Em 2002, trabalhei no desenvolvimento de uma solução CAD complexa. Um dos objetivos do projeto, na época, era desenvolver um sistema extremamente componível (queríamos poder instalar plugins no sistema, enriquecendo suas features).

Determinamos que cada vez que uma operação fosse realizada, ou houvesse mudança de estado, um evento fosse disparado (na época, chamamos de gatilho) em um “bus” rudimentar. Os “plugins” do sistema tinham acesso ao “bus” e conseguiam “identificar” quando um gatilho (evento) de um determinado tipo havia sido disparado e conseguiam então executar processamentos relacionados.

Tangibilizando, é como se no “word”, quando o usuário ativasse negrito usando atalhos de teclado, fosse disparado um “evento” que o botão na toolbar “escutaria”, se ativando.

Problemas em sistemas que empregam notificações de eventos

Baixo acoplamento é ótimo. Porém, tem um preço que pode ser bem alto.

Quando permitimos que componentes comecem a “escutar” eventos em nossa aplicação, é fácil perder o controle do que será executado.

No sistema desktop que descrevi acima, começamos a padecer com componentes que realizavam processamentos pesados como “resposta” a eventos e a aplicação, muitas vezes, perdia em responsividade.

Sistemas distribuídos, baseados em notificações por eventos, tornam alguns tipos de operações comuns (como transações) difíceis de implementar e, principalmente, monitorar.

Importante determinar que é possível conseguir um bom nível de baixo acoplamento simplesmente implementando abordagens assíncronas para acionamento ativo (como envio de comandos de um componente para outro usando algum mecanismo de mensageria).

Concluindo

Sistemas baseados em notificações com eventos tem, naturalmente, baixo acoplamento e tendem a ter evolução facilitada. Entretanto, é necessário estar atento a “evolução” dos fluxos de execução balanceando “complexidade” com simplificação da implementação das operações do domínio.

Sistemas baseados em eventos apresentam novos e complexos desafios para implantação de monitoramento (tema para outro post).

Você tem alguma experiência desenvolvimento sistemas que adotam eventos de notificação?

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
19 Comentários
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Arley Pádua
Arley Pádua
4 anos atrás

Um outro ponto importante nesse assunto é que eventos vendem a idéia de baixo acoplamento, mas se esquecermos que o conteúdo dos eventos também causam acoplamento, o objetivo de desacoplar não é alcançado, resultando em um acoplamento distribuído.

Exemplo comum, porém errôneo: Serviço A notifica que um cliente foi registrado. Serviço B escuta esse evento e salva o nome do cliente em seu banco de dados para ser usado posteriormente. Nesse momento, serviço B passa a depender do serviço A notificá-lo de que o nome do cliente foi alterado.

Em um cenário como esse, é importante manter os dados protegidos em seus contextos (serviços) evitando a dependência no conteúdo do evento.

Serviço A sabe o nome do cliente, porém só pública a informação de que um cliente X foi registrado. Serviço B registra a existência do cliente X, somente como referência e outros dados relacionados ao contexto do serviço B.

TL;DR
Uma dica muito boa que me ajuda a modelar sistemas distribuídos, quando necessário: Não vaze informação de negócio para fora do seu lugar de coesão.

Alessandro de Souza
Alessandro de Souza
4 anos atrás

Pensa na alegria da pessoa – eu – ao ler essa matéria e estar no meio do desenvolvimento de um sistema em node tentando dividir em Bounded Contexts e usando justamente a abordagem assíncronas para acionamento ativo com chamadas assíncrona em um pub/sub simples.

Alessandro de Souza
Alessandro de Souza
4 anos atrás

Não entendi…
Na sua solução, como o serviço B ficará sabendo se o nome do cliente for alterado?
Nunca? , ou pior, terá um ‘endpoint’ específico pra alterar o nome do cliente?

Poderia explicar, por gentileza?
Pq eu uso exatamente o cenário ‘errado’ que vc disse.

Obrigado.

Arley
Arley
4 anos atrás

Fala Alessandro,
A resposta curta para a sua pergunta é: O Serviço B não precisa saber que o nome foi alterado. O nome deve ser de responsabilidade de um e somente um serviço.

Exemplificando mais, me permita dar mais detalhes de um domínio de exemplo:

Serviço A seria o serviço de Carteira de Clientes
Serviço B seria o serviço de Faturamento

Digamos que temos uma feature a ser implementada: Integrar com a receita federal a nota fiscal de um pedido faturado.
E por lei, o nome do cliente é obrigado.

Nesse cenário:
– Serviço de Carteira de Clientes saberia qual o cliente/nome associado a um pedido.
– Serviço de Faturamento sabe quando um pedido é faturado
– Serviço de Faturamento comanda a integração de uma nota fiscal
– Serviço de Integração c/ Receita recebe essa requisição e obtém os dados necessários para nota fiscal
— Nome do cliente vindo da Carteira de Cliente
— Valor do pedido vindo do Faturamento
— Endereço de entrega vindo do serviço Z
– Serviço de Integração c/ Receita integra a nota fiscal com os dados compostos

Perceba que o nome do cliente nunca saiu do seu contexto e que Faturamento não tem nenhum motivo para manter o nome do cliente.
No exemplo da nota fiscal, o nome é necessário, e é obtido na forma de composição. Da mesma forma que em um relatório, o nome pode ser necessário e será obtido por meio de composição.

Elemar Júnior
Elemar Júnior
4 anos atrás

O acoplamento a uma mensagem é menor que o acoplamento a um serviço específico. Não? 🙂

Alessandro de Souza
Alessandro de Souza
4 anos atrás

Oi.. entendi perfeitamente sua explicação e agradeço..
Porém, me permita te dar uma sugestão: dê uma olhada em microserviços autônomos. Muito resumidamente, você deve trocar mensagens entre os serviços via mensageira de forma que quando um serviço for realizar o seu trabalho os dados já estejam no seu banco, sem precisar fazer requisição para outro serviço. Até porque, especialmente Se for requisição síncrona gera acoplamento.

Arley
Arley
4 anos atrás

No exemplo anterior quando digo requisição, quero dizer qualquer forma de comandar algo a outro componente.
Valeu pela sugestão, porém essa abordagem propõe replicar os dados onde ele for necessário. Caso esse dado seja alterado na origem, o custo de manutenção desse dado em todas as dependências é muito alto, sendo muito fácil de perder em quem é a autoridade de negócio responsável pelo dado. No final o que se tem é uma confusão de quem é dono de quem.

É importante desacoplar com mensageria, mas acho mais importante ainda desacoplar no nível da dependência do dado, pois é nesse nível que se protege os bounded contexts.

Ja mexi com backend distribuído dessa forma (sem pensar se faz sentido o dado se espalhar pra todo lado) e era comum dar desculpas em nome da consistência eventual (as vezes nem eventual chegava).

Arley
Arley
4 anos atrás

Sim, concordo. Mas botar uma mensagem no meio não é tudo.
Óbvio que não depender do SLA do outro componente já adianta muito, mas não é tudo 🙂

Alessandro de Souza
Alessandro de Souza
4 anos atrás

Arley.. só me restou uma dúvida na sua abordagem: eu só não consigo entender como vc fará uma requisição assincrona quando um serviço precisa integrar os dados de vários outros serviços para realizar seu processo (enviar nf para a receita no seu exemplo). Só vejo sendo feito via requisição síncrona. E entre ter uma requisição síncrona e um dado bem documentado de outro serviço (detalhe para o bem documentado) ‘representando uma entidade’ de outro serviço para que eu já tenha tudo que preciso para executar uma tarefa em um serviço, essa última me parece a melhor abordagem. IMHO. Abraço….

Alessandro de Souza
Alessandro de Souza
4 anos atrás

Me esqueci de um outro detalhe: grandes players usam essa abordagem mais ou menos como eu disse. Ex: o Elemar em uma de suas palestras deu o exemplo do Facebook. Quando vc pede pra trocar seu nome, ele te pede até 72hrs, salvo engano, para realizar o processo. Ou seja, em back ele está replicando os dados (seu nome alterado) em todos os seus posts, comentários etc.. etc….
Até porque quando ele lista seus posts e comentários, se ele tiver que fazer solicitação para outro serviço só pra pegar seu nome. seria inviável.

Thiago Castro
Thiago Castro
4 anos atrás

Perfeito, finalmente um comentário sensato vindo de um case real. Event Bus só desacopla nos artigos e nos diagramas dos arquitetos que ficam depois para dar manutenção.

Thiago Castro
Thiago Castro
4 anos atrás

Corrigindo: “Event Bus só desacopla nos artigos e nos diagramas dos arquitetos que NÃO ficam depois para dar manutenção.”.

Elemar Júnior
Elemar Júnior
4 anos atrás

Concordamos em discordar. Não dá para balizar o mundo apenas por suas experiências.

Elemar Júnior
Elemar Júnior
4 anos atrás

Não se trata, necessariamente, de eliminar o acoplamento. Mas, sim, em buscar alternativas de acoplamento mais baratas.

Concordo com você que algum acoplamento é preservado. Entretanto, concordemos que é um acoplamento menor.

Elemar Júnior
Elemar Júnior
4 anos atrás

Há um porém. Rede costuma ser um grande problema para performance. Se a demanda por um serviço for alta o suficiente, como indicado no próximo post da série (https://www.eximiaco.tech/pt/2019/08/12/event-carried-state-transfer/) pode valer a pena.

Elemar Júnior
Elemar Júnior
4 anos atrás

🙂 Concordamos. Não é tudo, mas é bastante, em muitos cenários.

Elemar Júnior
Elemar Júnior
4 anos atrás

Thiago, adoraria entender melhor sua perspectiva. Há um “mundo” de implementações nesse modelo. Honestamente, gostaria de entender o que te fez fazer essa generalização.

Em tempo, no texto do post há um exemplo onde indiquei uma implementação concreta onde eventos fizeram sim desacoplamento. O problema, se moveu para tracing .. mas a conversa é outra.

Elemar Júnior
Elemar Júnior
4 anos atrás

Em tempo, nossa recomendação de leitura dessa semana pode ajudar a ver algumas possiilidades interessantes.

https://www.eximiaco.tech/pt/2019/08/16/enterprise-integration-patterns-eip/

Márcio
Márcio
4 anos atrás

Acho que vai gostar -> http://vertx.io/

[]s

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
19
0
Queremos saber a sua opinião, deixe seu comentáriox
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Notificação por eventos

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Notificação por eventos

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?