Como os comandos Adicionar / Criar * devem ser tratados na arquitetura CQRS + Event Sourcing


11

Quero implementar meu primeiro aplicativo usando o padrão CQRS junto com o Event Sourcing. Gostaria de saber como a criação de raízes agregadas deve ser tratada adequadamente. Digamos que alguém envie o comando CreateItem. Como deve ser tratado? Onde o evento ItemCreated deve ser armazenado? Como primeiro evento de um novo item? Ou devo ter algum tipo de entidade ItemList que agrega todos os itens e sua lista de eventos consiste apenas em eventos ItemCreated?

Udi Dahan sugere não criar raízes agregadas e sempre usar algum tipo de método de busca. Mas como posso buscar algo novo e certamente não tem nenhum ID atribuído. Eu entendo a idéia por trás e é bastante razoável pensar que um novo objeto é um objeto cujo estado é composto de zero eventos respondidos. Mas como devo usá-lo? Devo ter um método distinto no meu Repositório como getNewItem()ou fazer meu get(id)método aceitar Optional<ItemId>?

Edit: Depois de algum tempo de escavação, achei a implementação realmente interessante dos padrões acima mencionados usando atores. O autor, em vez de criar o agregado, o recupera de algum tipo de repositório com o UUID recém-criado. A desvantagem dessa abordagem é que ele permite um estado de inconsistência temporário. Também estou querendo saber como posso implementar o deletemétodo com essa abordagem. Basta adicionar o evento Excluído à lista de eventos do agregado?


1
Suspeito que o pós-título de Udi seja enganador. IMHO, parece que seu objetivo real é que os ARs recém-fabricados sempre estejam acessíveis de outro lugar, de uma maneira que capte o contexto sobre por que / como / quem decidiu que o novo AR precisava ser criado. Todo o resto é sobre como uma implementação específica (NHibernate?) Pode facilitar o gerenciamento.
— Darien

2
Observe que o artigo de Udi Dahan que você está referenciando especificamente ressalta que seus conselhos podem não se aplicar à fonte de eventos: udidahan.com/2009/06/29/dont-create-aggregate-roots/…
— EZ Hart

Respostas:


13

A idéia no post de Udi, como reconheço, é que nenhum tipo de item aparece do nada. Há (quase) sempre alguma coisa, ou mais especificamente, alguma operação de domínio, que causou a criação do item. Assim como o exemplo de Udi de um usuário realmente nascido de um visitante que se registra no site. Nesse ponto e nesse contexto limitado, Visitor é a raiz agregada, que é recuperada por seu endereço IP. Este Visitante cria o novo "item", um usuário neste momento, por meio de uma operação de domínio chamada Registro . O mesmo vale para a etapa anterior, que é outro contexto limitado: o referenciador é o AR, que é recuperado pela URL e que possui uma operação de domínio chamada BroughtVisitorWithIp , onde o visitante nasceu.

O Udi também escreve muito bem sobre exclusão: http://www.udidahan.com/2009/09/01/dont-delete-just-dont/ . A idéia principal é que você nunca exclua nada. Há sempre uma operação de domínio por trás, que queremos capturar. Como um pedido sendo cancelado, em vez de excluído. Leia, é um post muito bom.

O ponto principal aqui em ambas as contas, executando DDD e, especialmente, Event Sourcing, é que você nunca deve fazer operações CRUD diretas. Se você se encontrar em uma situação em que realmente precisa apenas inserir, atualizar ou excluir alguns dados, e realmente não há nenhuma operação de domínio por trás disso, talvez o DDD e o Event Sourcing não sejam adequados para esse contexto limitado . Você é livre para combinar esses dois conforme desejar, desde que um único contexto delimitado adira a um princípio. Dessa forma, o contexto limitado no estilo CRUD pode criar alguma linha no banco de dados, que se torna uma entidade e uma raiz Agregada em outro contexto limitado, onde agora você pode recuperar o AR e não precisar criá-lo.


2
"talvez o DDD e o Event Sourcing não sejam adequados para esse contexto limitado". Você entende direito o DDD. Não deve ser implementado em todos os casos apenas para a glória de satanás, mas apenas quando é necessário lidar com um domínio complexo e cheio de regras incertas. Pessoalmente, eu fiz isso para software jurídico em que os requisitos não são conduzidos pela lógica.
— Yegor Chumakov

2
+1 apenas nesta frase "para esse contexto limitado". :)
— Songo 03/07

2
Em +1, o uso dos verbos 'Adicionar' e 'Criar' é altamente sugestivo de que você ainda está pensando em seu domínio em termos de interação com um bom e antigo banco de dados tabular. Sem conhecer seu domínio / contexto limitado, não posso dizer se isso é apropriado ou não. Ignore a persistência, concentre-se primeiro nos COMANDOS e EVENTOS (também conhecidos como INTENÇÕES e RESULTADOS), que são exclusivos do seu domínio, e depois se preocupe com a persistência do estado, que é um problema que já foi resolvido centenas de milhares de vezes antes.
— Matt

"o uso dos verbos 'Adicionar' e 'Criar' é altamente sugestivo de que você ainda está pensando em seu domínio em termos de interação com um bom e antigo banco de dados tabular" Hmmm. Quando você tem um design de interface do usuário com um grande botão 'Adicionar algo', então, infelizmente, essa é a intenção; literalmente para adicionar algo novo. Eu geralmente concordo com você, mas não estamos falando no nível do banco de dados aqui; às vezes, Adicionar ou Criar são, na verdade, as palavras certas para usar.
— Designer # #

1
@designermonkey Quando você tem esses botões na interface do usuário, você realmente tem uma operação de domínio por trás deles? Talvez, mas 9 em 10 vezes não haja realmente uma operação de domínio complexa nesse contexto limitado. E a operação CRUD pura é apenas isso, uma operação CRUD pura e deve ser tratada como tal. Somente quando houver necessidade da complexidade do modelo de domínio, ele deve ser usado. Assim, os diferentes contextos delimitados com diferentes princípios de design.
— Tuukka Haapaniemi
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.