DEV Community

Cover image for Event-Driven: Diferenças entre mensagens, eventos e comandos
José Roberto Araújo for Emerging Code

Posted on • Updated on

Event-Driven: Diferenças entre mensagens, eventos e comandos

A arquitetura de sistemas distribuídos tem como fundamento a comunicação de sistemas no formato assíncrono, baseando-se na troca de mensagens entre sistemas ou mesmo entre seus módulos.

Esse tipo de arquitetura compreende duas variações de mensagens: Eventos e Comandos. Esses dois tipos de mensagens possuem propósitos distintos, a nomeação desses tipos são determinados com base em suas intenções, o proprietário muda mediante o contexto, ou seja, é perceptível que tudo isso faz diferença durante a modelagem de uma mensagem em uma arquitetura Event-Driven e pode, consideravelmente, mudar a experiência do usuário final.


Mensagens

Toda comunicação baseia-se em uma mensagem. Quando você vai ao mercado perto da sua casa e tem dúvida sobre alguma coisa, o que acontece? Acontece, nesse momento, a abertura da comunicação entre duas partes: Você e uma outra pessoa (no mínimo 2 partes precisam existir para acontecer uma comunicação). Quando você quer enviar uma mensagem para alguém, através de algum aplicativo, o que você vai fazer é: Enviar uma mensagem! -- Não existe outra forma de ter comunicação, síncrona ou assíncrona sem existir uma: Mensagem. Sempre vamos ter um Produtor de mensagem e um consumidor dessa mesma mensagem

Em uma arquitetura Event-Driven não é diferente, se uma aplicação/módulo que conversar com outro, precisa existir uma comunicação através de uma: Mensagem.

E ai você pode virar pra mim e dizer: Poxa, bem que essa parte do artigo podia ser ignorada, né? Pois é! poderia ser ignorado SE os fundamentos não fossem tão importantes para o entendimento do todo.

Entender o básico, vai ajudar você no dia a dia a distinguir as diferenças entre os dois tipos de mensagens e entender quando e porquê usar cada um deles, além de entender o impacto que o uso equivocado desses tipos, pode causar na experiência com o usuário da sua aplicaçao, além de trazer impactos em COMO será pensada a arquitetura do sistema seja no Backend ou na experiência com o usuário.

Mensagem sendo enviada e consumida

Comandos

Comandos tem um propósito bem definido: Executar um Comportamento. Façamos aqui uma analogia: Quando você entra em um ambiente da sua casa e ele está com as lâmpadas apagadas, o que você faz? Aciona o interruptor e a lâmpada é acesa. O que acontece aqui é que foi enviado uma mensagem no formato de comando, o sistema elétrico reconheceu o comando e executou uma ação que foi acender a lâmpada e a resposta foi ter a lâmpada acesa.

Em uma arquitetura de sistemas distribuídos, também existe o envio de mensagens com a intenção de executar operações dentro de outros sistemas. É interessante observar que existem sistemas ou partes de um sistema que expõem suas capacidades/funcionalidades através de comandos.

Torna-se evidente que, ao executar um comando, o agente de execução espera por uma resposta ao comando enviado. Nesse caso, pode-se associar um comando a uma ação síncrona, onde o agente que enviou o comando fica aguardando o receptor do comando receber o tal comando, validar o payload, executar a operação e retornar dizendo o estado da operação.

Há quem diga que comandos podem ser geridos de forma assíncrona, e digo: Podem! Mas isso muda muito as regras do jogo e também dependendo de onde o comando foi originado, a resposta síncrona precisa acontecer dentro alguns segundos depois que o agente produtor enviou o comando, afim de dar um feedback, mais rápido possível, para quem produziu o comando.

Então pense bem: A origem do comando pode mudar completamente a experiência do usuário e, consequentemente, a abordagem arquitetural.

Abaixo existem 2 fronteiras lógicas diferentes, Pedido e Pagamento, onde cada uma delas envia um comando, mas haverá apenas 1 lugar dentro da arquitetura que terá a responsabilidade de saber reconhecer, validar, executar e responder a um comando. É o consumidor ou o Handler desse comando. É onde a regra do negócio será executada.

Comando de criação de pedido


Comando de preparação de pedido

Os dois exemplos acima estão usando uma Queue para gerir a produção e o consumo de mensagens desse tipo, afim de focarmos na abordagem da comunicação de sistemas distribuídos.

