Jak rozwiązać problem "joint entities" w clean architecture

0

Cześć wszystkim :)

Zacząłem pisać swoją pierwszą większą aplikację w .Net Core, która docelowo ma być klonem Youtube. Zanim zacząłem tworzyć strukturę projektu, poczytałem sobie jak dobrze zaprojektować architekturę aplikacji i poczytałem sobie o clean architecture.

Jedną z funkcjonalności będzie możliwość subskrybowania użytkowników, a to wymaga stworzenia relacji many-to-many obiektów tej samej klasy (User). Przy modelowaniu bazy danych używam podejścia code-first w EF Core, a ten z kolei wymaga utworzenia dodatkowej klasy umożliwiającej takie mapowanie.

I tutaj pojawia się moja zagwozdka. Bo obiekt ten nie jest z pewnością częścią domeny, powinien być powiązany z częścią projektu odpowiedzialną za persystencję. Nie mogę go natomiast po prostu tam umieścić, bo wtedy obiekt domenowy User będzie zależny od klasy spoza domeny.

Jedyne co przychodzi mi do głowy to utworzenie (prawie zduplikowanie) zestawu klas z domeny razem z informacjami potrzebnymi do zapisu do BD i mapowanie pomiędzy tymi obiektami a domenowymi. Lub mógłbym odtworzyć tam tylko klasę User, ale to chyba nie jest dobre rozwiązanie bo wtedy każdy pipeline zawierający zapytania do BD byłby różny przy zapytaniach dotyczących Usera i wszystkich pozostałych. Z drugiej strony jeśli stworzę takie obiekty dla wszystkich obiektów domenowych, mimo że nie jest to potrzebne (przynajmniej na razie) to nie jest to łamanie DRY i YAGNI? Jakie jest wg. Was najlepsze rozwiązanie takiego problemu?
(Póki co to mapowanie zrobione jest przez obiekt Subscription w folderze ValueObjects, to jest oczywiście do zmiany).

I jeszcze drugie pytanie.

Inną z funkcjonalności będzie możliwość dawania łapek w górę/dół pod filmem/komentarzem.
Zrobiłem osobne obiekty dla lajków pod wideo, dislajków pod wideo i to samo dla komentarzy. Każdy z nich zawiera tylko autora danego lajka i film/komentarz, do którego został dodany i nic więcej. Czyli w praktyce są to również obiekty mapujące ze sobą 2 wiersze z dwóch innych tabel (czyli 2 inne obiekty domenowe). I właśnie nie jestem pewny co do tego czy powinienem traktować je jako obiekty domeny (value objects, gdyż nie muszą być w żaden sposób identyfikowalne) czy tak jak w przypadku wyżej traktować je jako obiekt stricte mapujący i przenieść do projektu z infrastrukturą. Wydaje mi się, że poprawna jest pierwsza opcja, ale nie mam pewności.

Jeśli macie jakieś dodatkowe uwagi jak można by coś zrobić lepiej to też chętnie przygarnę :)

Tutaj jest link do aplikacji: https://github.com/Qbelek/BlueTube

1

To jest kanoniczny dylemat- gdzieś mówią aby robić X, w moim przypadku lepiej by pasowało XY ale przecież tak nie wolno! Otóż wolno, jeśli rozwiązuje to Twój konkretny problem. Uważam że w programowaniu trzeba być dogmatycznym pragmatykiem, czyli przestrzegać zasad ale być otwartym na ich modyfikacje. A po zmodyfikowaniu trzymać się linii którą się ustaliło, aż do momentu kiedy znów trzeba dokonać lekkich modyfikacji. Grunt to być konsekwentnym i zdyscyplinowanym. Co za tym idzie nie uważam więc żeby Twoja klasa pośrednia- która de facto jest wymuszona przez ORM- była aż takim problemem. Jeśli koniecznie chcesz tego uniknąć i pozostawić warstwę domeny wierną jakimś dogmatom to może odseparować klasy reprezentujące encje od klas reprezentujących model domeny. Będzie to oczywiście oznaczało sporo duplikacji i konieczność mapowania z encji EF do klas domenowych. Jeśli jest to koszt który Twoim zdaniem warto ponieść to zrób to, w przeciwnym razie wybierz pierwszą opcję.

0
Qbelek napisał(a):

Z drugiej strony jeśli stworzę takie obiekty dla wszystkich obiektów domenowych, mimo że nie jest to potrzebne (przynajmniej na razie) to nie jest to łamanie DRY i YAGNI?

Jeśli chcesz odseparować dwie warstwy, to te klasy są potrzebne, a więc nie łamiesz YAGNI.
DRY dotyczy duplikowania logiki, a nie tego, że te same klasy mają podobne właściwości.

Jakie jest wg. Was najlepsze rozwiązanie takiego problemu?

Nie używać ORMa, który nie pozwala na persistence ignorance.

0

Wydaje mi się raczej że masz problem z samymi kontekstami User jest zbyt ogólny i zaczynasz mieszać warstwę Bazy danych z logiką biznesową.
Zamiast User zdefiniuj Subscriber, Channel etc. Wtedy biznesowo masz relacje troche inne, masz Channel(one) - subscriber(many). W momencie zapisu encji możesz to mapować na obiekty w bazie juz w dowolny sposób, ORM wtedy nawet jest zbędny.

Co do lajków to jest to kompletnie inny kontekst i ponownie nie powinieneś używać tutaj pojęcia User tylko np Viewer, nie powinno cię interesować jak to jest mapowane w bazie danych bo zaczynasz uzależniać się od szczegółów implementacji.

Musisz rozbudować słownictwo domenowe, wtedy będzie łatwiej oddzielić te konteksty od siebie.

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