Wątek przeniesiony 2019-11-13 18:10 z przez Patryk27.

DDD - optymalizacja operacji na dużych kolekcjach wchodzących w skład agregatu i paginacja

Odpowiedz Nowy wątek
2019-11-13 14:46
0

Edycja: Byłbym wdzięczny o przeniesienie do forum 'Inżynieria oprogramowania'

Witam serdecznie, moje pytanie będzie się odnosić ogólnie do DDD ale posłużę się przykładem, aby łatwiej pokazać o co mi chodzi.
Załóżmy, że chcemy zaprojektować model forum, w którego skład wchodzi następujący agregat:

Wątek << Aggregate Root >>
Post << Entity >>

Wydaje się logiczne, że post nie ma globalnej tożsamości więc będzie wchodził w skład wątku.
W tym momencie wszystko wygląda w porządku, dopóki wielkość kolekcji postów nie będzie miała dużych rozmiarów.

I tutaj moje pytanie - jak powinna wyglądać poprawna paginacja postów. Nie chcę dodawać do wątku metod typu getPosts(int page), które nie mają nic wspólnego z domeną a tworzenie repozytorium postów przeczy idei agregatu.

Moje następne pytanie - zakładamy, że aplikacja ma możliwość operacji na pojedynczych postach, typu: edycja postu, polubienie postu. W sytuacji gdy kolekcja postów danego wątku jest bardzo duża za każdym razem muszę pobrać ją całą i dopiero wtedy wykonać operację na danym poście. Jak poprawnie zoptymalizować takie operację?

Pozdrawiam.

edytowany 3x, ostatnio: anon, 2019-11-13 14:50

Pozostało 580 znaków

2019-11-13 17:39

Na wstępie zaznaczam- nie ma złotych środków i jedynie proponuję jedno z możliwych rozwiązań.

Jak zawsze, należy zachować zdrowy rozsądek i wybrać optymalne rozwiązanie. Zwróć uwagę że napisałeś:

Wydaje się logiczne, że post nie ma globalnej tożsamości więc będzie wchodził w skład wątku.

Agregat to przede wszystkim granica transakcyjności (transactional boundary, nie wiem czy tak to się tłumaczy na język polski). Należy się kierować przede wszystkim tą zasadą kiedy myśli się o modelowaniu agregatów. Również nie ma nic złego w bardzo małych, jedno-encyjnych agregatach jeśli ma to sens i spełnia warunek pierwszej zasady. Piszę to dla tego że należało by odpowiedzieć sobie na pewne pytania:

  • Czy zmiana treści postu wymaga zaangażowania wątku?
  • Czy zmiana treści wątku (np. tytuł) wymaga zaangażowania postów?
  • Czy posty mogą zostać usunięte oddzielnie od usuwanego właśnie wątku?

Dodatkowo dochodzi wymieniony przez Ciebie problem potencjalnie dużej ilości postów w wątku, oraz samych postów mających dodatkowe atrybuty (nie mylić z atrybutami w kodzie) takie jak polubienia. Wracamy więc do pytań:

  • Czy załadowanie wątku oznacza konieczność załadowania wszystkich postów wraz z ich "wewnętrznymi" atrybutami?
  • Czy polubienie postu jest elementem "transakcji" całego wątku?

Moim zdaniem na podstawie tych pytań i informacji które podałeś wynika że Post jest świetnym kandydatem aby być agregatem samym w sobie, z encją Post jako root oraz np. Polubienie jako value object zawierający ID Posta i użytkownika który to polubił.

@Charles_Ray wspomniał że Wątek może być tylko view modelem Poszedł w dobrym kierunku, problem tylko że- jak mniemam- wątek również może być edytowany (tytuł, treść?) oraz zamykany i/lub usuwany. W tej sytuacji Wątek to również kandydat na agregat. Natomiast wspomnienie modelu widoku jest jak najbardziej trafne. Należy pamiętać że agregaty należą do warstwy modelu domeny, i same w sobie nie powinny mieć nic wspólnego z obsługą widoku. Co za tym idzie zainteresuj się CQRS i Materialized View. Wydaje mi się że Twój scenariusz wymaga takiego zastosowania- na podstawie tego co zachodzi w domenie będziesz mógł budować widok obsługujący konkretne wymagania- w Twoim przypadku zwracający wątek (a konkretnie informacje o wątku) oraz podzbiór postów filtrowany na podstawie strony którą aktualnie przegląda użytkownik.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus, 2019-11-13 19:34
Wow, super merytoryczny komentarz! - Charles_Ray 2019-11-13 17:42

