DTO - czy dobrze rozumiem ?

0

Hej, jakiś czas temu zastanawiałem się po co jest DTO, ale tego "nie czułem". Za to dzisiaj wpadła mi myśl do głowy i CHYBA zrozumiałem po co DTO jest.
przykład:
Mam rejestrację na stronie:
W Controllerze przyjmuję UserDTO -> w Service z UserDTO robię User'a i poprzez Repository zapisuję go do bazy danych.
Tak to powinno działać czy może się mylę ?

2

Hm no niekoniecznie. Ten User w Serwisie to moze być jakiś Domain Object, podczas gdy to co zapisujesz do bazy często jest jeszcze innym obiektem.
Wracajac do pytania wyjściowego: DTO to są po prostu struktury danych, zwykle używane żeby przekazywać dane pomiędzy serwisami (także zdalnymi). Takie coś co łatwo zmapować i odmapować z jsona czy xmla.

4

Może się zdarzyć, że w bazie czy obiekcie domenowym masz dużo więcej informacji niż to co chcesz przesłać na widok. W takiej sytuacji "przepisujesz" do DTO tylko to co chcesz wysyłasz dalej

1
  1. DTO to Data Transfer Object, czyli obiekt służący do transferu danych po sieci i innego sensu to nie ma.
  2. Osobne warstwy aplikacji powinny mieć osobne zestawy obiektów, Dla przykładu zamówienie powinno być reprezentowane przez:
  • OrderDTO w warstwie RESTowej
  • Order w warstwie biznesowej
  • OrderRow (czy jakoś tak) w warstwie bazodanowej (przy założeniu, że redukujemy magię związaną z dostępem do bazki do minimum)
  • OrderView w warstwie widokowej (z tym, że obecnie idzie się w SPA typu Angular/ React/ Vue/ cokolwiek, więc OrderView będzie napisane w JavaScripcie)

Warstwa biznesowa to także warstwa gdzie warto opakować ogólne typy w typy domenowe, czyli np zamiast przerzucać wszędzie nazwę konta jako String można zrobić np z pomocą Lomboka klaskę:

@lombok.Data
public class AccountName {
  private final String value;
}

Późniejsze używanie AccountName zamiast Stringa pozwoli na znacznie efektywniejszą statyczną analizę kodu.

@Data generuje equals, hashCode itd, więc w warstwie biznesowej można posługiwać się instancją klasy AccountName wprost, a dopiero przy konwersjach z/ do OrderDTO, OrderRow czy OrderView wyjdzie potrzeba wyciągnięcia wartości metodą getValue().

0

Spoko, wiem co to lombok (a przynajmniej umiem z niego korzystać :D)
@Wibowit napisałeś "OrderDTO w warstwie RESTowej" tzn. chodzi o RestControllery ?

@danek "Może się zdarzyć, że w bazie czy obiekcie domenowym masz dużo więcej informacji niż to co chcesz przesłać na widok."
Czyli robię obiekt identyczny jak ten bazodanowy i przepisuję sobie do niego tylko te informacje, które w danym momencie potrzebuję, a cała reszta jest pusta? Czy może robię kilka różnych DTO z tymi polami, które potrzebuję ?
Jeszcze pytanie czym może różnić się obiekt domenowy od obiektu bazodanowego ? Jakimiś zbędnymi informacjami, które nie są zbyt wykorzystywane ?

Jeśli macie jakieś ciekawe materiały/artykuły związane z tematem to możecie podesłać. I sorki, że ze mnie taka ciemna masa :X
Jeszcze takie pytanie czym się różni DAO od Repository ?

2

@herbatek

Robisz kilka dto, w zależności od tego co potrzebujesz. Np masz obiekt ligi która ma listę meczy, a na widoku chcesz wyświetlić tylko podsumowanie ligi i nie ma sensu wtedy całej listy meczy wysyłać

1

Była całkiem ciekawa dyskusja o obiektach domenowych tutaj - w teorii obiekt bazodanowy w Javie powinien służyć tylko do zadań związanych z persystencją, obiekt domenowy z kolei do wykonywania zadań domenowych. Więcej można się dowiedzieć czytając o architekturze DDD :).

2

@Wibowit napisałeś "OrderDTO w warstwie RESTowej" tzn. chodzi o RestControllery ?

Nie wiem co to RestControllery (bo w Scali piszę a to pewnie Springowe :) ), ale brzmi jakby to było to.

Może się zdarzyć, że w bazie czy obiekcie domenowym masz dużo więcej informacji niż to co chcesz przesłać na widok.

Czasami może być też odwrotnie, np chcemy wyświetlić zamówienie na podstawie danych zarówno z naszej bazki jak i np raportu ściąganego codziennie z zewnątrz, którego nie chcemy pakować do bazy, a trzymać w oryginalnej formie na dysku.

Jeszcze pytanie czym może różnić się obiekt domenowy od obiektu bazodanowego ? Jakimiś zbędnymi informacjami, które nie są zbyt wykorzystywane ?

Przede wszystkim jeśli oddzielisz obiekt domenowy od bazodanowego to możesz robić wszelakie mappingi i optymalizacje bez mieszania w obiekcie domenowym. Dla przykładu możesz mieć własny dziwaczny system enumów, którego twoja magiczna biblioteka do łączenia z bazą danych z automatu nie obsługuje, więc zrobisz go sobie sam w warstwie bazodanowej tam gdzie jest tłumaczenie między postacią domenową, a bazodanową. Możesz zoptymalizować działanie bazy dzieląc tabelę na dwie w relacji 1:1. Dla przykładu zamówienie dzielisz na OrderDocumentRow (zawierające oryginalny dokument z zamówieniem) + OrderHeadersRow (zawierające najczęściej wykorzystywane dane pochodzące z dokumentu). Skanowanie tabeli OrderHeadersRow jest szybsze niż skanowanie niepodzielonej tabeli, więc dla skomplikowanych zapytań do bazy wykorzystanie zasobów będzie mniejsze. Inną sprawą jest np serializacja danych - możesz zdecydować się na upakowanie zawartości całej klasy do jednego Stringa i w takiej postaci zapisywać go w bazie. Możesz mieć klasy z bazodanowymi IDkami w środku i robić na nich różne cuda wewnątrz warstwy bazodanowej - nie zaśmiecając obiektów domenowych (wstawianie IDków bazodanowych do obiektów domenowych moim zdaniem szybko się mści).

Czyli robię obiekt identyczny jak ten bazodanowy i przepisuję sobie do niego tylko te informacje, które w danym momencie potrzebuję, a cała reszta jest pusta? Czy może robię kilka różnych DTO z tymi polami, które potrzebuję ?

Zakoduj sobie, że DTO jest do pchania danych między aplikacjami/ mikroserwisami/ klientem i serwerem/ etc, a nie między aplikacją, a bazą danych. DTO jest w zasadzie (sporą) częścią zewnętrznego API aplikacji. Z tego powodu DTO powinno być dość stabilne, bo zmiany trzeba synchronizować między aplikacjami/ mikroserwisami/ klientami i serwerem/ etc a to jest upierdliwe. Obiekty domenowe są prywatne dla danej aplikacji, więc można je swobodniej zmieniać niż DTO.

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