Comandos podem ser enviados de várias boundaries (limites) diferentes, ou seja, pode existir vários produtores diferentes para um mesmo comando. É quesionável? Bem! Pense em módulo de email. Um email pode ser disparado tanto pelo módulo de pedido, quando pelo módulo de registro de usuário pedindo para confirmar o cadastro. Nesse caso, existem 2 boundaries distintas, que podem enviar comandos para envio de emails.

A forma como se modela e nomeia um comando importa e faz toda a diferença. Perceba nos dois desenhos acima que, em nenhum momento, os comandos foram nomeados como: CriarPedido, AtualizarPedido, DeletarPedido. Essas ações constituem significados específicos e estão ligadas, diretamente, as intenções do negócio. Por isso é importante dar nomes coerentes aos comandos, como: AdicionarPedido, AjustarEstoque, PrepararPedido, EnviarPedido, etc. O comando PrepararPedido, sendo enviado a partir da boundary de Pagamento, quer dizer que o pagamento já foi realizado e que o pedido pode ser preparado para ser enviado.

Eventos

Tudo o que você viu no passado, não pode desvisto. Nada do que aconteceu no passado pode ser desfeito, mas o que aconteceu pode ser notificado/publicado para que alguém que tenha interesse nessa informação possa consumir. Essa é a premissa dos eventos, notificar o mundo externo que algo aconteceu.

Imagine o cenário onde você pede para alguém ir ao mercado comprar alguma comida que você deseja muito, é essa pessoa envia uma mensagem para você, dizendo: Comida comprada!

Os eventos possuem 2 partes, assim como os comandos. A primeira parte é o produtor da mensagem, é quem DETEM o Ownership do contrato da mensagem do tipo Evento, e esse produtor vai notificar o mundo externo sobre algo que já aconteceu. A segunda parte é a parte que consome esses eventos, ou seja, um consumer ou um handler, e que pode realizar alguma operação com base nas informações do payload desse tal evento.

O diagrama abaixo ilustra um único publicador (publisher/producer) de evento e vários consumidores interessados nesse evento:

Evento de Pedido adicionado

Através da ilustração do diagrama, é possível perceber que só existe uma única boundary responsável por produzir esse tal evento. É esse Contexto Delimitado (Bounded Context) que tem a lógica de o que produzir, qual payload quer compartilhar (dados) com o mundo externo e quando esse evento deve ser publicado.

O Consumidor de um evento, pode viver dentro de muitos contextos delimitados (bounded context) diferentes, com interesse em consumir o mesmo evento e realizar operações de lógica de negócio dentro de suas fronteiras. Não é obrigado existir sempre um consumidor de eventos, pode existir ZERO ou MUITOS.

Nomear os eventos é essencial para que a comunicação entre as boundaries (fronteiras) faça sentido e seja fácil identificar a intenção de cada evento. Uma vez que os eventos são algo que ocorreu no passado, fica claro que a nomenclatura deles DEVE ficar no passado. Como exemplos temos: PedidoAdicionado, EntregaRecebida, EmailEnviado, PagamentoProcessadoComSucesso. Esses nomes deixam claro qual é a intenção de comunicação dos eventos.

Ao modelar sistemas usando a abordagem do Domain-Driven Design (DDD), é comum perceber que dentro de cada contexto delimitado (bounded context) ações/operações que serão executadas é o geram como resultado, o que chamamos de: Eventos de Domínio. Existem alguns tipos diferentes de eventos e que são usados com finalidades específicas, como por exemplo: Eventos de integração. Em outro artigo, falarei sobre os diferentes tipos de eventos.

Comandos vs Eventos

Objetivo Comandos Eventos
Propósito Executar um comportamento Expor que algo aconteceu
Proprietário Propriedade do consumidor Propriedade do produtor
Consumidores Tem 1 consumidor Zero ou muitos consumidores
Produtores Muitos produtores Tem 1 produtor
Nomenclatura Verbo (indicar ação) Passado

Conclusão

A premissa de uma arquitetura Event-Driven não é apenas lidar com eventos, mas sim modelar a comunicação entre sistemas, através de mensagens, e essas terão suas classificações dependendo da intenção do conteúdo de uma mensagem.

Referências

Junte-se a nossa comunidade

No Youtube você vai encontrar vídeos sobre System Design, Software Architecture. Quer conversar sobre Domain-Driven Design, System Design, Software Architecture? Então faça parte da nossa comunidade no Discord.

Se quiser se aprofundar mais sobre Event-Driven e CQRS, acesse nosso curso de Arquitetura CQRS e acesse o repositório do projeto no Github

Top comments (0)