Valori calcolati e letture semplici - Un fastidioso dolore per i miei disegni basati su domini!

9

Il problema che affronto continuamente è come gestire i valori calcolati guidati dalla logica del dominio mentre si sta ancora lavorando efficientemente contro l'archivio dati.

Esempio:

Sto restituendo un elenco di prodotti dal mio repository tramite un servizio. Questo elenco è limitato dalle informazioni sulla paginazione dalla richiesta DTO inviata dal cliente. Inoltre, il DTO specifica un parametro sort (un enum client-friendly).

In uno scenario semplice, tutto funziona alla grande: il servizio invia le espressioni di paging e di ordinamento al repository e il repository invia una query efficiente al DB.

Tutto ciò non funziona, tuttavia, quando devo ordinare i valori generati in memoria dal mio modello di dominio. Ad esempio, la classe Product ha un metodo IsExpired () che restituisce un valore bool in base alla business logic. Ora non riesco a ordinare e pagina a livello di repository - tutto sarebbe stato fatto in memoria (inefficiente) e il mio servizio avrebbe dovuto conoscere la complessità di quando inviare questi parametri al repository e quando eseguire l'ordinamento / il paging stesso.

L'unico schema che sembra avere senso per me è quello di memorizzare lo stato dell'entità nel db (rendere IsExpired () un campo readonly e aggiornarlo tramite la logica del dominio prima di salvare). Se separo questa logica in un repository separato "read model / dto" e "reporting", sto rendendo il mio modello più anemico di quanto mi piacerebbe.

A proposito, ogni esempio che ho visto là fuori per calcoli come questo sembra poggiare sull'elaborazione in memoria e sul fatto che è molto meno efficiente a lungo termine. Forse sto ottimizzando prematuramente, ma questo non mi sta proprio bene.

Mi piacerebbe sapere come gli altri hanno affrontato questo problema, sono sicuro che è comune su quasi un progetto che riguarda il DDD.

    
posta drogon 04.02.2012 - 02:10
fonte

3 risposte

3

