Czy usługi powinny zawsze zwracać DTOs, czy też mogą zwracać modele domen?

Projektuję (re)wielkoskalową aplikację, wykorzystujemy architekturę wielowarstwową opartą na DDD.

Mamy MVC z warstwą danych( implementacja repozytoriów), warstwą domeny (definicja modelu domeny i interfejsów - repozytoria, usługi, jednostka pracy), warstwą usług (implementacja usług). Do tej pory korzystamy z modeli domen (głównie encji) dla wszystkich warstw, a DTOs używamy tylko jako modeli widoków(w controlle, service returns domain model (S) I controller tworzy model widoku, który jest przekazywany do widoku).

Czytałem niezliczone artykuły o używaniu, nie używaniu, mapowaniu i przekazywaniu DTOs. Rozumiem, że nie ma żadnej ostatecznej odpowiedzi, ale nie jestem pewien, czy jest ok, czy nie zwraca modeli domen z usług do kontrolerów. Jeśli zwrócę model domeny, nadal nie jest on przekazywany do widoku, ponieważ kontroler zawsze tworzy model widoku specyficzny dla widoku - w tym przypadku wydaje się to legalne. Z drugiej strony, nie czuje się dobrze, gdy model domeny opuszcza warstwa biznesowa (service layer). Czasami usługa musi zwrócić obiekt danych, który nie został zdefiniowany w domenie i wtedy albo musimy dodać nowy obiekt do domeny, która nie jest mapowana, albo utworzyć obiekt POCO (jest to brzydkie, ponieważ niektóre usługi zwracają modele domen, niektóre skutecznie zwracają DTOs).

Pytanie brzmi - jeśli ściśle używamy modeli widoków, czy jest w porządku zwracać modele domen aż do kontrolerów, Czy zawsze powinniśmy używać DTOs do komunikacji z warstwą usług? Jeśli tak, to czy ok, aby dostosować modele domen w oparciu o jakie usługi potrzebują? (Szczerze mówiąc nie sądzę, ponieważ usługi powinny konsumować to, co ma domena.) Jeśli powinniśmy ściśle trzymać się DTOs, to czy powinny one być zdefiniowane w warstwie usług? (Chyba tak.) Czasami jest jasne, że powinniśmy używać DTOs (np. gdy serwis wykonuje dużo logiki biznesowej i tworzy nowe obiekty), czasami jest jasne, że powinniśmy używać tylko Modeli domen (np. gdy serwis członkowski zwraca anemicznych użytkowników - wydaje się, że nie miałoby to większego sensu stworzyć DTO czyli taki sam jak model domeny) - ale wolę spójność i Dobre praktyki.

Artykuł domena vs DTO vs ViewModel-jak i kiedy z nich korzystać? (a także kilka innych artykułów) jest bardzo podobny do mojego problemu, ale nie odpowiada na to pytanie (y). Article Czy powinienem zaimplementować DTOs we wzorze repozytorium za pomocą EF? jest również podobny, ale nie dotyczy DDD.

Zastrzeżenie: nie zamierzam używać żadnego wzorca projektowego tylko dlatego, że istnieje i jest z drugiej strony chciałbym wykorzystać dobre wzorce projektowe i praktyki również dlatego, że pomaga to w projektowaniu aplikacji jako całości, pomaga w rozdzielaniu obaw, nawet używanie określonego wzorca nie jest "konieczne", przynajmniej w tej chwili.

Jak zawsze, dziękuję.

Author: Community, 2014-02-04

9 answers

nie wydaje się to właściwe, gdy model domeny opuszcza warstwę biznesową (warstwę usług)

Sprawia, że czujesz się, jakbyś wyciągał wnętrzności, prawda? Według Martina Fowlera: warstwa usług definiuje wiązania aplikacji, hermetyzuje domenę. Innymi słowy chroni domenę.

czasami usługa musi zwrócić obiekt danych, który nie został zdefiniowany w domenie

Czy możesz podać przykład tych danych obiekt?

Jeśli powinniśmy ściśle trzymać się DTOs, to czy powinny one być zdefiniowane w warstwie usług?

Tak, ponieważ odpowiedź jest częścią warstwy usług. Jeśli jest zdefiniowana jako "gdzie indziej", warstwa usług musi odnosić się do tego "gdzie indziej", dodając nową warstwę do Twojej lasagny.

Czy można zwracać modele domen aż do kontrolerów, Czy zawsze powinniśmy używać DTOs do komunikacji z serwisem warstwa?

DTO jest obiektem odpowiedzi/żądania, ma to sens, jeśli używasz go do komunikacji. Jeśli używasz modeli domeny w warstwie prezentacji (MVC-Controllers/View, WebForms, ConsoleApp), warstwa prezentacji jest ściśle powiązana z twoją domeną, wszelkie zmiany w domenie wymagają zmiany kontrolerów.

