Como modelar eventos de domínio com clareza e sem ambiguidade
1. Fundamentos da modelagem de eventos de domínio
Eventos de domínio representam fatos consumados que ocorreram dentro de um contexto delimitado (bounded context). No design orientado a eventos, eles são a espinha dorsal da comunicação entre agregados e sistemas, registrando mudanças de estado que importam para o negócio.
A principal diferença entre tipos de eventos é:
- Evento de domínio: algo que aconteceu no negócio (ex: Pedido.Confirmado)
- Evento de integração: comunicação entre sistemas (ex: Pedido.EnviadoParaERP)
- Evento de sistema: mudança técnica (ex: Cache.Atualizado)
Para identificar eventos relevantes, utilize a linguagem ubíqua do domínio. Pergunte: "O que os especialistas do negócio dizem que aconteceu?" Se a frase "Quando X acontece, fazemos Y" surge naturalmente, você encontrou um evento.
2. Estrutura do nome do evento: verbo no passado + contexto
O padrão mais claro é [Entidade].[AçãoRealizada] com verbo no particípio passado:
Pedido.Faturado
Cliente.Cadastrado
Estoque.Reservado
Pagamento.Autorizado
Evite nomes genéricos como DadosAtualizados — prefira Cliente.EnderecoAlterado. Qualificadores adicionais resolvem ambiguidades:
// Ambíguo
Pedido.Modificado
// Claro
Pedido.ValorTotalRecalculado
Pedido.ItemRemovido
3. Definição de propriedades essenciais do evento
Todo evento de domínio deve conter:
Evento: Pedido.Faturado
{
"eventId": "evt_9a8b7c6d-1234",
"timestamp": "2025-03-15T14:30:00Z",
"version": 1,
"data": {
"pedidoId": "ped_12345",
"clienteId": "cli_67890",
"valorTotal": 1250.00,
"dataFaturamento": "2025-03-15"
}
}
Regras importantes:
- Identificador único: UUID ou chave globalmente única
- Timestamp: UTC, formato ISO 8601
- Versão do evento: número inteiro para rastrear schema
- Dados do agregado: apenas o necessário para o contexto. Não inclua detalhes de implementação como IDs de tabelas ou campos técnicos.
4. Granularidade adequada: eventos atômicos vs. eventos compostos
A granularidade errada é uma das maiores fontes de ambiguidade. Use eventos atômicos quando cada mudança tem significado independente:
// Eventos atômicos (recomendado para independência)
Pedido.Item.Adicionado
Pedido.Item.Removido
Pedido.Item.QuantidadeAlterada
// Evento composto (use quando as mudanças são inseparáveis)
Pedido.PrecoRecalculado
Regras para decidir:
- Evento atômico: quando consumidores precisam reagir a mudanças específicas
- Evento composto: quando várias mudanças formam uma única transação lógica e inseparável
- Evite: eventos que misturam responsabilidades ou são tão granulares que geram ruído
Exemplo de modelagem ruim:
// Ruim: muito genérico e ambíguo
Cliente.Alterado
// Ruim: muito granular sem necessidade
Cliente.PrimeiroNomeAlterado
Cliente.UltimoNomeAlterado
Cliente.EmailAlterado
// Bom: agrupamento lógico
Cliente.DadosCadastraisAlterados
Cliente.EmailAlterado
5. Versionamento e evolução de eventos
Eventos evoluem. Use versionamento semântico para garantir compatibilidade:
// Versão 1
Evento: Pedido.Faturado (v1)
{
"pedidoId": "ped_123",
"valorTotal": 1250.00
}
// Versão 2 (adiciona campo opcional)
Evento: Pedido.Faturado (v2)
{
"pedidoId": "ped_123",
"valorTotal": 1250.00,
"descontoAplicado": 50.00 // campo opcional
}
Estratégias de migração:
// Consumidor v1 ignora campos desconhecidos
// Consumidor v2 usa campo com default
{
"pedidoId": "ped_123",
"valorTotal": 1250.00,
"descontoAplicado": null // interpretado como 0
}
Nunca remova campos existentes sem depreciação. Adicione campos como opcionais e documente a transição.
6. Documentação e rastreabilidade dos eventos
Crie um catálogo centralizado de eventos. Exemplo de entrada:
Evento: Pedido.Faturado
Versão: 2
Origem: Serviço de Faturamento
Destino: Serviço de Contabilidade, Serviço de Notificação
Descrição: Disparado quando um pedido é faturado com sucesso
Schema: pedido_faturado_v2.avsc
Exemplo:
{
"eventId": "evt_abc123",
"timestamp": "2025-03-15T14:30:00Z",
"version": 2,
"data": {
"pedidoId": "ped_12345",
"clienteId": "cli_67890",
"valorTotal": 1250.00,
"descontoAplicado": 50.00
}
}
Use schemas para validação automatizada. JSON Schema é acessível para todos:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"eventId": { "type": "string", "pattern": "^evt_" },
"timestamp": { "type": "string", "format": "date-time" },
"version": { "type": "integer", "minimum": 1 },
"data": {
"type": "object",
"properties": {
"pedidoId": { "type": "string" },
"valorTotal": { "type": "number", "minimum": 0 }
},
"required": ["pedidoId", "valorTotal"]
}
},
"required": ["eventId", "timestamp", "version", "data"]
}
7. Padrões para evitar ambiguidades em cenários complexos
Tratamento de valores nulos vs. ausência
// Campo ausente: consumidor assume que não mudou
{
"descontoAplicado": null // campo presente, mas nulo = desconto zerado
}
// Campo ausente: consumidor usa valor do evento anterior
{
// "descontoAplicado" não está presente
}
Eventos de compensação
Use nomenclatura clara para ações de rollback:
Pagamento.Autorizado
Pagamento.Estornado // compensação de Autorizado
Estoque.Reservado
Estoque.ReservaLiberada // compensação de Reservado
Idempotência e eventos duplicados
Todo consumidor deve tratar eventos duplicados. Use o eventId para deduplicação:
// Estratégia: armazenar eventIds processados
// Se eventId já foi processado, ignorar
// Se não, processar e armazenar eventId
// Exemplo de evento duplicado seguro
Evento: Pedido.Faturado
eventId: "evt_9a8b7c6d-1234" // mesmo ID = mesma ação
Eventos simultâneos
Quando eventos podem ocorrer ao mesmo tempo, use timestamps e ordenação lógica:
// Dois eventos no mesmo milissegundo
// Use sequenciador lógico para ordenar
Evento: Pagamento.Autorizado (timestamp: 2025-03-15T14:30:00.000Z, seq: 1)
Evento: Pedido.Confirmado (timestamp: 2025-03-15T14:30:00.000Z, seq: 2)
Conclusão
Modelar eventos de domínio com clareza exige disciplina em nomenclatura, granularidade, versionamento e documentação. Cada evento deve ser um fato consumado, imutável e auto-contido. Use a linguagem ubíqua como guia, evite ambiguidades com qualificadores precisos e mantenha um catálogo centralizado. Com essas práticas, seus eventos se tornam a fonte de verdade confiável para todo o ecossistema orientado a eventos.
Referências
- Event Sourcing Pattern - Microsoft Azure Architecture Center — Guia completo sobre event sourcing, incluindo modelagem de eventos de domínio e armazenamento de eventos imutáveis.
- Domain Event Pattern - Martin Fowler — Artigo seminal de Martin Fowler definindo eventos de domínio e suas propriedades essenciais.
- JSON Schema Specification — Documentação oficial do JSON Schema para validação de schemas de eventos.
- Avro Schema Specification - Apache Avro — Especificação oficial do Apache Avro para serialização e versionamento de eventos.
- Event-Driven Architecture - AWS Whitepaper — Whitepaper da AWS abordando boas práticas para modelagem de eventos em arquiteturas orientadas a eventos.
- Versioning Events in Event-Driven Systems - Confluent Blog — Artigo técnico sobre estratégias de versionamento de eventos sem quebrar consumidores existentes.
- Idempotency in Event-Driven Systems - Red Hat Developer — Tutorial prático sobre implementação de idempotência para evitar duplicação de eventos.