Projektuję (re) dużą aplikację, używamy architektury wielowarstwowej opartej na DDD.
Mamy MVC z warstwą danych (implementacja repozytoriów), warstwą domenową (definicja modelu domeny i interfejsów - repozytoria, usługi, jednostka pracy), warstwą usługową (implementacja usług). Do tej pory używamy modeli domenowych (głównie encji) na wszystkich warstwach, a DTO używamy tylko jako modeli widoku (w kontrolerze usługa zwraca model (y) domeny, a kontroler tworzy model widoku, który jest przekazywany do widoku).
Czytałem niezliczone artykuły o używaniu, nieużywaniu, mapowaniu i przekazywaniu DTO. Rozumiem, że nie ma żadnej ostatecznej odpowiedzi, ale nie jestem pewien, czy jest to w porządku, czy nie zwracam modeli domeny z usług do kontrolerów. Jeśli zwracam model domeny, nadal nie jest on przekazywany do widoku, ponieważ kontroler zawsze tworzy model widoku specyficzny dla widoku - w tym przypadku wydaje się to uzasadnione. Z drugiej strony nie wydaje się dobrze, gdy model domeny opuszcza warstwę biznesową (warstwę usług). Czasami usługa musi zwrócić obiekt danych, który nie został zdefiniowany w domenie, a następnie 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 domeny, niektóre skutecznie zwrócić DTO).
Pytanie brzmi - jeśli ściśle używamy modeli widoku, czy można zwracać modele domeny aż do kontrolerów, czy też powinniśmy zawsze używać DTO do komunikacji z warstwą usług? Jeśli tak, czy można dostosować modele domen w oparciu o potrzebne usługi? (Szczerze mówiąc, nie sądzę, ponieważ usługi powinny zużywać to, co ma domena.) Jeśli powinniśmy ściśle trzymać się DTO, czy powinny być zdefiniowane w warstwie usług? (Myślę, że tak.) Czasami jest jasne, że powinniśmy używać DTO (np. Gdy usługa wykonuje dużo logiki biznesowej i tworzy nowe obiekty), czasami jest jasne, że powinniśmy używać tylko modeli domeny (np. Gdy usługa członkostwa zwraca anemiczny użytkownik ( s) - wydaje się, że nie miałoby sensu tworzenie DTO, które jest takie samo jak model domeny) - ale wolę spójność i dobre praktyki.
Artykuł Domena vs DTO vs ViewModel - jak i kiedy ich używać? (a także kilka innych artykułów) jest bardzo podobny do mojego problemu, ale nie zawiera odpowiedzi na to pytanie (a). Artykuł Czy za pomocą EF należy implementować DTO we wzorcu repozytorium? jest również podobny, ale nie dotyczy DDD.
Zastrzeżenie: nie zamierzam używać żadnego wzorca projektowego tylko dlatego, że istnieje i jest fantazyjny, z drugiej strony chciałbym używać dobrych wzorców i praktyk projektowych również dlatego, że pomaga projektować aplikację jako całość, pomaga w oddzieleniu obaw, nawet jeśli używanie określonego wzorca nie jest „konieczne”, przynajmniej w tej chwili.
Jak zawsze dziękuję.
źródło
Odpowiedzi:
Sprawia, że czujesz, że wyciągasz flaki, prawda? Według Martina Fowlera: warstwa usług definiuje granice aplikacji, hermetyzuje domenę. Innymi słowy, chroni domenę.
Czy możesz podać przykład tego obiektu danych?
Tak, ponieważ odpowiedź jest częścią Twojej warstwy usług. Jeśli jest zdefiniowane „gdzie indziej”, wówczas warstwa usług musi odnosić się do tego „gdzie indziej”, dodając nową warstwę do twojej lasagne.
DTO jest obiektem odpowiedzi / żądania, ma sens, jeśli używasz go do komunikacji. Jeśli używasz modeli domeny w warstwie prezentacji (MVC-Controllers / View, WebForms, ConsoleApp), wówczas warstwa prezentacji jest ściśle powiązana z Twoją domeną, wszelkie zmiany w domenie wymagają zmiany kontrolerów.
Jest to jedna z wad DTO dla nowych oczu. W tej chwili myślisz o powielaniu kodu , ale w miarę rozwoju projektu miałoby to znacznie większy sens, szczególnie w środowisku zespołowym, w którym różne zespoły są przypisane do różnych warstw.
DTO może zwiększyć złożoność aplikacji, ale tak samo jak warstwy. DTO to kosztowna funkcja twojego systemu, nie są one darmowe.
Dlaczego warto korzystać z DTO
Ten artykuł przedstawia zarówno zalety, jak i wady korzystania z DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html
Podsumowanie w następujący sposób:
Kiedy użyć
Kiedy nie używać
Argumenty przeciwko DTO
Argumenty z DTO
źródło
Wygląda na to, że Twoja aplikacja jest wystarczająco duża i złożona, ponieważ zdecydowałeś się przejść przez podejście DDD. Nie zwracaj swoich jednostek poco ani tak zwanych jednostek domeny i obiektów wartości w warstwie usług. Jeśli chcesz to zrobić, usuń warstwę usług, ponieważ już jej nie potrzebujesz! Obiekty widoku modelu lub transferu danych powinny znajdować się w warstwie usług, ponieważ powinny być mapowane na elementy składowe modelu domeny i odwrotnie. Dlaczego więc musisz mieć DTO? W złożonych aplikacjach z wieloma scenariuszami należy oddzielić zagadnienia dotyczące domeny i widoków prezentacji, model domeny można podzielić na kilka DTO, a także kilka modeli domen można zwinąć w DTO. Dlatego lepiej jest utworzyć DTO w architekturze warstwowej, nawet jeśli byłby taki sam jak model.
Czy zawsze powinniśmy używać DTO do komunikacji z warstwą usług? Tak, musisz zwrócić DTO przez swoją warstwę usług, ponieważ rozmawiasz ze swoim repozytorium w warstwie usług z członkami modelu domeny i mapujesz je na DTO i wracasz do kontrolera MVC i odwrotnie.
Czy można dostosowywać modele domen na podstawie potrzebnych usług? Usługa polega tylko na rozmowie z repozytorium i metodami domeny oraz usługami domenowymi. Powinieneś rozwiązać działalność w swojej domenie w oparciu o swoje potrzeby, a zadaniem usługi nie jest informowanie domeny, co jest potrzebne.
Jeśli powinniśmy ściśle trzymać się DTO, czy powinny być zdefiniowane w warstwie usługowej? Tak, spróbuj później uruchomić DTO lub ViewModel, ponieważ powinny być one mapowane na członków domeny w warstwie usług i nie jest dobrym pomysłem umieszczanie DTO w kontrolerach aplikacji (spróbuj użyć wzorca Request Response w warstwie Service), pozdrawiam !
źródło
Z mojego doświadczenia wynika, że powinieneś robić to, co praktyczne. „Najlepszy projekt to najprostszy projekt, który działa” - Einstein. Mając to na uwadze ...
Absolutnie w porządku! Jeśli masz jednostki domeny, DTO i modele widoków, to włączając tabele bazy danych, wszystkie pola w aplikacji są powtórzone w 4 miejscach. Pracowałem nad dużymi projektami, w których encje domeny i modele widoków działały dobrze. Jedynym wyjątkiem jest sytuacja, gdy aplikacja jest rozproszona, a warstwa usług znajduje się na innym serwerze, w którym to przypadku DTO są wymagane do wysyłania przez sieć ze względu na serializację.
Generalnie zgodziłbym się i powiedziałbym nie, ponieważ model domeny jest zazwyczaj odzwierciedleniem logiki biznesowej i zwykle nie jest kształtowany przez konsumenta tej logiki.
Jeśli zdecydujesz się z nich skorzystać, zgodzę się i powiem, że tak, warstwa usług jest idealnym miejscem, ponieważ pod koniec dnia zwraca DTO.
Powodzenia!
źródło
Spóźniłem się na to przyjęcie, ale jest to tak powszechne i ważne pytanie, że czułem się zmuszony do odpowiedzi.
Przez „usługi” masz na myśli „warstwę aplikacji” opisaną przez Evana w niebieskiej książce ? Ja zakładam, że zrobić, w tym przypadku odpowiedź brzmi, że powinny one nie powrócić DTOs. Proponuję przeczytać rozdział 4 w niebieskiej książce, zatytułowany „Isolating the Domain”.
W tym rozdziale Evans mówi o warstwach:
Jest ku temu dobry powód. Jeśli użyjesz koncepcji częściowego porządku jako miary złożoności oprogramowania, wtedy posiadanie warstwy zależy od warstwy nad nią, co zwiększa złożoność, co zmniejsza łatwość konserwacji.
Odnosząc się do twojego pytania, DTO to w rzeczywistości adapter, który jest przedmiotem zainteresowania 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ż, że DTO jest częścią warstwy usług, chociaż niekoniecznie mówi w języku DDD).
Jeśli twoja warstwa aplikacji zależy od tych DTO, zależy to od warstwy nad nią, a twoja złożoność wzrasta. Mogę zagwarantować, że zwiększy to trudność w utrzymaniu oprogramowania.
Na przykład, co się stanie, jeśli Twój system będzie współpracował z kilkoma innymi systemami lub typami klientów, z których każdy wymaga własnego DTO? Skąd wiesz, która DTO metoda Twojej usługi aplikacji powinna zwrócić? Jak byś rozwiązał ten problem, jeśli wybrany przez ciebie język nie pozwala na przeciążanie metody (w tym przypadku metody serwisowej) opartej na typie zwracanym? A nawet jeśli znajdziesz sposób, po co naruszać warstwę aplikacji, aby wspierać problem związany z warstwą prezentacji?
W praktyce jest to krok w dół na drodze, która zakończy się architekturą spaghetti. Widziałem tego rodzaju decentralizację i jej rezultaty na podstawie własnego doświadczenia.
Tam, 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 znajduje się pod nią. Ponadto ta zależność jest zminimalizowana do typu zależności „tylko odwołanie”, ponieważ:
a) Warstwa interfejsu może uzyskać dostęp do tych obiektów domeny tylko jako wartości zwracane tylko do odczytu, uzyskane przez wywołania warstwy aplikacji
b) metody na usługach w Warstwie Aplikacji akceptują jako dane wejściowe tylko „surowe” dane wejściowe (wartości danych) lub parametry obiektów (w celu zmniejszenia liczby parametrów w razie potrzeby) 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 obiektów domeny na DTO. Ponownie, to sprawia, że DTO skupia się na byciu adapterami kontrolowanymi przez warstwę interfejsu.
źródło
Spóźniłem się na imprezę, ale mam dokładnie ten sam typ architektury i skłaniam się ku „tylko DTO z serwisu”. Dzieje się tak głównie dlatego, że zdecydowałem się używać tylko obiektów / agregatów domeny, aby zachować ważność w obrębie obiektu, a więc tylko podczas aktualizacji, tworzenia lub usuwania. Kiedy wysyłamy zapytania o dane, używamy EF jako repozytorium i mapujemy wynik na DTO. Dzięki temu możemy swobodnie optymalizować zapytania odczytu i nie dostosowywać ich do obiektów biznesowych, często korzystając z funkcji bazy danych, ponieważ są one szybkie.
Każda metoda obsługi definiuje własną umowę i dlatego jest łatwiejsza do utrzymania w czasie. Mam nadzieję.
źródło
Ponieważ model domeny zapewnia terminologię ( język wszechobecny ) dla całej aplikacji, lepiej jest szeroko używać modelu domeny.
Jedynym powodem używania ViewModels / DTO jest implementacja wzorca MVC w Twojej aplikacji w celu oddzielenia
View
(dowolnego rodzaju warstwy prezentacji) iModel
(Model domeny). W takim przypadku prezentacja i model domeny są luźno powiązane.Zakładam, że mówisz o usługach Application / Business / Domain Logic.
Proponuję zwrócić jednostki domeny, kiedy tylko możesz. Jeśli konieczne jest zwrócenie dodatkowych informacji, można zwrócić DTO, który zawiera kilka jednostek domeny.
Czasami osoby, które używają frameworków trzeciej części, które generują proxy dla jednostek domeny, napotykają trudności w ujawnianiu jednostek domeny z ich usług, ale jest to tylko kwestia niewłaściwego użycia.
Powiedziałbym, że w 99,9% przypadków wystarczy zwrócić podmioty domeny.
Aby uprościć tworzenie DTO i mapowanie do nich jednostek domeny, możesz użyć AutoMapper .
źródło
Jeśli zwrócisz część modelu domeny, stanie się on częścią umowy. Kontrakt jest trudny do zmiany, ponieważ zależą od niego rzeczy poza twoim kontekstem. W związku z tym utrudniłoby to zmianę części modelu domeny.
Bardzo ważnym aspektem modelu domeny jest to, że można go łatwo zmienić. To sprawia, że jesteśmy elastyczni wobec zmieniających się wymagań domeny.
źródło
Proponuję przeanalizować te dwa pytania:
Czy Twoje wyższe warstwy (tj. Wyświetlaj i przeglądaj modele / kontrolery) zużywają dane w inny sposób niż warstwa domeny? Jeśli jest dużo mapowania lub nawet logiki, zasugeruję zrewidowanie twojego projektu: prawdopodobnie powinno być bliżej sposobu, w jaki dane są faktycznie wykorzystywane.
Jakie jest prawdopodobieństwo, że głęboko zmienisz swoje górne warstwy? (np. zamiana ASP.NET na WPF). Jeśli jest to bardzo odmienne, a Twoja architektura nie jest zbyt złożona, może być lepiej, jeśli ujawnisz jak najwięcej jednostek domeny.
Obawiam się, że jest to dość obszerny temat i tak naprawdę sprowadza się do tego, jak złożony jest Twój system i jakie są jego wymagania.
źródło
Z mojego doświadczenia wynika, że jeśli nie używasz wzorca OO UI (jak nagie obiekty), ujawnianie obiektów domeny w interfejsie użytkownika jest złym pomysłem. Dzieje się tak, ponieważ wraz z rozwojem aplikacji potrzeby z interfejsu użytkownika zmieniają się i wymuszają na obiektach dostosowanie się do tych zmian. W końcu służysz 2 mistrzom: UI i DOMENA, co jest bardzo bolesnym doświadczeniem. Uwierz mi, nie chcesz tam być. Model UI ma funkcję komunikacji z użytkownikiem, model DOMAIN do przechowywania reguł biznesowych, a modele trwałości zajmują się efektywnym przechowywaniem danych. Wszystkie odpowiadają różnym potrzebom aplikacji. Jestem w trakcie pisania wpisu na blogu na ten temat, dodam go, gdy będzie gotowy.
źródło