Lassen Sie mich zunächst für die Länge des Beitrags entschuldigen, aber ich wollte unbedingt möglichst viele Details im Vorfeld vermitteln, damit ich mir nicht die Zeit nehme, in Kommentaren hin und her zu gehen.
Ich entwerfe eine Anwendung nach einem DDD-Ansatz und frage mich, welche Anleitung ich befolgen kann, um zu bestimmen, ob eine aggregierte Root eine andere AR enthalten soll oder ob sie als separate, "freistehende" ARs belassen werden sollen.
Nehmen Sie den Fall einer einfachen Stechuhr-Anwendung, mit der Mitarbeiter sich für den Tag ein- oder ausstempeln können. Über die Benutzeroberfläche können sie ihre Mitarbeiter-ID und PIN eingeben, die dann validiert und der aktuelle Status des Mitarbeiters abgerufen werden. Wenn der Mitarbeiter gerade eingetaktet ist, wird auf der Benutzeroberfläche die Schaltfläche "Ausstempeln" angezeigt. und umgekehrt, wenn sie nicht eingetaktet sind, lautet die Schaltfläche "Eingetaktet". Die durch die Schaltfläche ausgeführte Aktion entspricht auch dem Status des Mitarbeiters.
Die Anwendung ist ein Webclient, der einen Back-End-Server aufruft, der über eine RESTful-Serviceschnittstelle verfügbar gemacht wird. Mein erster Versuch, intuitive, lesbare URLs zu erstellen, führte zu den folgenden zwei Endpunkten:
http://myhost/employees/{id}/clockin
http://myhost/employees/{id}/clockout
HINWEIS: Diese werden verwendet, nachdem die Mitarbeiter-ID und die PIN validiert wurden und ein "Token", das den "Benutzer" darstellt, in einem Header übergeben wurde. Dies liegt daran, dass es einen "Manager-Modus" gibt, mit dem ein Manager oder Vorgesetzter einen anderen Mitarbeiter ein- oder ausstempeln kann. Im Interesse dieser Diskussion versuche ich, es einfach zu halten.
Auf dem Server habe ich einen ApplicationService, der die API bereitstellt. Meine anfängliche Idee für die ClockIn-Methode ist wie folgt:
public void ClockIn(String id)
{
var employee = EmployeeRepository.FindById(id);
if (employee == null) throw SomeException();
employee.ClockIn();
EmployeeRepository.Save();
}
Dies sieht ziemlich einfach aus, bis wir feststellen, dass die Zeitkarteninformationen des Mitarbeiters tatsächlich als Liste von Transaktionen gespeichert sind. Das heißt, jedes Mal, wenn ich ClockIn oder ClockOut aufrufe, ändere ich nicht direkt den Status des Mitarbeiters, sondern füge stattdessen einen neuen Eintrag in das Arbeitszeitblatt des Mitarbeiters ein. Der aktuelle Status des Mitarbeiters (eingetaktet oder nicht eingetaktet) wird aus dem letzten Eintrag im Arbeitszeitblatt abgeleitet.
Wenn ich also den oben gezeigten Code befolge, muss mein Repository erkennen, dass sich die dauerhaften Eigenschaften des Mitarbeiters nicht geändert haben, sondern dass ein neuer Eintrag zum Arbeitszeitblatt des Mitarbeiters hinzugefügt wurde, und eine Einfügung in den Datenspeicher vornehmen.
Auf der anderen Seite (und hier ist die ultimative Frage des Beitrags) scheint TimeSheet ein aggregierter Stamm zu sein, und es hat eine Identität (die Mitarbeiter-ID und die Periode), und ich könnte genauso einfach dieselbe Logik wie TimeSheet.ClockIn implementieren (Mitarbeiter-ID).
Ich diskutiere die Vorzüge der beiden Ansätze und frage mich, wie eingangs erwähnt, welche Kriterien ich bewerten sollte, um festzustellen, welcher Ansatz für das Problem besser geeignet ist.