Design basato sul dominio, due aggregati possono avere la stessa radice?

4

Allo scopo di separare funzionalità diverse in classi diverse, ho due seguenti aggregati:

  1. ActiveEmployee

    • AssignTask ()
    • ReassignManager ()
    • Disattiva (motivo stringa)
  2. InactiveEmployee

    • GetReasonForDeactivation ()
    • Reinstate ()

Entrambi gli aggregati condividono la stessa radice, dbo.Employee.

Server EmployeeID come chiave primaria per entrambi Aggregati.

Il repository crea un'istanza del primo o il secondo basato su un flag booleano dbo.Employee.IsActive.

Poiché seguo la regola secondo cui solo un aggregato può essere modificato in una transazione, non troverò mai una situazione in cui carico entrambi gli aggregati con lo stesso ID, finendo con InactiveEmployee con ID 3 e ActiveEmployee con ID 3 nella stessa transazione.

Questo buon DDD? DDD consente di avere due aggregati con la stessa radice? Possiamo differenziare i tipi di aggregati in base a un flag?

UPDATE 1:

Quando ho detto che entrambi gli aggregati condividono la stessa radice, volevo dire che entrambi gli aggregati rappresentano una riga nella tabella dbo.Employee.

A mio avviso, una radice di Aggregate è l'entità definita in modo univoco nel nostro dominio. Ciò non significa che quell'entità debba esistere come una vera classe, l'identità è ciò che conta. Ogni altro aggregato che vuole fare riferimento a Inactive / ActiveEmployee conserverà un riferimento a EmployeeID, non il riferimento all'istanza dell'oggetto.

    
posta omittones 23.05.2015 - 16:56
fonte

3 risposte

9

Devi capire che DDD non tratta di chiavi, righe o tabelle primarie - questi sono solo mezzi per implementarlo.

La radice aggregata viene in genere implementata come classe, poiché è necessario accedere a tutte le funzionalità e i dati dell'aggregazione tramite la radice. Deve quindi avere un comportamento, qualcosa che la chiave primaria della tabella non può avere. Il vantaggio principale di questo è l'incapsulamento degli aggregati - la sua logica è completamente contenuta all'interno dell'aggregato e non perde all'esterno, il che riduce notevolmente l'accoppiamento (e di conseguenza la complessità) dell'applicazione.

Ne consegue che ogni aggregato ha la propria radice aggregata, quindi due aggregati non possono avere la stessa radice (se hanno, c'è effettivamente solo un aggregato).

Nel tuo caso, probabilmente vuoi avere due aggregati indipendenti (ActiveEmployee, InactiveEmployee) che sono supportati dalla stessa tabella (che va bene perché è totalmente fuori dall'ambito di DDD). Ma ricorda che in realtà non esiste un'entità dbo.Employee nel tuo modello di dominio, è solo una tabella su un livello inferiore (persistence).

    
risposta data 24.05.2015 - 15:30
fonte
3

Se Employee è una radice aggregata, significa che tutti gli oggetti esterni possono fare riferimento solo a Employee (e non a ActiveEmployee / InactiveEmployee ).

Any references from outside the aggregate should only go to the aggregate root. DDD aggregate by Martin Fowler

Non penso che sia il tuo intento.
Penso che ActiveEmployee e InactiveEmployee siano entrambi radici aggregate indipendenti nell'esempio.
Questi due sono completamente diversi. Espongono diverse API e richiedono una gestione diversa. Condividono alcune informazioni (tabella dei dipendenti), ma a parte questo non hanno alcuna interazione reciproca. Non possono sostituirsi a vicenda e le loro API non possono essere invocate senza prima controllare lo stato del dipendente

Questa situazione assomiglia molto alla violazione del principio di sostituzione di Liskov a me.

    
risposta data 24.05.2015 - 05:07
fonte
1

Quindi, penso che ciò che l'OP ha fatto è creare 2 Roots aggregati chiamati ActiveCustomer e InactiveCustomer, e in quelli ha aggiunto una proprietà di tipo Customer. Questa è un'entità, che rappresenta un Cliente nel suo sistema.

Questo è il posto dove penso che sia sorta la confusione / problema. In effetti questo ha reso l'aggregato root un wrapper attorno all'entità, ma dovrebbe essere molto di più.

Devi smettere di pensare al database, alle tabelle, qualsiasi cosa abbia a che fare con la persistenza. Quella roba non esiste nel tuo dominio. Invece, basta vedere ActiveCustomer e InactiveCustomer. Possono avere molte delle stesse proprietà, ma hanno un comportamento diverso. Quindi costruisci quel comportamento.

Per quanto riguarda la persistenza, quello che faccio è un progetto di infrastruttura che contenga la mia funzionalità di accesso ai database, sia che si tratti di EF, NHIbernate, ecc. Al suo interno è possibile associare i propri oggetti alle tabelle. Quello che ho iniziato a fare è creare una classe di stato dei dati interna all'interno dei miei aggregati, che è quella a cui EF associa. Quindi, potresti avere qualcosa come CustomerDataState che ha tutti i tuoi getter e setter pubblici e identità su di esso. Usa EF o NHibernate per popolare quell'oggetto stato, che a sua volta imposta il tuo aggregato. Quella classe di stato non è esposta attraverso il tuo aggregato, quindi per quanto riguarda gli utenti del modello di dominio stanno semplicemente lavorando con ActiveCustomer o InactiveCustomer.

Quindi il tuo aggregato Active / InactiveCustomer viene caricato da o reidratato da un CustomerDataState che può essere caricato da un supporto di persistenza.

Trovo che il modo migliore per lavorare con DDD sia ignorare il database, dimenticarlo, far finta che non esista. Non appena inizi a pensare a come sarà mantenuto il tuo aggregato, hai perso la strada. Quindi, non appena un pensiero su file o tabelle ti viene in mente, datti una scossa e fai un passo indietro.

    
risposta data 01.02.2016 - 11:00
fonte

Leggi altre domande sui tag