Manipuladores de comando e DDD

10

Eu tenho um aplicativo ASP.NET MVC, que usa um serviço de consulta para obter dados e um serviço de comando para enviar comandos. Minha pergunta é sobre a parte do comando.

Se uma solicitação for recebida, o serviço de comando usará um distribuidor de comandos que encaminhará o comando para seu manipulador de comandos designado. Este manipulador de comando valida o comando primeiro e, se tudo for aceitável, ele executa o comando.

Exemplo concreto: o AddCommentToArticleCommandHandler recebe um AddCommentToArticleCommand, que possui um ArticleId, CommentText e EmailAddress.

Primeiro; a validação deve ocorrer, como: - verifique se o artigo existe - verifique se o artigo não está fechado - verifique se o texto do comentário está preenchido e entre 20 e 500 caracteres - verifique se o endereço de email está preenchido e tem um formato válido.

Gostaria de saber onde colocar essa validação?

1 / no próprio manipulador de comandos. Mas, então, não pode ser reutilizado em outros manipuladores de comando.

2 / na entidade do domínio. Porém, como uma entidade de domínio não conhece repositórios ou serviços, não pode realizar a validação necessária (não pode verificar se existe um artigo). Mas, por outro lado, se a entidade não contém lógica, torna-se um simples contêiner de dados, que não segue os princípios DDD.

3 / o manipulador de comando usa validadores, para que a validação possa ser reutilizada em outros manipuladores de comando.

4 / Outros mecanismos?

Estou procurando a cadeia de responsabilidades desse exemplo em particular e quais objetos (entidades, repositórios, ...) desempenham um papel nele.

Você tem idéias sobre como implementar isso, iniciando no manipulador de comandos até os repositórios?

L-Four
fonte
"Mas como uma entidade de domínio não conhece repositórios ou serviços, não pode fazer a validação necessária"? Por que não? Que princípio do DDD exige isso?
S.Lott
Eu li em todos os lugares que uma entidade não deveria saber sobre repositórios ou qualquer outra coisa.
L-Four
Você pode fornecer uma cotação, link ou exemplo do que você leu especificamente? Não sabemos quais descrições de DDD você está lendo.
S.Lott 20/09
Jimmy Bogard compartilhou algumas opiniões sobre este tópico ... Lostechies.com/jimmybogard/2009/02/15/validation-in-a-ddd-world
Mayo

Respostas:

4

Eu acho que você precisa separar dois tipos de validação neste caso; validação de domínio e validação de aplicativo .

