Gestori di comandi e DDD

10

Ho un'applicazione ASP.NET MVC, che utilizza un servizio di query per ottenere dati e un servizio di comando per inviare comandi. La mia domanda riguarda la parte di comando.

Se arriva una richiesta, il servizio comandi utilizza un commander di comandi che instraderà il comando al relativo gestore comandi designato. Questo gestore comandi convalida prima il comando e se tutto è accettabile, esegue il comando.

Esempio concreto: AddCommentToArticleCommandHandler riceve un AddCommentToArticleCommand, che ha un ArticleId, CommentText e EmailAddress.

Per prima cosa; la validazione deve avvenire, come: - controlla se l'articolo esiste - controlla se l'articolo non è chiuso - controlla se il testo del commento è compilato e tra 20 e 500 caratteri - controlla se l'indirizzo email è compilato e ha un formato valido.

Mi chiedo dove mettere questa convalida?

1 / nel gestore di comandi stesso. Ma poi, non può essere riutilizzato in altri gestori di comandi.

2 / nell'entità del dominio. Ma poiché un'entità di dominio non sa di repository o servizi, non può effettuare la convalida necessaria (non è possibile verificare se esiste un articolo). D'altro canto, se l'entità non contiene la logica, diventa un semplice contenitore di dati, che non segue i principi del DDD.

3 / il gestore comandi utilizza i validatori, in modo che la convalida possa essere riutilizzata in altri gestori di comandi.

4 / Altri meccanismi?

Sto cercando la catena di responsabilità per questo particolare esempio e quali oggetti (entità, repository, ...) hanno un ruolo in esso.

Hai idee su come implementarlo, a partire dal gestore di comando fino ai repository?

    
posta L-Four 20.09.2011 - 11:13
fonte

2 risposte

4

Penso che sia necessario separare due tipi di convalida in questo caso; convalida del dominio e convalida dell'applicazione .

La convalida dell'applicazione è ciò che si ha quando si verifica che la proprietà del comando 'testo' sia compresa tra 20 e 200 caratteri; quindi lo convalidi con la GUI e con un validatore del modello di visualizzazione che viene eseguito anche sul server dopo un POST. Lo stesso vale per l'e-mail (btw, spero che tu ti renda conto che un'e-mail come "32 .d +" Hello World .42 "@ mindomän.local" è valida secondo la RFC).

Quindi hai un'altra convalida; controlla che l'articolo esista - devi porsi la domanda perché l'articolo non dovrebbe esistere se c'è davvero un comando inviato dalla GUI che riguarda l'allegare un commento ad esso. La tua GUI alla fine era coerente e hai una radice aggregata, l'articolo, che può essere fisicamente cancellato dall'archivio dati? In tal caso basta spostare il comando nella coda degli errori perché il gestore comandi non riesce a caricare la radice aggregata.

Nel caso precedente, avresti un'infrastruttura che gestisce i messaggi velenosi: per esempio, ripeteranno il messaggio 1-5 volte e poi lo sposteranno in una coda di poision in cui potresti ispezionare manualmente la raccolta di messaggi e ri-inviare quelli rilevante. È una cosa buona da monitorare.

Quindi ora abbiamo discusso:

  • Convalida dell'applicazione

    • Con javascript nella GUI
    • Con convalida MVC sul server web
  • Routine aggregate mancanti + code velenose

E i comandi che non sono sincronizzati con il dominio? Forse hai una regola nella logica del tuo dominio che dice che dopo 5 commenti a un articolo, sono ammessi solo commenti inferiori a 400 caratteri, ma un ragazzo era troppo in ritardo con il 5 ° commento e doveva essere il 6 ° - la GUI non l'ha catturato perché non era coerente con il dominio nel momento in cui inviava il suo comando - in questo caso hai un 'errore di convalida' come parte della tua logica di dominio e restituiresti il corrispondente evento di errore.

L'evento potrebbe essere sotto forma di un messaggio su un broker di messaggi o sul tuo dispatcher personalizzato. Il server Web, se l'applicazione è monolitica, può ascoltare contemporaneamente sia un evento di successo che l'evento di errore menzionato e visualizzare la vista / parziale appropriata.

Spesso hai un evento personalizzato che significa fallimento per molti tipi di comandi, ed è questo evento a cui ti abboni dal punto di vista del server web.

Nel sistema su cui stiamo lavorando, stiamo facendo una richiesta-risposta con comandi / eventi su un bus + broker di messaggi MassTransit + RabbitMQ e abbiamo un evento in questo particolare dominio (modellando un flusso di lavoro in parte) che è chiamato InvalidStateTransitionError . La maggior parte dei comandi che tentano di spostarsi lungo un bordo nel grafico di stato può causare questo evento. Nel nostro caso, modifichiamo la GUI dopo un paradigma alla fine coerente, quindi inviamo l'utente a una pagina di "comando accettato" e in seguito le visualizzazioni del server Web vengono passivamente aggiornate attraverso le sottoscrizioni degli eventi. Va detto che stiamo facendo anche l'event-sourcing nelle radici aggregate (e lo faremo anche per le saghe).

Così vedi, molte delle convalide di cui stai parlando sono in realtà delle convalide di tipo applicativo, non una vera logica di dominio. Non c'è alcun problema nell'avere un modello di dominio semplice se il tuo dominio è semplice ma stai facendo DDD. Continuando a modellare il tuo dominio, tuttavia, scoprirai che il dominio potrebbe non essere così semplice come prima. In molti casi la radice / entità aggregata potrebbe accettare una chiamata al metodo causata da un comando e modificare parte del suo stato senza nemmeno eseguire alcuna convalida, specialmente se ci si fida dei comandi come si farebbe se li si convalida nel server Web che tu controlli.

Posso consigliare e guardare le due presentazioni su DDD da Norwegian Developer Conference 2011 e anche la presentazione di Greg a Öredev 2010 .

Saluti, Henke

    
risposta data 21.09.2011 - 22:47
fonte
0

EDIT: link WaybackMachine: link

Non c'è risposta.

There are two clear project scenarios which come to mind when I try to answer where validation should live. The first is wherein a DTO layer is used to transfer information between the view and domain layers. For example, you may have a Customer object in your domain layer and an associated Customer DTO in another layer to which you map the Customer information, to then give to the view for presenting Customer information to the user.

The second scenario is a project wherein the entities within the domain layer are shared directly with the view to present the data to the user. For example, instead of maintaining a separate DTO layer and mapping domain object to the DTOs to be given to the view, the view could be given the Customer object directly. So instead of talking via a separately maintained DTO to show a Customer's name, the view would simply ask the Customer object itself for the information.

    
risposta data 20.09.2011 - 12:40
fonte

Leggi altre domande sui tag