Modelli di dominio DDD e business logic

6

Sono un programmatore esperto ma un debuttante con DDD. Ho un progetto che sto cercando di implementare con DDD e la mia comprensione è che c'è qualche ambiguità riguardo all'uso di modelli di dominio e servizi applicativi. Nella più pura delle implementazioni DDD, la mia comprensione è che i modelli di dominio dovrebbero contenere tutte le logiche di business. Tuttavia, questo non mi sembra un obiettivo realistico. In scenari di convalida semplici e simili, tutto va bene, ma l'obiettivo dell'incapsulamento della logica aziendale nei modelli di dominio diventa un po 'scivoloso quando pensiamo alla logica che richiede servizi aggiuntivi come ricerche / persistenza del database e altre dipendenze esterne.

Ad esempio, ho un modello di dominio "Ordine" che ha un metodo "IsValid". Per determinare se un ordine è valido, è necessario eseguire una lettura del database. Per mantenere pulito il modello, non voglio inserire alcun lavoro di database in esso. OK bene - Creo un OrderService per fare il colpo al database e passare un risultato a "IsValid" in modo che la dipendenza dal database risieda con il servizio. Tuttavia, cosa succede se ci sono più accessi al database che dipendono dalla logica aziendale? È appropriato aggiungere questa logica al servizio dell'applicazione? Se è così, sembra che la logica aziendale stia perdendo nel livello dei servizi applicativi che è una violazione del DDD. Tuttavia, se spostiamo la logica all'interno del modello di dominio e facciamo il database colpito lì, stiamo mescolando preoccupazioni e anche violando DDD.

Chiunque abbia esperienza con DDD può fornire informazioni su come affrontare questo tipo di problema? DDD sembra offrire un buon valore, ma sono preoccupato per questo tipo di problemi che portano alla progettazione di "rot".

    
posta Andy 24.03.2017 - 18:58
fonte

3 risposte

2

Non posso darti una risposta concreta. Ma posso darti due cose da considerare:

In primo luogo , un dominio che "conosce" la persistenza, almeno in un senso vago, non è necessariamente negativo.

Se le entità di dominio sono in gran parte uno a uno con le tue tabelle di database, potresti seguire un record attivo modello. E va bene. È semplice, e fatto bene - pochissime righe di codice. (Entrambi molto buoni per la manutenzione!)

Se utilizzi un modello di repository , che è tipico di DDD, è ancora possibile che il dominio funzioni con repository. idealmente vuoi inserire quei repository nel dominio. (Potrei obiettare che individuare repo è anche OK.)

Un Order nel tuo dominio può essere costruito con ILineItemRepo e invoca repo.GetByOrder(this) - e va bene. Potrebbe anche essere necessario sapere, come hai suggerito, che è own repository per applicare determinati vincoli.

Perfettamente bene.

Questo non è affatto incompatibile con un livello di configurazione che decide come vengono gestiti i repository. Anche il pattern Active Record permette questo, se fatto bene. Il tuo dominio può sapere che sta tirando oggetti dentro e fuori da qualcosa - di solito non dovrebbe sapere esattamente qual è quel qualcosa. 1

In secondo luogo, il dominio deve solo conoscere le regole di business "core".

In altre parole, il dominio contiene idealmente tutte le regole e solo quelle regole applicabili a qualsiasi applicazione che utilizza tali entità nella tua attività.

Puoi sicuramente allungarlo per soddisfare le esigenze della tua squadra, perché la tua piccola libreria di dominio probabilmente non è utilizzata in tutta l'organizzazione. Ma, ho trovato che sia un buon principio guida, specialmente quando altri gruppi della tua organizzazione richiedono gli endpoint nella tua applicazione.

Ogni client (e endpoint) può avere determinate regole o passaggi speciali che devono essere eseguiti. Tuttavia, solo quelle regole applicabili a tutti i possibili "client" o "applicazioni" appartengono al tuo dominio.

Tutto ciò che sembra applicarsi al servizio di un singolo cliente o "applicazione" appartiene al servizio o all'applicazione di quel particolare cliente 2 ...

1. A meno che il tuo software di base, e quindi il tuo dominio, sia esattamente su che gestisce la persistenza! Avresti difficoltà a scrivere il livello del dominio per un file system che non conosce i file!

