Zagłębiam się w koncepcje projektowania opartego na domenach (DDD) i odkryłem, że niektóre zasady są dziwne, szczególnie w odniesieniu do izolacji domeny i modelu trwałości. Oto moje podstawowe zrozumienie:
- Usługa w warstwie aplikacji (udostępniająca zestaw funkcji) żąda obiektów domeny z repozytorium, której potrzebuje do wykonywania swojej funkcji.
- Konkretna implementacja tego repozytorium pobiera dane z pamięci, dla której została zaimplementowana
- Usługa informuje obiekt domeny, który zawiera logikę biznesową, o wykonaniu pewnych zadań, które modyfikują jego stan.
- Usługa informuje repozytorium o utrwaleniu zmodyfikowanego obiektu domeny.
- Repozytorium musi odwzorować obiekt domeny z powrotem na odpowiednią reprezentację w pamięci.
Teraz, biorąc pod uwagę powyższe założenia, następujące wydaje się niezręczne:
Ogłoszenie 2 .:
Model domeny wydaje się ładować cały obiekt domeny (w tym wszystkie pola i odwołania), nawet jeśli nie są one potrzebne dla funkcji, która o to poprosiła. Całkowite wczytanie może nawet nie być możliwe, jeśli odwołujemy się do innych obiektów domeny, chyba że załadujesz również te obiekty domeny i wszystkie obiekty, do których się odwołują, itd. I tak dalej. Leniwe ładowanie przychodzi mi na myśl, co oznacza jednak, że zaczynasz sprawdzać obiekty domeny, które powinny przede wszystkim odpowiadać repozytorium.
Biorąc pod uwagę ten problem, „poprawny” sposób ładowania obiektów domeny wydaje się mieć dedykowaną funkcję ładowania dla każdego przypadku użycia. Te dedykowane funkcje ładowałyby wtedy tylko dane wymagane przez przypadek użycia, dla którego zostały zaprojektowane. Oto, gdzie pojawia się niezręczność: po pierwsze musiałbym utrzymać znaczną liczbę funkcji ładowania dla każdej implementacji repozytorium, a obiekty domeny skończyłyby w niekompletnych stanach przenoszących null
swoje pola. Ten ostatni nie powinien technicznie stanowić problemu, ponieważ jeśli wartość nie została załadowana, nie powinna być wymagana przez funkcję, która o to poprosiła. Nadal jest to niewygodne i potencjalne zagrożenie.
Ogłoszenie 3 .:
W jaki sposób obiekt domeny zweryfikowałby ograniczenia unikatowości podczas budowy, jeśli nie ma pojęcia repozytorium? Na przykład, jeśli chciałbym utworzyć nowy User
z unikalnym numerem ubezpieczenia społecznego (który jest podany), najwcześniejszy konflikt wystąpiłby po poproszeniu repozytorium o zapisanie obiektu, tylko jeśli w bazie danych zdefiniowano ograniczenie wyjątkowości. W przeciwnym razie mógłbym poszukać zabezpieczenia User
z danym ubezpieczeniem społecznym i zgłosić błąd, jeśli taki istnieje, zanim utworzę nowy. Ale wtedy kontrole ograniczeń będą działać w usłudze, a nie w obiekcie domeny, do której należą. Właśnie zdałem sobie sprawę, że obiektom domeny bardzo dobrze wolno używać (wstrzykiwanych) repozytoriów do sprawdzania poprawności.
Ogłoszenie 5 .:
Odwzorowanie obiektów domeny na zaplecze pamięci postrzegam jako proces wymagający dużej pracy w porównaniu z bezpośrednią modyfikacją danych domeny przez obiekty domeny. Jest to oczywiście niezbędny warunek oddzielenia konkretnej implementacji pamięci od kodu domeny. Czy jednak rzeczywiście wiąże się to z tak wysokimi kosztami?
Najwyraźniej masz opcję użycia narzędzi ORM do wykonania mapowania. Często wymagałyby one zaprojektowania modelu domeny zgodnie z ograniczeniami ORM, a nawet wprowadzenia zależności od domeny do warstwy infrastruktury (np. Za pomocą adnotacji ORM w obiektach domeny). Przeczytałem również, że ORM wprowadzają znaczny narzut obliczeniowy.
W przypadku baz danych NoSQL, dla których prawie nie istnieją pojęcia podobne do ORM, w jaki sposób śledzisz, które właściwości zmieniły się w modelach domen save()
?
Edycja : Ponadto, aby repozytorium mogło uzyskać dostęp do stanu obiektu domeny (tj. Wartości każdego pola), obiekt domeny musi ujawnić swój stan wewnętrzny, który przerywa enkapsulację.
Ogólnie:
- Dokąd zmierza logika transakcyjna? Z pewnością jest to charakterystyczne dla przetrwania. Niektóre infrastruktury pamięci masowej mogą nawet nie obsługiwać transakcji (np. Fałszywe repozytoria w pamięci).
- Czy w przypadku operacji masowych, które modyfikują wiele obiektów, musiałbym ładować, modyfikować i przechowywać każdy obiekt osobno, aby przejść przez enkapsulowaną logikę sprawdzania poprawności? Jest to przeciwieństwo wykonywania pojedynczego zapytania bezpośrednio w bazie danych.
Byłbym wdzięczny za wyjaśnienia na ten temat. Czy moje założenia są prawidłowe? Jeśli nie, jaki jest właściwy sposób rozwiązania tych problemów?