Operacje na encjach niebędących korzeniami

0

Dalej dla nauki piszę tego mojego CRUDa, wykorzystując wzorce z DDD. Postanowiłem, że jak już zacząłem, to już skończę. Pojawił się znowu problem natury filozoficznej. W tej mojej aplikacji klient może oceniać produkty, ale też zmieniać dokonane oceny. I tu pytanie: jak te zmiany zrealizować?
Opcja 1:

// gdzieś w warstwie aplikacji
// metoda SetStars encji ProductRate jest oznaczona jako internal i wywoływana przez AR Product
product.ChangeRate(_identity.GetCurrentUserId(), stars)

Opcja 2:

// gdzieś w warstwie aplikacji
// metoda SetStars jest publiczna
var rate = product.Rates.SingleOrDefault(r => r.CustomerId == _identity.GetCurrentUserId())
if (rate is null)
    // zrób coś
rate.SetStars(stars)
2
  1. CRUD i DDD nie powinny iść w parze. Rozumiem, że to dla nauki DDD, więc w sumie OK. Banalny przykład, żeby się uczyć.
  2. Po to masz aggregate root/korzeń, żeby pilnował spójności danych (ang. transactional boundary). Pomaga też, posiadanie metod które mają znaczenie biznesowe. Wtedy wiesz po co ta metoda istnieje. Wzbogaca to czytelność kodu. Także nie, nie możesz użyć drugiego podejścia. Wtedy szlag trafia enkapsulacje. Co nie tylko nie jest "fajne" w DDD ale także w OOP.
  3. Masz dwie biznesowe operacje: Dodanie oceny i Zmiana oceny. Jeśli się da - rozbij je na osobne metody w domenie, a także osobne endpointy w API.
1

W ogóle bym się zastanowił czy z ocen nie zrobić AR, w teorii zawsze powinniśmy wczytywać całego AR do pamięci razem z jego zależnościami (to jest miejsce w którym lazy loading się przydaje). A więc jeśli nasz produkt ma tysiące ocen, to za każdym razem będziemy musieli je wszystkie załadować. To nie będzie przyjemne ze względu wydajnościowego, a w ddd wydajność również jest ważna jak wiemy z niebieskiej książki, także lepiej zrobić z produktu i z ocen oddzielne AR.

AR powinny być małe, jeśli zawartość jakiegoś AR może być duża i szybko rosnąć, to najlepiej go podzielić.

0

Wybierajac pierwsze podejscie, powinienem oznaczyc metode SetStars encji ProductRate jako internal, zeby nie wypuscic jej z warstwy domeny. Jesli wiec podziele projekt na moduly, to bede musial tez podzielic kazdy z tych modulow na kilka projektow, z ktorych kazdy bedzie odpowiadal logicznie jednej z warstw. Tak?

0

@neves Wydawalo mi sie, ze o tym, czy encja powinna byc korzeniem, mozna zdecydowac, patrzac na to, czy moze byc potrzebna bezposrednio z innych agregatow. Skoro ze wzgledow wydajnosciowych odpowiedz nie zawsze jest tak prosta, tak wiec czym sie kierowac?

3

i dostępnością, i tym żeby agregat był mały, i spójnością, i wydajnoscią, i innymi rzeczami też :D, polecam te trzy krótkie artykuły, powinny sporo wyjaśnić:
Effective Aggregate Design Part I
Effective Aggregate Design Part II
Effective Aggregate Design Part III

0

Produkt może być agregatem, skoro możesz go ocenić. Natomiast jeśli masz agregat Zamówienie, które ma w sobie encje Produkt, to powinny to być „snapshoty” produktów bez ocen. Widać wyraźnie, że masz kontekst Zamówień i Katalogu Produktów. Pomyśl sobie o cyklu życia takiego produktu - najpierw jest on Produktem w jakimś katalogu produktów, a później jest pozycja zamówienie - to 2 różne byty.

1 użytkowników online, w tym zalogowanych: 0, gości: 1