Non penso che avere due diversi modelli di dominio dello stesso modello di dati renda il tuo dominio anemico. Un modello di dominio anemico è quello in cui la logica aziendale che cambia spesso è nascosta dal dominio in un livello di servizio (o, peggio, nel livello dell'interfaccia utente).

La separazione dei modelli di dominio di comando e query è spesso condivisa e ha un bel acronimo che puoi usare su Google in CQRS (Comando di segregazione delle query).

Utilizzo del modello del modello di dominio, Udi Dahan

While I was "successful" in the past in creating a single persistent object model that handled both commands and queries, it was often very difficult to scale it, as each part of the system tugged the model in a different direction.

It turns out that developers often take on more strenuous requirements than the business actually needs. The decision to use the domain model entities for showing information to the user is just such an example.

[...]

For those old enough to remember, the best practices around using COM+ guided us to create separate components for read-only and for read-write logic. Here we are, a decade later, with new technologies like the Entity Framework, yet those same principles continue to hold.

CQRS con attori Akka e modelli di dominio funzionali, Debasish Ghosh

Greg Young has delivered some great sessions on DDD and CQRS. In 2008 he said "A single model cannot be appropriate for reporting, searching and transactional behavior". We have at least two models - one that processes commands and feeds changes to another model which serves user queries and reports. The transactional behavior of the application gets executed through the rich domain model of aggregates and repositories, while the queries are directly served from a de-normalized data model.

CQRS, Martin Fowler

The change that CQRS introduces is to split that conceptual model into separate models for update and display, which it refers to as Command and Query respectively following the vocabulary of CommandQuerySeparation. The rationale is that for many problems, particularly in more complicated domains, having the same conceptual model for commands and queries leads to a more complex model that does neither well.

In breve, la tua idea di avere il modello di comando gestire la scadenza e passarla al database è assolutamente soddisfacente. Leggi il primo articolo sopra e vedrai scenari simili ma più complessi.

    
risposta data 04.02.2012 - 04:49
fonte
2

SPECIFICHE

So che hai già accettato una risposta, ma hai chiesto informazioni su DDD e la corrispondenza esatta per questo è ciò che Evans chiama una "specifica":
link diretto a google books
Se quel link non funziona controlla il libro in questi risultati
È la pagina 226 se hai il libro.

Nella pagina 227 ci sono 3 usi per le specifiche: convalida, selezione, costruzione di un nuovo oggetto speciale. La tua è 'selezione' - IsExpired.

Un'altra cosa sul concetto di "specificheiton" è che ammette che, per ragioni di efficienza, potrebbe essere necessaria una versione di codice per operare sugli oggetti in memoria e un'altra versione del codice per interrogare in modo efficiente il repository senza avere per prima cosa prendi tutti gli oggetti in memoria.

In un mondo semplice, ciò significherebbe inserire una versione SQL nel repository e una versione di oggetti nel modello, ovviamente che presenta degli svantaggi. La logica è in 2 punti (male, qualcuno si dimenticherà di aggiornare su quei posti) e c'è la logica di dominio nel tuo repository.

Quindi la risposta è mettere entrambi i gruppi di logica in una specifica. La versione in-memory, ovviamente, ma anche una versione di repository. Se si utilizza ad esempio n-hibernate, è possibile utilizzare il relativo linguaggio di query incorporato per la versione del repository.

Altrimenti dovrai creare un metodo di repository speciale per questa specifica che viene utilizzata dall'oggetto della specifica. Le richieste di collecitons di oggetti corrispondenti alle specifiche passano attraverso le specifiche, non il repository. E almeno il codice urla "Sono in 2 posti, non dimenticarlo" ai futuri manutentori. C'è un meraviglioso esempio a pagina 231-232 per risolvere problemi molto simili.

La specifica è una perdita "permessa" / lo slittamento della "purezza" del DDD. Potrebbe ancora non soddisfare le tue esigenze per una varietà di scopi. Ad esempio, l'ORM potrebbe generare errori di SQL; potrebbe esserci troppa codifica in più. Quindi potresti dover chiamare i metodi di repository in modo tale che è quasi come mettere SQL nelle specifiche. Una brutta cosa, ovviamente. Ma non dimenticare, il tuo programma deve funzionare a una velocità ragionevole. Non deve vincere un premio di purezza DDD. Quindi una realtà di commutazione dei datastore potrebbe significare un intervento chirurgico vecchio stile in tutto il programma. Anche una brutta cosa. Ma non così male come un programma lento (aka SUCKing). Se in esecuzione fuori dalla scatola su vari DB è una realtà, ovviamente, duplicherete le regole di business per ciascun datastore per ogni specifica. Almeno hai il dito sulla questione e puoi sfruttare il modello di strategia quando scambi i repository. Ma se stai utilizzando un DB specifico, ricorda già YAGNI.

Per quanto riguarda CQRS: la citazione di Fowler di pdr sopra vale ancora qui: "avere lo stesso modello concettuale per comandi e query porta a un modello più complesso che non funziona bene" ... e potresti necessità di utilizzare CQRS o simili. Ma è molto più costoso dal punto di vista dello sviluppo e della manutenzione. Se sei un venditore di pacchi in concorrenza con altri, potrebbe pagare. Se stai scrivendo un'app LOB personalizzata per un cliente, le riprese per la perfezione sono una scelta sbagliata. Devi decidere se il valore di avere un modello completamente o per lo più doppio vale lo sforzo extra. Specifica è un buon compromesso perché ti permette di fare questa separazione in una piccola parte del programma che ne ha bisogno, con la velocità (di sviluppo) e la semplicità di un modello. Buona fortuna!

    
risposta data 06.02.2012 - 17:01
fonte
0

Credo che metterei in discussione la logica aziendale che determina se isExpired sia vero o no. Questa logica può essere eseguita da una query mentre il modello di dati è valido? In tal caso, puoi rendere il tuo repository abbastanza intelligente da utilizzare la logica "isExpired" quando lo chiedi per Prodotti in un certo modo? In caso contrario, forse è necessario riesaminare il modello di dati.

DDD non significa che i tuoi repository debbano essere stupidi - significa semplicemente che il tuo dominio ha bisogno di sapere come parlare ai tuoi repository.

    
risposta data 04.02.2012 - 05:15
fonte

Leggi altre domande sui tag