Nachdem ich "Implementieren von domänengesteuertem Design von Vaughn Vernon" gelesen habe, habe ich beschlossen, meinen Code für eine bessere Wiederverwendbarkeit umzugestalten, indem ich das, was ich für Kerndomänenkonzepte halte, in separate Module isoliere.
Jedes Modul enthält einen eigenen Satz unterschiedlicher Architekturebenen, darunter die Domänen-, Infrastruktur- und die Anwendungs- / Präsentationsschicht (gemäß Vaughns Empfehlung habe ich beschlossen, die Verantwortlichkeiten der Anwendungsschicht weiter von Routen, MVC-Controllern + Vorlagen zu trennen, die in der Präsentationsfolie).
Ich habe beschlossen, jede dieser Ebenen in einem eigenen Paket zu platzieren. und jedes Paket verweist auf die darunter liegende Ebene als Abhängigkeit. Das heißt: Die Präsentationsschicht hängt von der Anwendungsschicht ab, die Anwendung hängt von der Infrastruktur ab usw. Da das Repository Teil der Domäne ist, ist jede Repository-Schnittstelle innerhalb der Domänenschicht / des Domänenpakets vorhanden, wobei die Implementierung in der Verantwortung der Infrastrukturschicht / des Infrastrukturpakets liegt (Doctrine) , usw).
Ich hoffe, dass ich durch die Umstrukturierung meines Codes auf diese Weise die Anwendungsschicht austauschen und meine Domain für mehrere Webanwendungen wiederverwenden kann.
Der Code sieht schließlich so aus, als würde er sich wieder formen. Was mich jedoch immer noch verwirrt, ist diese Unterscheidung zwischen Anwendungs-, Infrastruktur- und Domänendiensten.
Ein häufiges Beispiel für einen Domänendienst ist etwas, mit dem Sie Kennwörter hashen würden. Dies ist aus SRP-Sicht für mich sinnvoll, da sich die Benutzerentität nicht mit den vielen verschiedenen Hashing-Algorithmen befassen sollte, die zum Speichern der Anmeldeinformationen eines Benutzers verwendet werden können.
In diesem Sinne habe ich diesen neuen Domain-Service genauso behandelt wie meine Repositorys. indem Sie eine Schnittstelle in der Domäne definieren und die Implementierung der Infrastrukturschicht überlassen. Jetzt frage ich mich jedoch, was mit den Anwendungsdiensten geschehen soll.
Derzeit verfügt jede Entität über einen eigenen Anwendungsdienst, dh die Benutzerentität verfügt über einen UserService innerhalb der Anwendungsschicht. Der UserService ist in diesem Fall für das Parsen primitiver Datentypen und die Behandlung eines allgemeinen Anwendungsfalls "UserService :: CreateUser (Stringname, String-E-Mail usw.): Benutzer verantwortlich.
Was mich betrifft, ist die Tatsache, dass ich diese Logik über mehrere Anwendungen hinweg erneut implementieren muss, wenn ich mich entscheide, die Anwendungsschicht auszutauschen. Ich denke, das führt mich zu meinen nächsten Fragen:
Sind Domänendienste lediglich eine Schnittstelle, die eine Abstraktionsebene zwischen der Infrastrukturschicht und Ihrem Modell bereitstellt? dh: Repositories + HashingServices usw.
Ich erwähnte einen Anwendungsdienst, der so aussieht:
Zugriff / Anwendung / Dienste / UserService :: CreateUser (Zeichenfolgenname, Zeichenfolgen-E-Mail usw.): Benutzer
Die Methodensignatur akzeptiert primitive Datentypargumente und gibt eine neue Benutzerentität zurück (kein DTO!).
Gehört dies in die Infrastrukturschicht als Implementierung einer in der Domänenschicht definierten Schnittstelle oder ist die Anwendungsschicht aufgrund primitiver Datentypargumente usw. tatsächlich besser geeignet ?
Beispiel:
Access/Domain/Services/UserServiceInterface
und
Access/Infrastructure/Services/UserService implements UserServiceInterface
Wie sollten separate Module mit unidirektionalen Beziehungen umgehen? Sollte Modul A die Anwendungsschicht von Modul B (wie jetzt) oder die Infrastrukturimplementierung (über eine separate Schnittstelle) referenzieren?
Benötigen Application Layer Services eine separate Schnittstelle? Wenn die Antwort ja lautet, wo sollten sie sich dann befinden?