DDD non è appropriato per il mio sito web o dovrei introdurre un livello di query?

6

Ho ereditato un'applicazione del sito Web ASP.NET e lo sviluppatore precedente ha usato quelli che credo siano alcuni concetti DDD. Sono nuovo di DDD e devo ammettere che sto lottando con il lato pratico di esso proveniente da uno sfondo di Transaction Script N-Tier.

Uno dei problemi con il sito è che è lento. Non esiste alcuna impaginazione su griglie enormi e anche il livello della logica di business estrae più dati di quanto sia necessario per il 90% delle operazioni il 70% delle quali viene letto per associare i dati alle griglie.

Il progetto generale prevede che il livello della logica aziendale abbia una classe di servizio per radice aggregata, con vari metodi di tipo "GetByX ()", "FindBestMatching ()" e "Update ()". da cui vengono creati alberi di oggetti di dominio come "Organizzazione" e "Utente".

Nei miei giorni di script di transazione, il mio livello di servizio era simile: ci sarebbe stata probabilmente una logica, una chiamata in un repository (o dall'uso diretto di EF 6 di EF come può essere deriso per il test) e poi la chiamata sarebbe tornato Gli oggetti che sono stati restituiti sarebbero oggetti di tipo DTO contenenti dati di ritorno rilevanti, inclusi eventualmente alcuni oggetti entità POCO. Questi DTO viaggiavano verso i clienti tramite i servizi Web, si collegavano alle griglie ASP.NET o Silverlight ... tutto andava bene.

Le mie operazioni sul mio livello di servizio potrebbero essere molto specifiche, consentendo query come:

"GetUsersWithSurnameIncludeChildren(string surname, int skip, int take)"

che consente di eseguire query DB strette e semplici che supportano il caricamento impaginato e ansioso dei dati correlati. È stato veloce e ha caricato solo i dati effettivamente necessari.

Ora con questo sito che ho ereditato esiste un vero modello OO del dominio aziendale. Queste classi sono POCO, non generate da EF, ma EF viene utilizzato prima come repository (esiste molta mappatura tra gli oggetti dominio e gli oggetti EF). Un oggetto dominio di esempio è sotto (senza alcuna logica).

public class Organisation
{
    public int OrganisationID { get; set; }
    public string Name { get; set; }

    public IList<Organisation> AssociatedOrganisations { get; set; }
    public IList<User> Staff { get; set; }
    public IList<User> Managers { get; set; }

    // Business logic method implemented below here
}

Molte delle classi sono essenzialmente copie degli oggetti del framework entità sottostante, altre hanno una quantità significativa di logica incapsulata al loro interno.

Il modo in cui il sito funziona attualmente è che ogni volta che la classe di servizio OrganisationService crea un nuovo oggetto di dominio Organizzazione (e può creare una raccolta in un colpo) popola anche TUTTI i campi e le raccolte in quell'oggetto ... e tutti i campi e le raccolte in quegli oggetti! Un enorme albero profondo viene creato in memoria e una pila di join e unioni (generate da EF) è necessaria per ottenere tutti i dati. Questo è totalmente inappropriato per un sito web che visualizza principalmente un sacco di griglie piatte.

Le mie domande sono:

1) Un'applicazione che esegue il 70% di estrazione dei dati da un DB per la visualizzazione e una logica di business del 30% è in realtà un cattivo candidato per il DDD?

2) Se il DDD è appropriato, come sono generalmente progettati scenari come questo? Dovrei implementare un "servizio di query" separato progettato per estrarre un sacco di dati flat per il binding a pagine e griglie (questi potrebbero essere solo gli EF POCOS) e riservare gli oggetti Dominio solo per parti dell'applicazione in cui la logica deve effettivamente eseguito?

3) Devo caricare solo i dati nei miei tipi di riferimento e insiemi di oggetti di dominio quando è effettivamente accessibile (come EF lazy loading ...)? I post precedenti che ho letto hanno suggerito che il caricamento lazy in un oggetto dominio è un odore di codice: DDD Lazy Loading Code Smell

Sto per comprare un libro DDD stasera:)

    
posta MrLane 05.09.2014 - 10:02
fonte

4 risposte

4

Dopo aver letto il libro di Evans, vedrai che DDD è una raccolta di concetti. Il libro è stato scritto oltre un decennio fa. La mia opinione oggi è che ha parti buone, ma è facilmente frainteso e talvolta usato impropriamente. In realtà, alcune parti potrebbero non essere necessarie o potrebbero non essere adatte alla tua applicazione o agli strumenti scelti.

Per quanto riguarda EF, non penso che il concetto DDD di combinare dati e comportamenti nelle tue entità si fonda bene con esso. I modelli di entità EF devono essere privi di comportamento se si desidera evitare un sacco di errori imprevisti e colli di bottiglia nelle prestazioni. Come indicato in altre risposte, usare un pattern CQ (R) S è un buon modo per implementare il comportamento esternamente dalle entità EF. In conclusione, cerca di evitare di implementare un "modello di dominio ricco" usando metodi su entità EF. Puoi ancora scricchiolare la conoscenza del business in "il modello", ma il tuo "modello" dovrebbe contenere classi diverse per dati (entità) e comportamento (operazioni).