wydaje się, że nie ma sensu tworzyć DTO, które jest tym samym co model domeny)

Jest to jeden z wadą DTO dla nowych oczu. W tej chwili myślisz o powielaniu kodu , ale gdy twój projekt się rozwija, nabiera to większego sensu, szczególnie w środowisku zespołowym, w którym różne zespoły są przypisane do różnych warstw.

DTO może dodać dodatkowej złożoności do aplikacji, ale tak samo jak warstwy. DTO jest kosztowną cechą twojego systemu, nie są one bezpłatne.

Po co używać DTO

Ten artykuł dostarcza zarówno korzyści, jak i wad korzystanie z DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Podsumowanie w następujący sposób:

Kiedy stosować

  • dla dużych projektów.
  • Czas trwania projektu wynosi 10 lat i więcej.
  • strategiczne, krytyczne zastosowanie.
  • duże zespoły (więcej niż 5)
  • deweloperzy są rozproszeni geograficznie.
  • Domena i prezentacja są różne.
  • zmniejsz koszty wymiany danych (pierwotny cel DTO)

Kiedy nie używać

  • mały do średniej wielkości projekt (maksymalnie 5 członków)
  • Czas trwania projektu wynosi około 2 lata.
  • brak oddzielnego zespołu dla GUI, backendu itp.

Argumenty przeciwko DTO

Argumenty z DTO

  • BEZ DTO, prezentacja i domena są ze sobą ściśle powiązane. (To jest ok dla małych projektów.)
  • stabilność interfejsu/API
  • może zapewnić optymalizację dla warstwy prezentacji zwracając DTO zawierające tylko te atrybuty, które są absolutnie wymagane. Używając LINQ-projection , nie musisz ciągnąć całego bytu.
  • aby obniżyć koszty rozwoju, użyj narzędzi generujących kod
 197
Author: Yorro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:02

Jestem spóźniony na tę imprezę, ale to jest tak powszechne i ważne pytanie, że czułem się zmuszony odpowiedzieć.

Przez "usługi" masz na myśli "warstwę aplikacji" opisaną przez Evana w blue book? Zakładam, że tak, w takim przypadku odpowiedź jest taka, że powinni Nie zwracać DTOs. Proponuję przeczytać rozdział 4 w niebieskiej Księdze, zatytułowany "izolowanie domeny".

W tym rozdziale Evans mówi co następuje o warstwach:

Partycja a złożony program w warstwy. Opracuj projekt w każdej warstwie, który jest spójny i zależy tylko od warstw poniżej.

Jest ku temu dobry powód. Jeśli użyjesz pojęcia częściowego porządku jako miary złożoności oprogramowania, to posiadanie warstwy zależnej od warstwy nad nią zwiększa złożoność, co zmniejsza konserwowalność.

Stosując to do twojego pytania, DTOs są naprawdę adapterem, który jest problemem warstwy interfejsu użytkownika / prezentacji. Pamiętaj, że komunikacja zdalna/międzyprocesowa jest dokładnie celem Dto (warto zauważyć, że w tym poście Fowler argumentuje również przeciwko temu, że DTOs jest częścią warstwy usług, chociaż niekoniecznie mówi językiem DDD).

Jeśli warstwa aplikacji zależy od tych Dto, to zależy od warstwy nad nią i zwiększa się złożoność. Mogę zagwarantować, że zwiększy to trudność w utrzymaniu Twojego oprogramowania.

Na przykład, co jeśli twój interfejsy systemu z kilkoma innymi systemami lub typami klientów, z których każdy wymaga własnego DTO? Skąd wiesz, który DTO metoda Twojej usługi aplikacyjnej powinna zwrócić? Jak byś w ogóle rozwiązał ten problem, gdyby wybrany przez ciebie język nie pozwalał na przeciążenie metody (w tym przypadku metody serwisowej)na podstawie typu zwrotu? A nawet jeśli wymyślisz sposób, po co naruszać warstwę aplikacji, aby wspierać problem warstwy prezentacji?

W praktyce jest to krok w dół drogi, która skończy się architekturą spaghetti. Widziałem tego rodzaju decentralizację i jej skutki w moim własnym doświadczeniu.

Gdzie obecnie pracuję, usługi w naszej warstwie aplikacji zwracają obiekty domeny. Nie uważamy tego za problem, ponieważ warstwa interfejsu (tj. UI/Prezentacja) zależy od warstwy domeny, która jest poniżej. Ponadto zależność ta jest minimalizowana do typu" reference only", ponieważ:

A) warstwa interfejsu ma dostęp tylko do tych Obiekty domeny jako wartości zwracane tylko do odczytu uzyskane przez wywołania warstwy aplikacji

