Mapowanie encji biznesowych na encje bazodanowe - czy to ma sens?

0

Tak jak w tytule. Czy jest sens mieć dwa oddzielne modele dla encji biznesowych i encji np. JPA czy documentów Mongo? Czasami można usłyszeć, że tak, ale widzę w tym podejściu pewne problemy.
1.Dla każdej encji biznesowej musimy robić adekwatną encję bazodanową, mappera i repozytorium/dao co zwiększa ilość kodu i czas dowożenia projektu. Np. dla 5 encji jest to 10 dodatkowych klas (5 dla encji i 5 mapperów) a już dla 10 encji jest to 20 dodatkowych klas. Jak widać ilość tego dodatkowego kodu rośnie dość szybko.
2.Zmiana na innych sposób zapisu danych (np. z JPA na Mongo) jest czasochłonna co wynika z punktu 1. Jeśli nie mielibyśmy tego rozdzielenia na encje biznesowe i encje bazodanowe, to wystarczyłoby tylko pozmieniać dosłownie parę adnotacji (tak, tak wiem adnotacje nie są zbyt fajne, ale alternatyw jakoś nie widać za bardzo) i napisać repozytoria/dao. Załóżmy, że mamy te 10 encji czyli modyfikacja tych 10 encji + repo/dao vs 20 dodatkowych klas + repo/dao. Wybór wydaje się prosty.
3.Myślę, że do większości projektów wprowadzą to niepotrzebną złożoność i komplikacje, co utrudnia wejście do takiego projektu nowym osobą i utrzymywanie go.
Jestem przede wszystkim ciekaw z jakim podejściem spotykacie się w pracy. Zapraszam do dyskusji.

3
  1. Nigdy nie spotkałem się z tym, żeby ktoś podmieniał bazę z relacyjnej np. na Mongo. Zupełnie inne bazy, inne sposoby użycia. Co prawda spotkałem się z migracja Cassandra -> Mongo, ale to był k/v store.
  2. Jeśli te klasy są 1-1 to rzeczywiście nie ma sensu rozdzielać tych modeli. Dopiero jak model się rozrośnie, będzie więcej reguł itd, to może mieć sens. Nie ma sensu sobie dokładać pracy, tam gdzie się to nie spłaci.
  3. W teorii powinno się to rozdzielać, żeby model odzwierciedlał założenia biznesowe i nie musiał iść na kompromis z technologią (np. nie mogę zamodelować jakiegoś konceptu, bo mi framework nie pozwala). W praktyce takie sytuacje są raczej rzadko, a przy Mongo to już chyba w ogóle - nie ma problemów z lazy loadingiem, dokumenty przypominają obiekty itd
0
Charles_Ray napisał(a):

Jeśli te klasy są 1-1 to rzeczywiście nie ma sensu rozdzielać tych modeli. Dopiero jak model się rozrośnie, będzie więcej reguł itd, to może mieć sens.

To brzmi dobrze, ale z drugiej strony ogranicza to modelowanie domeny i zmusza do dopasowywania się do modelu bazodanowego. Np. mam tabelę Users, a mógłbym chcieć w domenie mieć bardziej kontekstową encję Administratora. I każdy w tym momencie mozna powiedzieć, że nie ma sensu zmieniać całego modelu, żeby wyodrębnić jedną encję. Indukcyjnie można pokazać, że choćbym mógł w ten sposób w koncu kompletnie przeprojektować domenę to nigdy nie będzie się to opłacać.

2

Jak robisz jakiś zwykły crud service, że byłoby 1:1 to nie ma sensu sobie dokładać roboty ale jak robisz coś ciekawszego to model domenowy może się różnić na tyle od modelu persystencji, że warto bo masz wtedy ładnie rozdzieloną logikę domenową bez mieszania tego z jakimiś adnotacjami z hibernate co jest też zgodne z architekturą hexagonalną.

1

3.Myślę, że do większości projektów wprowadzą to niepotrzebną złożoność i komplikacje, co utrudnia wejście do takiego projektu nowym osobą i utrzymywanie go.
Jestem przede wszystkim ciekaw z jakim podejściem spotykacie się w pracy. Zapraszam do dyskusji.

Jeśli masz model 1:1 to jesteś ograniczony takimi rzeczmi jak jakieś technikalia,czyli np. wymóg stosowania setterow/getterów czy konstruktor bezargumentowy to framework narzuca spore ograniczenia na design takich klas.

2