Inoltre non mi piace l'idea di repository, ma questa è principalmente la mia opinione e sono sicuro che gli altri non saranno d'accordo quando dico che non sono davvero necessari quando si utilizza un ORM come EF. Forse un decennio fa, prima che avessimo i generici moderni, erano più utili. In questi giorni, puoi racchiudere una singola interfaccia generica attorno a un DbContext EF e disporre di un singolo repository generico (insieme all'unità di lavoro).

D'altra parte, cose come la lingua onnipresente, le radici aggregate, i contesti limitati, i criteri di query, ecc. Io considero le perle. Mantenere il livello dell'applicazione sottile è anche una buona pratica senza tempo. Sembra che l'altro sviluppatore potrebbe non aver applicato i concetti DDD appropriati e, come già detto da qualcun altro, ha creato più problemi di quanti ne abbiano risolti.

    
risposta data 05.01.2015 - 08:20
fonte
1

1) Non lo direi. Il DDD è utile per i sistemi complessi (il che può significare qualcosa di più sofisticato del CRUD). La logica del dominio può essere molto complessa indipendentemente dalla sua condivisione nel sistema rispetto alla logica della query.

2) Vedo due modi per affrontare questo. Uno è limite di dimensioni aggregate. I piccoli aggregati sono meno inclini a un carico di dati eccessivo e lento. L'altro è separato le tue letture dalle tue scritture (CQRS). Questo è fondamentalmente il "Servizio di query" che stai citando, ma è meglio che restituisca oggetti modello letti separati che non siano le tue entità.

3) Chiamando l'entità pigra che carica un codice l'odore è in qualche modo ... supponente. Potrebbe effettivamente essere una soluzione. Tuttavia, potresti avere ancora problemi di prestazioni, come aggiungere un'entità a un'enorme raccolta che ti obbliga a caricare l'intera raccolta. Un design di aggregazione migliore può risolverlo.

    
risposta data 05.09.2014 - 11:05
fonte
1

Ho costruito diversi modelli DDD, la persistenza è stata gestita da NHibernate. Siamo andati con uno schema di deposito nei nostri primi progetti e abbiamo costruito tutte le nostre query nei nostri repository.

Questa è una grande idea in teoria, ma quello che abbiamo imparato in pratica è che si finisce per scrivere un sacco di posti nella caldaia quando si implementano i repository ed inoltre erano praticamente inutili comunque. Oltre al metodo standard save, delete e FindByID, tutte le query effettive che vengono utilizzate sono quasi sempre univoche per un particolare caso d'uso, specialmente quando si prendono in considerazione le proprietà che si desidera caricare.

Quindi utilizziamo ancora un modello di repository ma abbiamo solo metodi save, delete, findByID e findByQuery. La query è incapsulata in un oggetto e passata nel repository, l'oggetto query è costruito nel livello applicazione.

    
risposta data 06.10.2014 - 17:10
fonte
0

Se il codice è ciò con cui stai lottando, trova la ragione per cui è lì. Se non ci sono ragioni valide per essere trovato, sbarazzarsi del codice e scrivere il codice che ha un motivo per essere lì. La tua domanda sta mostrando un elenco di problemi autoinflitti causati dall'uso di un pattern che potrebbe aver risolto un paio di problemi, ma ha introdotto molto di più, molti dei quali tecnici.

Consentitemi di fare riferimento alla mia risposta su SO se DDD sia o meno una perdita di tempo: link

Questo potrebbe darti un po 'di prospettiva su cosa sia il DDD e cosa non lo sia. Il TL; DR è che non è una soluzione tecnica ma potrebbe (non sarebbe!) Finire in una soluzione tecnica di qualche tipo, ma non è necessario.

L'estenuante recupero del grafico potrebbe suggerire un problema di SELECT N + 1 attraverso il caricamento lazy o i loop che prelevano il codice degli elementi correlati. Questo potrebbe essere fatto per essere in grado di produrre una proiezione sui dati in memoria. Tuttavia, osservando lo snippet di classe, non vedo un'influenza DDD profonda lì, poiché altrimenti le collezioni non sarebbero state lì.

Potrebbe essere saggio vedere se è effettivamente necessario recuperare istanze di entità in un grafico, poiché potrebbe essere più rapido formulare la proiezione dei dati necessari come query di linq sulle entità nel modello e lasciare che DB fa la produzione stabilita. Il set di risultati può quindi essere recuperato in nuovi oggetti POCO, che sono semplicemente elenchi semplici e vengono quindi utilizzati nell'interfaccia utente. Ovviamente si tratta di dati letti / solo, ma per molti casi questo è sufficiente.

    
risposta data 06.09.2014 - 14:59
fonte