B) metody na usługach w warstwie aplikacji przyjmują jako dane wejściowe tylko" surowe " dane wejściowe (wartości danych) lub parametry obiektu (w razie potrzeby w celu zmniejszenia liczby parametrów) zdefiniowane w tej warstwie. W szczególności usługi aplikacji nigdy nie akceptują obiektów domeny jako danych wejściowych.

Warstwa interfejsu wykorzystuje techniki mapowania zdefiniowane w samej warstwie interfejsu do mapowania z obiektów domeny do DTOs. To sprawia, że DTOs koncentruje się na tym, że są to Adaptery sterowane przez warstwę interfejsu.

 16
Author: BitMask777,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-19 20:53:07

Z mojego doświadczenia wynika, że powinieneś robić to, co jest praktyczne. "Najlepszy projekt to najprostszy projekt, który działa" - Einstein. Z tym jest umysł...

Jeśli ściśle używamy modeli widoków, czy jest w porządku zwracać modele domen aż do kontrolerów, czy też powinniśmy zawsze używać DTOs do komunikacji z warstwą usług?

Absolutnie jest ok! Jeśli masz encje domeny, modele DTO i View, a następnie tabele bazy danych masz wszystkie pola w aplikacji powtórzony w 4 miejscach. Pracowałem nad dużymi projektami, w których podmioty domeny i modele widoku działały dobrze. Jedynym wyjściem jest to, że aplikacja jest dystrybuowana, a warstwa usług znajduje się na innym serwerze, w którym to przypadku Dto są zobowiązane do wysyłania przez przewód ze względów serializacyjnych.

Jeśli tak, to czy można dostosowywać modele domen w oparciu o potrzeby usług? (Szczerze mówiąc nie sądzę, ponieważ usługi powinny konsumować to, co ma domena.)

Ogólnie Zgadzam się i powiem nie, ponieważ model domeny jest zazwyczaj odzwierciedleniem logiki biznesowej i zwykle nie jest kształtowany przez konsumenta tej logiki.

Jeśli powinniśmy ściśle trzymać się DTOs, czy powinny one być zdefiniowane w warstwie usług? (Chyba tak.)

Jeśli zdecydujesz się z nich korzystać, zgodzę się i powiem tak warstwa usług jest idealnym miejscem, ponieważ zwraca DTOs na koniec dnia.

Powodzenia!

 11
Author: Justin Ricketts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 23:48:31

Wydaje się, że Twoja aplikacja jest wystarczająco duża i złożona, ponieważ zdecydowałeś się przejść przez podejście DDD. Nie zwracaj encji poco ani tak zwanych encji domeny i obiektów wartości w warstwie usług. Jeśli chcesz to zrobić, usuń warstwę serwisową, ponieważ już jej nie potrzebujesz! Model widoku lub obiekty przesyłania danych powinny być aktywne w warstwie usług, ponieważ powinny mapować do członków modelu domeny i odwrotnie. Więc po co Ci DTO? W złożonej aplikacji z dużą ilością scenariusze powinieneś oddzielić obawy dotyczące domeny i widoków prezentacji, model domeny można podzielić na kilka DTO, a także kilka modeli domeny można zwinąć w DTO. Więc lepiej jest stworzyć DTO w architekturze warstwowej, nawet gdyby był taki sam jak twój model.

Czy zawsze powinniśmy używać DTOs do komunikacji z service layer? Tak, musisz zwrócić DTO przez warstwę usługową, ponieważ rozmawiasz z repozytorium w warstwie usług z modelem domeny członków i mapować je do DTO i wrócić do kontrolera MVC i vice versa.

Czy można dostosowywać modele domen w oparciu o potrzeby usług? Usługa po prostu rozmawia z metodami repozytoriów i domen oraz usługami domenowymi, powinieneś rozwiązać biznes w swojej domenie w oparciu o swoje potrzeby i nie jest to zadanie usługi, aby powiedzieć domenie, co jest potrzebne.

Jeśli powinniśmy ściśle trzymać się DTOs, to czy powinny one być zdefiniowane w warstwie usług? tak spróbuj mieć DTO lub ViewModel po prostu później w serwisie, ponieważ powinny być mapowane do domenowych członków w warstwie serwisowej i nie jest dobrym pomysłem umieszczanie DTO w kontrolerach Twojej aplikacji( spróbuj użyć wzorca Request Response w warstwie serwisowej), pozdrawiam!

 11
Author: Ehsan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-04 13:32:16

Jeśli zwrócisz część modelu domeny, staje się on częścią umowy. Umowa jest trudna do zmiany, ponieważ od niej zależą rzeczy spoza twojego kontekstu. W związku z tym utrudniłbyś zmianę części modelu domeny.

Bardzo ważnym aspektem modelu domeny jest to, że można go łatwo zmienić. Dzięki temu jesteśmy elastyczni wobec zmieniających się wymagań domeny.

 5