Pozostało 580 znaków

2019-11-13 19:23
1

Matko przenajświętsza, przecież Post i Wątek to dwa agregaty.

A jak będziesz chciał moderować treść postu, to potrzebujesz do tego Wątek?

Będzie pochwalony! - Charles_Ray 2019-11-13 19:35

Pozostało 580 znaków

2019-11-13 19:48
0

@Aventus
Bardzo dziękuje za merytoryczną odpowiedź, od niedawna zajmuję się DDD i kilka napisanych przez Ciebie linijek
zmieniło moje postrzeganie tego tematu.

Co do CQRS to celowo o nim nie wspomniałem dlatego, że to rozwiązanie wydaje mi się zbyt drastyczne w przypadku
wydaje się prostego problemu jak paginacja. Wyobraźmy sobie, że mamy już stworzony dosyć rozwinięty model
domeny i nagle ze względów technicznych zachodzi potrzeba stronicowania jakiejś kolekcji, która wchodzi w skład agregatu.
Wprowadzenie CQRS z wyżej wymienionego powodu wydaje mi się zbyt drastyczne. Spotkałem się z jednak
z zapożyczoną z CQRS ideą Finder czyli klasy znajdującej się w warstwie aplikacji, która posiada wiedzę o wewnętrznej
strukturze agregatu i pozwala na odpytywanie o jego wewnętrzne elementy, nie jestem jednak pewien czy
nie przeczy to idei agregatu.

@Charles_Ray
Tak jak napisałem wyżej wydaje mi się, że w ten sposób zbliżamy się w stronę CQRS

@yarel
Dziękuję za przygotowany diagram, co do paginacji w warstwie domeny to może podałem zły przykład,
ponieważ możemy się tutaj na siłę doszukiwać znaczenia paginacji w dziedzinie jednak chodziło
mi o sytuację w której paginacja jest elementem wyłącznie technicznym, zwiększającym wydajność, elementem ui.

@WyznawcaDDD
Tak jak wspomniałem wyżej, nie chodzi mi konkretnie o problem forum ale o sytuacje w której musimy stronicować kolekcję która wchodzi w skład agregatu.
Szczerze mówiąc DDD zajmuję się od niedawna więc sytuacja jest czysto teoretyczna, nie wiem czy kiedykolwiek zajdzie taka potrzeba.

Pozostało 580 znaków

2019-11-13 20:06
2

Co do CQRS to celowo o nim nie wspomniałem dlatego, że to rozwiązanie wydaje mi się zbyt drastyczne w przypadku
wydaje się prostego problemu jak paginacja. Wyobraźmy sobie, że mamy już stworzony dosyć rozwinięty model
domeny i nagle ze względów technicznych zachodzi potrzeba stronicowania jakiejś kolekcji, która wchodzi w skład agregatu.
Wprowadzenie CQRS z wyżej wymienionego powodu wydaje mi się zbyt drastyczne.

Myślę że tutaj mylne są dwie kwestie. Po pierwsze w warstwie domeny chcesz osiągnąć coś co do domeny nie należy- paginacja na potrzeby widoku. Raz jeszcze zaznaczam że agregat to przede wszystkim granica transakcyjności. Paginowanie postów dla widoku nie leży w gestii tej transakcyjności.