Moim zdaniem rozdzielanie ma jak najbardziej sens. Poczytaj o koncepcji DTO. Wiele razy mi to już w projekcie pomogło, ponieważ obiekty które przyjmujemy w kontrolerze powinniśmy przemapować na model biznesowy, na tym modelu dopiero dokonać jakichś tam reguł biznesowych, a dopiero potem przemapować to na obiekt bazodanowy i zapisać. Single responsibility w czystej postaci.

Ktoś np. zmieni coś w konktrakcie to dotyka to tylko warstwy DTO. Ktoś zmieni albo chce coś porobić w warstwie biznesowej to dotyka tylko tej warstwy. Ktoś rusza baze danych to rusza tylko to. Takie podejście w przyszłości zaprocentuje, ponieważ warstwy się nie przenikają. Ale to moja opinia.

Dzięki takiemu podejściu tak naprawdę trzymasz warstwę biznesową samą sobie.

1

1.Dla każdej encji biznesowej musimy robić adekwatną encję bazodanową, mappera i repozytorium/dao co zwiększa ilość kodu i czas dowożenia projektu.

Czas dowożenia projektu jest zazwyczaj nieporównywalnie mniejszy niż czas dalszego rozwoju i utrzymywania projektu. Zazwyczaj, bo oczywiście zdarzają się projekty potrzebne na tu i teraz do rozwiązania konkretnego problemu, a za 3 miesiące można taki projekt ubić i nigdy do niego nie wracać. Częściej jednak zdarza się, że projekty działają i są rozwijane przez długie lata.

Np. dla 5 encji jest to 10 dodatkowych klas (5 dla encji i 5 mapperów)

Kiedyś podobno płacili od linijki kodu, więc im więcej było kodu tym lepiej. Te czasy się skończyły i niektórzy poszli w drugie ekstremum sądząc, że mniej kodu = lepiej, co nie jest prawdziwe, bo jeżeli możemy uzyskać moduły/klasy/funkcje z pojedynczymi odpowiedzialnościami kosztem trochę większej ilości kodu to należy tak zrobić.
W programowaniu nie ogranicza cię szybkość z jaką jesteś w stanie pisać litery tylko wydajność w myśleniu i łączeniu koncepcji, a to jest nieporównywalnie prostsze i bardziej efektywne, gdy kod na który patrzysz spełnia jedną ograniczoną funkcję zamiast robić wszystkiego po trochu.

2.Zmiana na innych sposób zapisu danych (np. z JPA na Mongo) jest czasochłonna

Zapomnij o tym. Argument ze zmianą zapisu danych jest wałkowany zawsze i wszędzie, a w praktyce nikt tak nie robi. Sytuacje, w których faktycznie zmieniasz z JPA na Mongo są marginalne. Nawet zmiany typu relacyjna baza danych X -> relacyjna baza danych Y są bardzo rzadkie, a są koronnym argumentem zwolenników JPA.

Jeśli nie mielibyśmy tego rozdzielenia na encje biznesowe i encje bazodanowe, to wystarczyłoby tylko pozmieniać dosłownie parę adnotacji

Jest to co najmniej bardzo naiwne.

3.Myślę, że do większości projektów wprowadzą to niepotrzebną złożoność i komplikacje, co utrudnia wejście do takiego projektu nowym osobą i utrzymywanie go.

Wiesz co wprowadza niepotrzebną złożoność?
Gdy wywołujesz author.getBooks() i dostajesz LazyInitializationException, bo nie byłeś w sesji.
Gdy jesteś w sesji, ale debugger nie pokazuje ci książek autora, bo dopóki nie użyjesz tego gettera to się nie zaczytają.
Gdy zmieniasz pole w kodzie i magicznie samo się zmienia w bazie.
i wiele innych

Twoje wnioski prawdopodobnie wynikają z pisania fatalnie nudnego CRUDa. Tam faktycznie może to wydawać się zbędne, ale nawet w dosyć CRUDowych aplikacjach podział na domenę i persystencję ma często sens. Mniejszy, ale ma.

Jeszcze jedno. Potrzeba rozdzielenia persystencji od domeny jest ważna głównie dlatego, że kod domenowy jest prosty i przewidywalny - iteracje, ify, mapowania. To co najgorsze - nieprzewidywalne błędy dzieją się zazwyczaj podczas operacji IO - przy zapisach i odczytach danych spoza systemu, dlatego warto te operacje oddzielić wyraźną granicą od kodu, który realizuje jakąkolwiek logikę.

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