2. Anche se non sta necessariamente parlando di DDD, Lo zio Bob mi fa un sacco di cose / a>. (E, per lo più, sono d'accordo con lui su questo punto.)

    
risposta data 24.03.2017 - 20:54
fonte
1

For example, I have a domain model "Order" that has a method "IsValid". To determine whether an order is valid, a database read must be performed.

Questo non è quasi certamente giusto; in quanto stai tirando in ballo ipotesi su dove i dati sono archiviati nel tuo modello di dominio.

Un'ortografia più ragionevole sarebbe qualcosa come "un ordine è valido se l'ordine totale è inferiore a $ 100 o se ha una firma di approvazione a livello C". Nel codice del modello di dominio, avresti accesso a questo stato e implementeresti la logica booleana, controllando le copie locali dello stato.

Normalmente il flusso dovrebbe assomigliare: la query arriva, l'applicazione legge la query per capire quale ordine è stato chiesto, l'OrderRepository verrebbe interrogato per lo stato dell'ordine specifico; lo stato dell'ordine verrebbe utilizzato per ricostituire il modello Ordine e quindi la query verrebbe eseguita sul modello per ottenere il risultato.

Un design in cui il risultato finale è la ricerca di dati di modello frammentari che hanno perso la trama. Carichi l'intero modello (in questo caso, l'intero ordine), quindi esegui la query sul modello.

Può essere utile pensare a scrivere test per il modello; dovresti essere in grado di farlo senza coinvolgere il componente di persistenza, semplicemente lavorando con copie in memoria dello stato del modello.

So one problem I've seen here is that some team members have injected an EF DbContext instance into a domain model

Sì, la letteratura è piuttosto carente nel comprendere le relazioni tra il modello, i repository e il sottostante negozio durevole. Il codice dominio dovrebbe essere completamente ignorante per la persistenza, ma sono necessari alcuni punti per ottenere lo stato corrente nel modello e nei casi di utilizzo in cui cambiamo il modello, riportando lo stato modificato nuovamente fuori dal modello.

    
risposta data 24.03.2017 - 19:58
fonte
1

Questa è una domanda molto ampia, ma cercherò di darti una risposta.

...there is some ambiguity with regard to the use of domain models and application services

Non c'è alcuna ambiguità se si progettano bene i contesti limitati, i modelli di dominio e le relazioni tra loro.

However, what happens if there are multiple database hits that depend on business logic?

In DDD , tutte le operazioni passano attraverso Aggregate root ( AR ). Il application services carica ARs dalla persistenza, invia loro comandi, quindi ripristina quelli ARs indietro. ARs non ha bisogno di colpire il database. In effetti un buon% di designato% di co_de non sa nemmeno che i database esistono affatto. Tutto ciò che toccano / vedi / odori è il loro stato interno e gli immutabili argomenti che ricevono nei loro metodi di comando. Se una AR ha bisogno di qualcosa dal database, allora AR passa quella cosa come argomento.

Application service dovrebbe essere puro, gli effetti collaterali liberano oggetti / funzioni. Una ragione è che i comandi applicati su di essi devono essere riprogrammabili, in caso di modifiche simultanee.

Come esempio: ARs non invia email, restituiscono una ARs che contiene i dati dell'email (da, a, oggetto e corpo) e il servizio Applicazione prende quell'oggetto valore e lo passa a un'infrastruttura servizio che fa l'effettivo invio dell'e-mail.

For example, I have a domain model "Order" that has a method "IsValid". To determine whether an order is valid, a database read must be performed.

Non è necessario un metodo value object , in quanto isValid non può entrare in uno stato non valido in ogni caso perché le modifiche vengono eseguite tramite i suoi metodi. Se ti riferisci all'esistenza di un Order allora questo tipo di convalida viene eseguito da Order : se non trova il Application service nella persistenza, allora non esiste, così semplice. Forse ti stai riferendo a Order come valido, non a ShoppingCart . E allora? Bene, potresti provare a creare un Order da Order e se hai successo allora un ShoppingCart è pronto per essere ordinato. Poiché Cart è privo di effetti collaterali, non verrà creato alcun ordine. Solo un esempio di come potresti pensare in Order .

DDD seems like it provides a lot of nice value, but I'm worried about these kinds of issues leading to design "rot".

Se segui bene l'approccio DDD , il tuo design non marcirà mai. Mai .

Come nota del piede: all'inizio ero un po 'trascurato dall'architettura Layered . Non commettere lo stesso errore. Dai un'occhiata ad alcune nuove architetture come DDD che si adatta molto bene con CQRS .

    
risposta data 24.03.2017 - 20:06
fonte

Leggi altre domande sui tag