Druga sprawa to że jak wiele osób zapewne mylisz podstawy CQRS z tym jak używa się go na poziomie infrastruktury- mając oddzielne bazy danych a czasem nawet serwisy. CQRS to natomiast coś znacznie prostszego, i fundamentalnie oznacza podział pomiędzy klasami odpowiadającymi za modyfikacje stanu aplikacji (polecenia- commands) oraz za odczyt tego stanu (zapytania- queries). Jeśli jest to więc odpowiednie rozwiązanie w Twoim przypadku, nic nie stoi na przeszkodzie aby korzystać z tej samej bazy danych. Różnica w tym że zamiast używać agregatu do załadowania widoku, skorzystasz z oddzielnej klasy reprezentującej widok która np. zostanie zbudowana na podstawie zapytania SQL stworzonego specjalnie na potrzeby tego widoku.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
Odczytanie rekordów z bazy danych na potrzeby paginacji to też transakcja w sensie bazodanowym. - TomRZ 2019-11-13 21:06
@TomRZ: zwróć uwagę że wątek dotyczy DDD i agregatów. Kiedy mowa o transakcyjności agregatu chodzi o transakcje w warstwie biznesowej. Warstwa infrastruktury nie ma tutaj znaczenia. Ba, w ogóle może jej nie być. To co napisałeś jest oczywiście słuszne, jednak w kontekście tej dyskusji nie ma znaczenia.. - Aventus 2019-11-13 21:21
Tak, rozumiem, wykonanie jakiejś operacji w logice biznesowej. Natomiast używanie agregatów równocześnie jako modeli do prezentacji danych jest kuszące... - TomRZ 2019-11-13 22:14
Jeśli ktoś ma wymogi dla widoku które mapują się 1:1 z agregatami to czemu nie. Natomiast w DDD modelowanie domeny nigdy nie powinno być podyktowane widokiem, tym bardziej że tych może być wiele w przyszłości. - Aventus 2019-11-13 22:22
Właśnie do tego piję, jakoś się tak często zdarza, że może nie 1:1, ale większość tego co jest w agregacie, powinno się też pojawić w widoku. Na przykładzie zamówienia i listy produktów - często jest tak, że oprócz działań logiki biznesowej, tą listę produktów gdzieś chcemy wyświetlić. Przynajmniej na początku jest wygodnie użyć agregatu, potem można robić dedykowany model widoku, który dodatkowo ma różne cechy związane ściśle z widokiem - np. jakieś keszowanie etc. - TomRZ 2019-11-13 22:28
Ok z tym się nie zgadzam. Nie mam innego punktu odniesienia więc opieram się na własnym doświadczeniu: częściej właśnie agregaty odbiegają od tego co widzi użytkownik. No ale to zapewne zależy od konkretnej domeny. No bo weźmy Twoje zamówienie dla przykładu- co oznacza zamówienie? To zależy od kontekstu (bounded context). Co jeśli w jednym kontekście zamówienie posiada atrybutu a, b i c, natomiast w drugim kontekście to już a, x i y? A użytkownik musi zobaczyć na ekranie a, b, x i Z? Wracamy do rozwiązania z dedykowanym modelem widoku ;) - Aventus 2019-11-13 22:37

Pozostało 580 znaków

2019-11-13 20:34
3

Jak @Aventus dobrze prawi: model układasz sobie w oparciu o reguły biznesowe (które musza być spójne natychmiast), które sprawdzasz przy zapisie, natomiast paginacja, grupowanie danych to kwestia odczytu danych, które mogą operować na innym modelu (zoptymalizowanym pod odczyty właśnie). Najważniejsza lekcja moim zdaniem - nie myśl o modelu w kategoriach widoków.

Pozostało 580 znaków

2019-11-13 21:39
0

@Aventus @Charles_Ray
Rozumiem i jak najbardziej ma to sens, ale jeszcze dopytam, czy warstwy zapisu i odczytu CQRS w kontekście DDD
to odpowiednio warstwa domeny i dodatkowa warstwa odczytu? Czy flow w tym przypadku mógłby wyglądać następująco:

  • UI - Przekazuje Command lub Query do CommandService lub QueryService warstwy aplikacji
  • Application - CommandService lub QueryService zarząda elementami Command Model (Domain) lub Query Model
  • Query Model - Zawiera modele widoku (np. projekcje agregatów) oraz interfejsy repozytoriów potrzebne do ich odczytu
  • Command Model (Domain) - to co w DDD
  • Infrastructure - to co w DDD

Pozostało 580 znaków

2019-11-13 21:44
1

Jak dla mnie to wygląda OK, poza ostatnim- nie za bardzo rozumiem co infrastruktura ma do DDD. Infrastruktura to infrastruktura dostarczająca implementacji dla abstrakcji wyżej.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.

Pozostało 580 znaków

2019-11-13 21:48
1

@Aventus
Tak i o to właśnie mi chodziło. Jeszcze raz dziękuje za pomoc, bardzo mi to pomogło

Pozostało 580 znaków

2019-11-13 21:54
1

To ja tu tylko zostawię jako taki mały suplement: https://pl.wikipedia.org/wiki/Kulty_cargo


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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