Vorrei iniziare prima scusandomi per la lunghezza del post, ma volevo davvero trasmettere il maggior numero di dettagli in modo che non prendessi il tuo tempo andando avanti e indietro nei commenti.
Sto progettando un'applicazione seguendo un approccio DDD e mi sto chiedendo quale guida posso seguire per determinare se una radice di aggregazione dovrebbe contenere un'altra AR o se dovrebbero essere lasciate come AR separate, "indipendenti".
Prendi il caso di una semplice applicazione Time Clock che consente ai Dipendenti di attivarsi o meno per il giorno. L'interfaccia utente consente loro di inserire l'ID e il PIN del dipendente che viene quindi convalidato e lo stato corrente del dipendente recuperato. Se il dipendente è attualmente in time-in, l'interfaccia utente visualizza un pulsante "Clock Out"; e, al contrario, se non sono sincronizzati, il pulsante legge "Clock In". L'azione eseguita dal pulsante corrisponde anche allo stato del dipendente.
L'applicazione è un client Web che chiama un server back-end esposto tramite un'interfaccia di servizio RESTful. Il mio primo passaggio alla creazione di URL intuitivi e leggibili ha portato ai seguenti due endpoint:
http://myhost/employees/{id}/clockin
http://myhost/employees/{id}/clockout
NOTA: Questi vengono utilizzati dopo che l'ID e il PIN del dipendente sono stati convalidati e un "token" che rappresenta l'utente viene passato in un'intestazione. Questo perché esiste una "modalità manageriale" che consente a un manager o supervisore di inserire o ritirare un altro dipendente. Ma, per il gusto di questa discussione, sto cercando di renderlo semplice.
Sul server, ho un ApplicationService che fornisce l'API. La mia idea iniziale per il metodo ClockIn è qualcosa del tipo:
public void ClockIn(String id)
{
var employee = EmployeeRepository.FindById(id);
if (employee == null) throw SomeException();
employee.ClockIn();
EmployeeRepository.Save();
}
Sembra piuttosto semplice fino a quando non ci rendiamo conto che le informazioni sulla carta del tempo del dipendente sono effettivamente mantenute come un elenco di transazioni. Ciò significa che ogni volta che chiamo ClockIn o ClockOut, non sto cambiando direttamente lo stato del Dipendente ma, invece, aggiungo una nuova voce nel TimeSheet del dipendente. Lo stato corrente del Dipendente (con o senza clock) è derivato dalla voce più recente nel TimeSheet.
Quindi, se vado con il codice mostrato sopra, il mio repository deve riconoscere che le proprietà persistibili del Dipendente non sono cambiate ma che una nuova voce è stata aggiunta nel TimeSheet del dipendente ed eseguito un inserimento nell'archivio dati.
D'altro canto (ed ecco l'ultima domanda del post), TimeSheet sembra essere una radice di aggregazione così come ha l'identità (l'ID e il periodo del dipendente) e potrei altrettanto facilmente implementare la stessa logica di TimeSheet.ClockIn (employeeId).
Mi trovo a discutere i meriti dei due approcci e, come affermato nel paragrafo di apertura, mi chiedo quali criteri dovrei valutare per determinare quale approccio sia più adatto al problema.