La mia architettura ha un problema con le viste che richiedevano informazioni da oggetti diversi. Come posso risolvere questo?

4

Sto costruendo un'architettura come questa: Questi sono i miei layer SW

 ______________
|              |
|    Views     |
|______________|

 ______________
|              |
|Business Logic|
|______________|

 ______________
|              |
|  Repository  |
|______________|

Le mie visualizzazioni genereranno il mio codice HTML da inviare all'utente La logica aziendale è dove sono tutte le logiche di business Il repository è un livello per accedere al DB

La mia idea è che il repository utilizzi entità (che sono fondamentalmente la rappresentazione delle tabelle, al fine di eseguire query DB.

Gli strati comunicano tra loro usando Business Objects, ovvero oggetti che rappresentano l'oggetto del mondo reale stesso. Possono contenere regole e metodi aziendali.

Le viste creano / usano DTO, sono fondamentalmente oggetti che hanno le informazioni richieste per essere mostrate sullo schermo. Si aspettano anche questo tipo di oggetto sulle azioni e, prima di chiamare la logica aziendale, creano BO.

Prima domanda: qual è la tua opinione generale su questa architettura?

Ho usato un'architettura simile per alcuni progetti e ho sempre avuto questo problema: Se la mia vista ha questo elenco da mostrare:

Student1, age, course, Date Enrolled, Already paid?

Ha informazioni da diversi BO. Come pensi che si dovrebbe costruire la struttura?

Queste erano le alternative a cui potevo pensare:

  • Il livello di visualizzazione può chiamare i metodi per ottenere lo studente, quindi il corso che studia, quindi le informazioni di pagamento . Ciò causerebbe molti accessi al DB e la mia vista avrebbe la conoscenza su come agire per generare queste informazioni. Questo mi sembra sbagliato.
  • Potrei avere un "oggetto adattatore", che ha le informazioni richieste (una classe che avrebbe una proprietà Studente, Corso e Pagamento). Ma avrei richiesto un oggetto adattatore per ogni caso simile, questo potrebbe andare molto male per i grandi progetti.

Ancora non mi piacciono. Avresti idee? Come cambieresti l'architettura per evitare questo tipo di problemi?

@Rory: Ho letto il CQRS e non penso che questo sia adatto alle mie esigenze. Come preso da riferimenti di link nel tuo link

Before describing the details of CQRS we need to understand the two main driving forces behind it: collaboration and staleness

Ciò significa: molti attori diversi che usano lo stesso oggetto (collaborazione) e una volta che i dati sono stati mostrati a un utente, gli stessi dati potrebbero essere stati cambiati da un altro attore - è stantio (stoltezza).

Il mio problema è che voglio mostrare le informazioni dell'utente da diversi BO, quindi avrei bisogno di riceverle dal livello di servizio. Come può il mio livello di servizio assemblare e fornire queste informazioni?

Modifica in @AndrewM: Sì, l'hai capito bene, l'idea originale era di avere il livello di visualizzazione per costruire i BO, ma hai un punto molto bello riguardo la creazione del BO all'interno dei livelli aziendali. Supponendo che seguo il tuo consiglio e sposti la logica di creazione all'interno del livello aziendale, la mia interfaccia del livello aziendale conterrebbe i DTO, ad esempio

public void foo(MyDTO object)

Ma per quanto ho capito, il DTO è strettamente accoppiato ad ogni vista, quindi non sarebbe riutilizzabile da una seconda vista. Per poterlo utilizzare, la seconda vista dovrebbe creare un DTO specifico da una vista specifica o dovrei duplicare il codice nel livello aziendale. È corretto o mi manca qualcosa?

    
posta JSBach 27.02.2014 - 17:46
fonte

3 risposte

7

I mappatori relazionali agli oggetti come NHibernate vogliono che tu faccia tutto il tuo trattamento dei dati usando oggetti di business. Tuttavia, come hai riconosciuto, estrai un intero aggregato dal repository è un'operazione costosa quando tutto ciò che vuoi è un aspetto di esso. Perché reidratare un intero Customer , inclusi tutti i relativi Order s e così via - potenzialmente unendo un certo numero di tabelle - quando tutto ciò che devi visualizzare sullo schermo è un FirstName ? I palloncini problema quando hai bisogno di un po 'di informazioni da un sacco di aggregati.

La soluzione è Segregazione di responsabilità di comando / query . (Credo che l'idea sia dovuta a Greg Young.) Una visione individuale ha bisogno di un insieme molto specifico di informazioni che un ORM può lottare per fornire in modo efficiente. Quindi, perché non scrivere query specifiche della vista che ignorano l'ORM, utilizzando un linguaggio progettato per l'interrogazione efficiente ed espressiva? (È possibile utilizzare SQL diretto, stored procedure, LINQ-to-SQL , HQL , o qualche altra lingua dichiarativa.) Questo In questo modo, puoi ottimizzare le tue query ai nini quando necessario, dopotutto, leggere i dati è molto più comune della scrittura dei dati.

In un'architettura CQRS, il modello di dominio (e NHibernate) esiste solo per facilitare scrivere . Il suo intero compito è proteggere gli invarianti di business e mantenere il database in uno stato coerente. La lettura dal database viene gestita in una parte completamente separata della tua applicazione, nota come Thin Read Layer, che non utilizza affatto il modello di dominio.

In genere, nel tuo livello di lettura sottile, avrai una query specializzata per visualizzazione. Questo può sembrare uno spreco ma come dicono Kent Beck e Martin Fowler , " Pensiamo che il riutilizzo sia sopravvalutato (lo usiamo solo). " Il sottile strato di lettura è sottile: estrae solo un set specifico di dati dal DB il più velocemente possibile. Quindi le query sono facili da scrivere, il che a sua volta le rende economiche da buttare via quando cambia la vista.

Quando prendi sul serio l'ottimizzazione della tua applicazione per la lettura, puoi realizzare che lo schema del tuo database ti trattiene e devi eseguire alcuni denormalizzazione . Tuttavia, la denormalizzazione può avere l'effetto di rendere le scritture nel database in modo inesplicabilmente complesso, rendendo il tuo modello di dominio lento e più difficile da mantenere. Quindi, alcune persone spostano l'intera query in un database separato! Questo potrebbe assumere la forma di un database SQL ottimizzato per la lettura, ma non è necessario utilizzare SQL: le tue visualizzazioni potrebbero essere più efficienti con qualcosa come Mongo o Lucene.

In questo tipo di sistema, il livello di lettura sottile deve controllare le modifiche nel modello di dominio. In genere, questo viene implementato utilizzando un modello di pubblicazione / sottoscrizione asincrono - il modello di dominio genera eventi a cui il read-side si iscrive per aggiornare la sua cache. Devi impostare il broker dei messaggi per registrare i tuoi eventi, in modo da poter ricostruire sempre le tue proiezioni nel caso qualcosa vada storto o devi creare una nuova istanza.

Questa architettura è facile da distribuire, quando arriva il momento di ingrandire la tua app. Avresti creato un database sul lato scrittura (con un modello di dominio) come "fonte di verità" e molti strati di lettura sottili posti sopra le cache di tutto il mondo.

    
risposta data 02.06.2014 - 23:43
fonte
3

Potrebbe essere utile esaminare il criterio Segregazione di responsabilità della query di comando . In sostanza, si introducono nuovi modelli per abbinare il modo in cui viene utilizzato il sistema. Potresti avere ad es. un modello di registrazione delle iscrizioni per gestire la tua query, mentre usi modelli di studenti, corsi, ecc. per le tue operazioni CRUD di base.

    
risposta data 27.02.2014 - 17:58
fonte
1

Non sono sicuro di seguirlo completamente, fammi vedere se ho questo diritto.

Il View Layer ha componenti che generano DTO per l'interfaccia utente, ma generano BO per chiamare i componenti nel livello aziendale. I componenti nel livello aziendale li consegnano ai componenti nel livello del repository per la memorizzazione / il recupero.

Se questo è il caso, allora non sono davvero sicuro del punto del livello aziendale. È difficile dire le sue responsabilità dalla descrizione. Se i componenti del livello vista sono quelli che creano BO, allora ha una conoscenza abbastanza complessa di quelli.

Potresti voler inserire tutte le costruzioni e la gestione BO in componenti nel livello aziendale. Sembra che il livello aziendale dovrebbe essere l'adattatore. (Questo di solito è ciò che la logica aziendale è per.) Mi aspetterei che i componenti del livello aziendale consumino richieste di dati dai componenti di visualizzazione (ad esempio, ottenere informazioni dallo studente) e creare oggetti completi (studente, età, corso, ecc. ) assemblando i dati dai componenti nel livello repository. Mi aspetterei che il tipo (e le qualità) degli oggetti che fluiscono tra i diversi livelli sia diverso in questo caso.

Puoi spiegare un po 'di più su cosa stai inviando tra i componenti?

    
risposta data 04.03.2014 - 14:03
fonte

Leggi altre domande sui tag