Author: Timo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-24 08:56:55

Spóźniony na imprezę, ale stoję przed dokładnie takim samym typem architektury i skłaniam się ku "tylko DTOs z serwisu". Dzieje się tak głównie dlatego, że zdecydowałem się używać tylko obiektów/agregatów domeny, aby utrzymać Ważność wewnątrz obiektu, a więc tylko podczas aktualizacji, tworzenia lub usuwania. Gdy pytamy o dane, używamy tylko EF jako repozytorium i mapujemy wynik do DTOs. Dzięki temu możemy optymalizować zapytania odczytu i nie dostosowywać ich do obiektów biznesowych, często korzystając z funkcji bazy danych jako są szybkie.

Każda metoda usługi definiuje swój własny kontrakt i dlatego jest łatwiejsza do utrzymania w czasie. Mam nadzieję.

 5
Author: Niklas Wulff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-17 17:56:39

Do tej pory używamy modeli domen (głównie encji) na wszystkich warstwach i używamy DTOs tylko jako modeli widoków(w kontrolerze usługa zwraca modele domen, a kontroler tworzy model widoku, który jest przekazywany do widoku).

Ponieważ model domeny dostarcza terminologii ( wszechobecny język) dla całej aplikacji, lepiej jest używać modelu domeny szeroko.

Jedynym powodem użycia ViewModels / DTOs jest implementacja wzorca MVC w Twoim aplikacja do oddzielenia View (dowolny rodzaj warstwy prezentacji) i Model (Model domeny). W tym przypadku Twoja prezentacja i model domeny są luźno powiązane.

Czasami usługa musi zwrócić obiekt danych, który nie został zdefiniowany w domenie, a następnie albo dodać nowy obiekt do domeny, która nie jest mapowana, albo utworzyć obiekt POCO (jest to brzydkie, ponieważ niektóre usługi zwracają modele domen, niektóre skutecznie zwracają DTOs).

Zakładam, że mówisz o Application / Business / Domain Logic services.

Proponuję zwrócić encje domeny, kiedy tylko możesz. Jeśli konieczne jest zwrócenie dodatkowych informacji, dopuszczalne jest zwrócenie DTO, które posiada kilka podmiotów domeny.

Czasami ludzie, którzy używają frameworków 3rd part, które generują proxy nad podmiotami domenowymi, napotykają trudności z ujawnieniem podmiotów domenowych z ich usług, ale jest to tylko kwestia niewłaściwego użycia.

Pytanie brzmi - jeśli ściśle używamy modeli widoku, czy można zwracać modele domen aż do kontrolerów, Czy zawsze powinniśmy używać DTOs do komunikacji z warstwą usług?

Powiedziałbym, że wystarczy zwrócić encje domeny w 99,9% przypadków.

Aby uprościć tworzenie DTOs i mapowanie do nich jednostek domeny, możesz użyć AutoMapper .

 4
Author: Ilya Palkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-01 13:02:46

Proponuję przeanalizować te dwa pytania:

  1. Czy twoje górne warstwy (np. modele / Kontrolery widoku i widoku) zużywają dane w inny sposób niż warstwa domeny? Jeśli robi się dużo mapowania lub nawet logiki, sugeruję ponowne przeanalizowanie twojego projektu: prawdopodobnie powinien być bliżej sposobu, w jaki dane są faktycznie używane.

  2. Jak prawdopodobne jest, że głęboko zmienisz swoje górne warstwy? (np. Zamiana ASP.NET dla WPF). Jeśli jest to wysoce w przeciwieństwie do i twoja Architektura nie jest bardzo złożona, możesz lepiej ujawnić tyle podmiotów domeny, ile możesz.

Obawiam się, że jest to dość szeroki temat i naprawdę sprowadza się do tego, jak skomplikowany jest Twój system i jego wymagania.

 2
Author: jnovo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-26 05:22:34

Z mojego doświadczenia wynika, że jeśli nie używasz wzorca oo UI (jak nagie obiekty), narażanie obiektów domeny na interfejs jest złym pomysłem. Dzieje się tak, ponieważ wraz z rozwojem aplikacji zmieniają się potrzeby interfejsu użytkownika i zmuszają obiekty do dostosowania tych zmian. W końcu obsługujesz 2 Mistrzów: interfejs użytkownika i domenę, co jest bardzo bolesnym doświadczeniem. Uwierz mi, nie chcesz tam być. Model UI ma funkcję komunikacji z użytkownikiem, model domeny do przechowywania reguł biznesowych i modele persistence zajmują się efektywnym przechowywaniem danych. Wszystkie one odnoszą się do różnych potrzeb aplikacji. Jestem w trakcie pisania posta na blogu o tym, dodam go, gdy to się skończy.

 1
Author: max_cervantes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-05 18:28:38