A validação de aplicativo é o que você possui quando verifica se a propriedade de comando 'text' tem entre 20 e 200 caracteres; para que você valide isso com a GUI e com um validador de modelo de exibição que também é executado no servidor após um POST. O mesmo vale para e-mail (btw, espero que você tenha percebido que um e-mail como `32.d +" Hello World .42 "@ mindomän.local" é válido de acordo com a RFC).

Então você tem outra validação; verifique se o artigo existe - você deve se perguntar por que o artigo não deveria existir, se houver realmente um comando enviado da GUI sobre como anexar um comentário a ele. Sua GUI acabou sendo consistente e você tem uma raiz agregada, o artigo, que pode ser fisicamente excluída do armazenamento de dados? Nesse caso, você apenas move o comando para a fila de erros porque o manipulador de comandos falha ao carregar a raiz agregada.

No caso acima, você teria uma infraestrutura que lida com mensagens suspeitas - elas, por exemplo, tentariam a mensagem de 1 a 5 vezes e depois a moveriam para uma fila de controle onde você poderia inspecionar manualmente a coleção de mensagens e despachar novamente as relevantes. É uma coisa boa para monitorar.

Então agora discutimos:

  • Validação de aplicativo

    • Com javascript na GUI
    • Com validação MVC no servidor da web
  • Filas agregadas raiz + envenenadas ausentes

E os comandos que estão fora de sincronia com o domínio? Talvez você tenha uma regra na lógica do seu domínio dizendo que, após 5 comentários em um artigo, apenas comentários abaixo de 400 caracteres são permitidos, mas um cara chegou muito tarde com o quinto comentário e chegou ao sexto - a GUI não o capturou porque não era consistente com o domínio no momento em que ele enviava seu comando - nesse caso, você tem uma 'falha de validação' como parte da lógica do domínio e retornaria o evento de falha correspondente.

O evento pode estar na forma de uma mensagem em um intermediário de mensagens ou em seu despachante personalizado. O servidor da Web, se o aplicativo for monolítico, poderá escutar de forma síncrona um evento de sucesso e o evento de falha mencionado e exibir a exibição / parcial apropriada.

Muitas vezes, você tem um evento personalizado que significa falha para muitos tipos de comandos e é esse evento que você assina da perspectiva do servidor da web.

No sistema em que estamos trabalhando, estamos realizando uma solicitação / resposta com comandos / eventos em um barramento de mensagens MassTransit + RabbitMQ + broker e temos um evento nesse domínio específico (modelando um fluxo de trabalho em parte) chamado InvalidStateTransitionError. A maioria dos comandos que tentam se mover ao longo de uma aresta no gráfico de estado pode causar esse evento. No nosso caso, estamos modelando a GUI após um paradigma eventualmente consistente e, portanto, enviamos o usuário para uma página 'comando aceito' e, a partir de então, deixamos que as visualizações do servidor da Web sejam atualizadas passivamente por meio de inscrições de eventos. Deve-se mencionar que também estamos fornecendo fontes de eventos nas raízes agregadas (e faremos também para as sagas).

Como você vê, muitas das validações de que você está falando são na verdade validações de tipo de aplicativo, não lógica de domínio real. Não há problema em ter um modelo de domínio simples se o seu domínio for simples, mas você estiver executando o DDD. Ao continuar modelando seu domínio, no entanto, você descobrirá que o domínio pode não ser tão simples como foi o primeiro. Em muitos casos, a raiz / entidade agregada pode aceitar apenas uma chamada de método causada por um comando e alterar parte de seu estado sem executar nenhuma validação - especialmente se você confiar em seus comandos como faria se os validasse no servidor Web que você controla.

Posso recomendar assistir as duas apresentações sobre DDD da Norwegian Developer Conference 2011 e também a apresentação de Greg no Öredev 2010 .

Saúde, Henke

Henrik
fonte
Obrigado! Uma coisa sobre a validação: no momento, essa validação é acionada pela interface do usuário (emitindo uma solicitação Validate (comando) para o serviço), que usa a Validate () da própria entidade Comment. Em seguida, se o comando for válido, o cliente emitirá um comando Execute, que executará novamente o Validate () para ter certeza e, se válido, o comando real será executado. Portanto, a validação principal é feita pela entidade Comment, porque em todos os contextos a validação será a mesma (o email sempre deve ser válido, o texto do comentário não é muito longo etc.) Essa é uma boa abordagem?
L-Four
A validação que você parece estar descrevendo não me parece justificá-la com um protocolo de validação de duas fases - com certeza, valide os parâmetros da invocação do método na entidade como se você testasse em um teste de unidade, mas além disso; a camada de aplicativo / GUI pode validar facilmente as regras que você está descrevendo sem enviar comandos para o domínio. Imo. A menos que o cliente seja malicioso, o comando deve funcionar. Se o cliente for malicioso, o comando falhará e seu modelo de leitura nunca receberá um evento correspondente e você poderá inspecionar o comando problemático na fila de erros.
Henrik
Na interface do usuário (ASP.NET MVC), estou usando atributos de validação para fazer toda a validação. Então, se essa validação tiver êxito, não preciso validar novamente no domínio, mas apenas executar o comando?
L-Four
11
Sim, você executa o comando, mas verifique se o comando não é inválido na camada e no domínio do aplicativo.
Henrik
0

EDIT: Link do WaybackMachine: http://devlicio.us/blogs/billy_mccafferty/archive/2009/02/17/a-response-to-validation-in-a-ddd-world.aspx

Não há resposta.

Existem dois cenários claros de projeto que vêm à mente quando tento responder onde a validação deve residir. O primeiro é onde uma camada DTO é usada para transferir informações entre as camadas de visualização e domínio. Por exemplo, você pode ter um objeto Cliente em sua camada de domínio e um DTO do Cliente associado em outra camada para a qual você mapeia as informações do Cliente, para fornecer a exibição para apresentar as informações do Cliente ao usuário.

O segundo cenário é um projeto em que as entidades da camada de domínio são compartilhadas diretamente com a exibição para apresentar os dados ao usuário. Por exemplo, em vez de manter uma camada DTO separada e mapear o objeto de domínio para os DTOs a serem fornecidos à exibição, a exibição pode receber diretamente o objeto Customer. Portanto, em vez de falar por meio de um DTO mantido separadamente para mostrar o nome de um cliente, a exibição simplesmente solicitaria as informações ao objeto Customer.

S.Lott
fonte