Pular para o conteúdo

Modelar o domínio

Linguagem ubíqua, event storming e onde traçar a fronteira de um agregado.

O código de domínio é tão bom quanto as palavras que ele usa. Se o negócio diz "o pedido foi faturado" e o código diz status = 3, cada conversa entre as duas pontas precisa de tradução — e a tradução é onde os requisitos se perdem.

Event storming, em três passos#

  • Os fatos, no passado. Numa parede (ou num documento), todo mundo escreve o que acontece no negócio: PedidoFeito, PagamentoConfirmado, PedidoEnviado. Discutir o nome de um fato é discutir o negócio.
  • O que os causa. Antes de cada fato, o comando que o provoca (Pagar) e quem o dá (o cliente, um sistema, o relógio).
  • O que precisa ser consistente junto. Os fatos que não podem divergir entre si formam um agregado. O resto se comunica por evento.

A fronteira do agregado#

SinalO que ele diz
dois comandos do mesmo agregado raramente disputamo tamanho está bom
`AggregateVersionError` frequenteo agregado junta coisas que mudam por motivos diferentes — divida
uma invariante precisa de dois agregadosou eles são um só, ou a regra é eventual e vira processo
o agregado carrega mil itens para mudar uma coleção deveria ser outro agregado, ligado por id
dataforge
adopt Arcane.Dominio as D

// a linguagem do negócio, e não a do banco
steady Dinheiro := D.valor("Dinheiro", ["centavos", "moeda"],
    regra := lambda v => v["centavos"] bigger_eq 0, motivo := "dinheiro não é negativo")

pedido := D.agregado("Pedido", D.novo_id(), situacao := "aberto", total := Dinheiro(0, "BRL"))
mark @pedido.comando("faturar")
action faturar(p):
    given p.ler("situacao") is not "aberto":
        trigger "só um pedido aberto é faturado"
    p.mudar(situacao := "faturado")
    p.aconteceu("PedidoFaturado")

pedido.faturar()
assert pedido.ler("situacao") is "faturado"
assert pedido.eventos()[0].nome is "PedidoFaturado"