Possono esserci più aggregati per lo stesso concetto?

4

Dire che ho il concetto di un utente; una struttura molto semplice nella realtà. Se l'azienda richiede che un aspetto del software debba visualizzare tutti i "Post" correlati, ad esempio, come dovrebbe essere modellato?

  1. Dovrebbero esserci post come attributo sull'entità Utente, il che significa che ogni volta che un utente è richiesto semplicemente per verificare un accesso per esempio, tutti i suoi post devono essere caricati?
  2. Dovrebbe essere utilizzato un aggregato separato. Come dovrebbe essere chiamato questo aggregato? UserWithPosts? Cosa succede se ci sono più attributi per i dati correlati?
  3. La radice aggregata dovrebbe essere un utente di interfaccia, con una semplice entità chiamata LoginUser e decoratori per funzionalità extra, come UserWithPosts, UserWithComments ecc?

Non riesco a capire quale sarebbe l'approccio migliore per evitare lo scenario 1.

    
posta designermonkey 28.07.2017 - 16:05
fonte

3 risposte

3

Ci sono due parti per questo.

Per i casi d'uso che non modificano i dati, non è necessario caricare l'intero aggregato in memoria. Quindi potresti utilizzare una vista di sola lettura dell'Utente per effettuare il login e una diversa visualizzazione di sola lettura per mostrare i Post.

Ciò che dovrebbe apparire è a diversi metodi sul repository, ognuno dei quali restituisce una vista di sola lettura che è adatta allo scopo.

Utilizzare i casi in cui modificare un aggregato ha bisogno di tutto lo stato richiesto per mantenere l'invariante; ma i casi d'uso per visualizzare un aggregato non lo fanno.

Non lo troverai descritto nel libro di Evans - è una tecnica che è diventata più popolare da allora.

La seconda parte di questa è la domanda di modellazione - sono la raccolta di Post associati a un Utente o sono un aggregato a se stessi? Questo dipenderà davvero dall'invariant che stai cercando di mantenere.

È normalmente accettabile avere relazioni tra aggregati, in cui lo stato di un aggregato include l'identificativo di un altro aggregato.

    
risposta data 28.07.2017 - 18:30
fonte
3

Sembra esserci una confusione tra concetti di progettazione guidati dal dominio, progettazione dell'API e approccio di implementazione.

Concetti di progettazione del dominio

Prima alcune definizioni del libro di riferimento DDD di Evan:

  • Aggregate: A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the aggregate, designated as the root.

  • Entity: An object fundamentally defined not by its attributes, but by a thread of continuity and identity.

E tieni presente che si tratta del dominio. Non ci interessa qui come saranno implementate le relazioni tra gli oggetti. Pertanto, da quello che dici:

  • User e relativo Posts appartengono allo stesso aggregato e User è l'entità radice di esso. Questo dice che ogni volta che voglio fare riferimento a Post , comunque è implementato, devo accedervi tramite User .
  • non è chiaro se Post all'interno dell'aggregato sia una entità o un oggetto valore . La differenza riguarda la semantica dell'identità: un post che viene aggiornato (ad esempio la correzione di un errore di battitura) è ancora lo stesso post o sarebbe considerato come un altro post? Personalmente opterei per l'entità, ma fino a te per vedere cosa si adatta meglio al tuo dominio.

Progettazione e ampli API modello di implementazione

Il modello di dominio è indipendente da qualsiasi implementazione specifica. Ma per implementarlo, devi definire:

  • Un'API, che definisce in che modo il dominio viene esposto ai livelli dell'applicazione che utilizzano il modello (ad esempio controller e viste).
  • Un approccio di implementazione per la gestione degli interni dipendenti dall'implementazione del modello, ad esempio per garantire la persistenza (ad esempio l'uso di una mappatura Object-Relational o l'uso di un database NOSQL).

Il modello di dominio non deve essere una prigione che ti impone di fare ciecamente cose che ostacolano le prestazioni, ma una guida per strutturare meglio il tuo software.

Nel tuo caso specifico, potresti ad esempio utilizzare caricamento lento : la tua API potrebbe dare l'impressione che tutto sia caricato contemporaneamente con User , ma in realtà, posts non verrà caricato fino a quando qualcuno non tenterà di accedervi tramite User (grazie all'incapsulamento).

Ma potresti anche definire un'API che sembra dare accesso diretto alle entità nell'aggregato, ma che impone l'accesso a Post per passare a User , in modo da avere l'opportunità di salvaguardare la coerenza di gli oggetti correlati.

Potresti anche, come suggerisci tu stesso, creare diversi tipi di oggetti User nell'applicazione per determinare cosa deve essere caricato e cosa potrebbe essere modificato. Ma poi è un modello di implementazione e non più il modello di dominio concettuale più.

    
risposta data 07.08.2017 - 01:09
fonte
1

Per (1), direi in nessun modo! Non si desidera leggere un gruppo di oggetti del database ogni volta che si recupera un utente, soprattutto considerando che non sempre sono necessari gli altri oggetti del database. Il modo (1) è la causa principale di molti problemi di prestazioni. La mia comprensione è che Hibernate rende fin troppo facile scegliere la modalità (1), e questo è uno dei motivi per cui preferisco scrivere manualmente le query SQL.

Il mio approccio è (2). Creo diverse "viste" immutabili (non viste del database!) Sullo stesso oggetto di base. Ci possono essere fino a 3-5 viste che uniscono la tabella del database di base a diverse altre tabelle. Questi oggetti vista non sono mai modificati; tutte le modifiche al database passano tramite l'oggetto di base.

Di solito cerco di mantenere tutta la logica nell'applicazione stessa, quindi anche se ho queste viste a livello di applicazione, non utilizzo mai il comando SQL CREATE VIEW . Francamente, non vedo lo scopo delle visualizzazioni a livello di database. Fanno qualcosa che dovrebbe essere fatto nell'applicazione.

Se il linguaggio di programmazione che usi è Java, potresti avere una classe User e una classe interna User.WithPosts . Le classi interne sono così banali che ha senso averle come classi interne, e rende anche facile trovare dove sono le viste rilevanti, se si segue l'abitudine di renderle classi interne. Rendo queste classi interne static così puoi avere User.WithPosts senza User .

    
risposta data 28.07.2017 - 16:53
fonte

Leggi altre domande sui tag