Jedną z części projektu opartego na domenie, która wydaje się nie być zbyt szczegółowa, jest sposób i dlaczego należy izolować model domeny od interfejsu. Próbuję przekonać moich kolegów, że to dobra praktyka, ale nie wydaje mi się, aby robiłam duże postępy ...
W warstwach prezentacji i interfejsu używają jednostek domeny, gdziekolwiek chcą. Kiedy argumentuję, że powinni używać modeli wyświetlania lub DTO do izolowania warstwy domeny od warstwy interfejsu, odpowiadają, że nie widzą wartości biznesowej w zrobieniu czegoś takiego, ponieważ teraz masz obiekt interfejsu użytkownika do utrzymania a także oryginalny obiekt domeny.
Dlatego szukam konkretnych powodów, dla których mógłbym to potwierdzić. Konkretnie:
- Dlaczego nie powinniśmy używać obiektów domeny w naszej warstwie prezentacji?
(jeśli odpowiedź jest oczywista: „oddzielenie”, proszę wyjaśnić, dlaczego jest to ważne w tym kontekście) - Czy powinniśmy używać dodatkowych obiektów lub konstrukcji, aby odizolować nasze obiekty domeny od interfejsu?
design-patterns
architecture
domain-driven-design
presentation-layer
data-transfer-objects
Mark Rogers
źródło
źródło
Odpowiedzi:
Po prostu powodem jest implementacja i dryf. Tak, Twoja warstwa prezentacji musi wiedzieć o obiektach biznesowych, aby móc je poprawnie przedstawić. Tak, początkowo wygląda na to, że implementacja tych dwóch typów obiektów w dużym stopniu się pokrywa. Problem polega na tym, że w miarę upływu czasu sprawy są dodawane po obu stronach. Prezentacja zmienia się, a potrzeby warstwy prezentacji ewoluują i obejmują elementy całkowicie niezależne od warstwy biznesowej (na przykład kolor). W międzyczasie obiekty domeny zmieniają się w czasie, a jeśli nie masz odpowiedniego oddzielenia od interfejsu, ryzykujesz zepsucie warstwy interfejsu, wprowadzając pozornie łagodne zmiany w obiektach biznesowych.
Osobiście uważam, że najlepszym sposobem podejścia do rzeczy jest ściśle przestrzegany paradygmat interfejsu; oznacza to, że warstwa obiektu biznesowego udostępnia interfejs, który jest jedynym sposobem, w jaki można się z nią komunikować; żadne szczegóły implementacji (tj. obiekty domeny) dotyczące interfejsu nie są ujawniane. Tak, oznacza to, że musisz zaimplementować obiekty domeny w dwóch lokalizacjach; twoją warstwę interfejsu i twoją warstwę BO. Ale ta ponowna implementacja, chociaż początkowo może wydawać się dodatkową pracą, pomaga wyegzekwować oddzielenie, które pozwoli zaoszczędzić TONY pracy w pewnym momencie w przyszłości.
źródło
Sam się z tym zmagałem. Są przypadki, w których DTO ma sens w prezentacji. Powiedzmy, że chcę wyświetlić listę firm w moim systemie i potrzebuję ich identyfikatora, aby powiązać wartość.
Cóż, zamiast ładować CompanyObject, który może mieć odniesienia do subskrypcji lub kto wie, co jeszcze, mógłbym odesłać DTO z nazwą i identyfikatorem. To jest dobre zastosowanie IMHO.
Weźmy teraz inny przykład. Mam obiekt, który reprezentuje oszacowanie, to oszacowanie może składać się z robocizny, wyposażenia itp., Może mieć wiele obliczeń, które są zdefiniowane przez użytkownika, które biorą wszystkie te pozycje i podsumowują je (każde oszacowanie może być różne dla różnych typów obliczeń). Dlaczego powinienem dwukrotnie modelować ten obiekt? Dlaczego nie mogę po prostu wyliczyć mojego interfejsu użytkownika na obliczeniach i wyświetlić je?
Generalnie nie używam DTO do odizolowania warstwy domeny od interfejsu użytkownika. Używam ich do odizolowania warstwy domeny od granicy, która jest poza moją kontrolą. Pomysł, że ktoś umieści informacje nawigacyjne w swoim obiekcie biznesowym, jest śmieszny, nie zanieczyszczaj tego obiektu biznesowego.
Pomysł, że ktoś umieściłby walidację w swoim obiekcie biznesowym? Cóż, mówię, że to dobra rzecz. Twój interfejs użytkownika nie powinien odpowiadać wyłącznie za weryfikację obiektów biznesowych. Twoja warstwa biznesowa MUSI przeprowadzić własną walidację.
Dlaczego miałbyś umieścić kod generujący interfejs użytkownika w obiekcie busienss? W moim przypadku mam osobne obiekty, które generują kod UI oddzielnie od UI. Mam oddzielne obiekty, które renderują moje obiekty biznesowe w XML, pomysł, że musisz oddzielić warstwy, aby zapobiec tego typu zanieczyszczeniu, jest dla mnie tak obcy, ponieważ po co w ogóle umieszczać kod generujący HTML w obiekcie biznesowym ...
Edycja Myślę, że trochę więcej, ale są przypadki, w których informacje o interfejsie użytkownika mogą znajdować się w warstwie domeny. Może to spowodować zachmurzenie tego, co nazywasz warstwą domeny, ale pracowałem nad aplikacją dla wielu dzierżawców, która miała bardzo różne zachowanie, zarówno w wyglądzie, jak i funkcjonalnym przepływie pracy. W zależności od różnych czynników. W tym przypadku mieliśmy model domeny, który reprezentował dzierżawców i ich konfigurację. Ich konfiguracja zawierała informacje o interfejsie użytkownika (na przykład etykiety dla pól ogólnych).
Gdybym musiał zaprojektować moje obiekty tak, aby były trwałe, czy powinienem również powielić te obiekty? Pamiętaj, że jeśli chcesz dodać nowe pole, masz teraz dwa miejsca na dodanie go. Być może rodzi to kolejne pytanie, czy używasz DDD, czy wszystkie obiekty domeny utrwalonych jednostek? Wiem na moim przykładzie, że tak było.
źródło
Robisz to z tego samego powodu, dla którego nie dopuszczasz SQL do stron ASP / JSP.
Jeśli zachowasz tylko jeden obiekt domeny do użytku w warstwie prezentacji ORAZ domenie, ten jeden obiekt wkrótce stanie się monolityczny. Zaczyna zawierać kod weryfikacji interfejsu użytkownika, kod nawigacji interfejsu użytkownika i kod generowania interfejsu użytkownika. Następnie wkrótce dodasz do tego wszystkie metody warstwy biznesowej. Teraz twoja warstwa biznesowa i interfejs użytkownika są pomieszane, a wszystkie z nich bawią się w warstwie encji domeny.
Chcesz ponownie użyć tego fajnego widżetu interfejsu użytkownika w innej aplikacji? Cóż, musisz stworzyć bazę danych o tej nazwie, tych dwóch schematach i tych 18 tabelach. Musisz również skonfigurować Hibernate i Spring (lub wybrane frameworki), aby przeprowadzić weryfikację biznesową. Och, musisz również dołączyć te 85 innych niezwiązanych ze sobą klas, ponieważ są one przywoływane w warstwie biznesowej, która po prostu znajduje się w tym samym pliku.
źródło
Nie zgadzam się.
Myślę, że najlepszym sposobem jest rozpoczęcie od obiektów domeny w warstwie prezentacji, Póki nie ma sensu zrobić inaczej.
Wbrew powszechnemu przekonaniu „obiekty domeny” i „obiekty wartości” mogą szczęśliwie współistnieć w warstwie prezentacji. I to jest najlepszy sposób na zrobienie tego - uzyskujesz korzyści z obu światów, zmniejszoną liczbę duplikatów (i kodu standardowego) z obiektami domeny; oraz dostosowywanie i upraszczanie koncepcyjne używania obiektów wartości w żądaniach.
źródło
Odpowiedź zależy od skali Twojej aplikacji.
Prosta aplikacja CRUD (tworzenie, odczytywanie, aktualizowanie, usuwanie)
W przypadku podstawowych aplikacji Crud nie masz żadnych funkcji. Dodawanie DTO do obiektów byłoby stratą czasu. Zwiększyłoby to złożoność bez zwiększania skalowalności.
Umiarkowanie skomplikowana aplikacja Non-CRUD
W tej wielkości aplikacji będziesz mieć kilka jednostek, które mają rzeczywisty cykl życia i pewną logikę biznesową z nimi związaną.
Dodanie DTO w tym przypadku jest dobrym pomysłem z kilku powodów:
Skomplikowana aplikacja dla przedsiębiorstw
Pojedyncza jednostka może potrzebować wielu sposobów prezentacji. Każdy z nich będzie potrzebował innego zestawu pól. W takim przypadku napotkasz te same problemy, co w poprzednim przykładzie, a ponadto musisz kontrolować liczbę pól widocznych dla każdego klienta. Posiadanie oddzielnego DTO dla każdego klienta pomoże ci wybrać to, co powinno być widoczne.
źródło
Używamy tego samego modelu na serwerze i na interfejsie użytkownika. I to jest ból. Musimy to kiedyś naprawić.
Problemy wynikają głównie z tego, że model domeny musi zostać pocięty na mniejsze części, aby można było go serializować bez odwoływania się do całej bazy danych. To sprawia, że trudniej jest używać go na serwerze. Brakuje ważnych linków. Niektórych typów nie można również serializować i nie można ich wysłać do klienta. Na przykład „Typ” lub dowolna klasa ogólna. Muszą być nieogólne, a Type należy przesłać jako ciąg. Generuje to dodatkowe właściwości do serializacji, są one zbędne i mylące.
Innym problemem jest to, że jednostki w interfejsie użytkownika tak naprawdę nie pasują. Używamy wiązania danych, a wiele jednostek ma wiele nadmiarowych właściwości tylko do celów interfejsu użytkownika. Ponadto w modelu jednostki istnieje wiele „BrowsableAttribute” i innych. To jest naprawdę złe.
Na koniec myślę, że to tylko kwestia tego, która droga jest łatwiejsza. Mogą być projekty, w których po prostu działa dobrze i nie ma potrzeby pisania kolejnego modelu DTO.
źródło
W większości dotyczy zależności. Podstawowa struktura funkcjonalna organizacji ma swoje własne wymagania funkcjonalne, a interfejs użytkownika powinien umożliwiać ludziom modyfikowanie i przeglądanie rdzenia; ale sam rdzeń nie powinien być wymagany do dostosowania interfejsu użytkownika. (Jeśli zajdzie taka potrzeba, zwykle oznacza to, że rdzeń nie został zaprojektowany pod kątem właściwości).
Mój system księgowy ma strukturę i zawartość (oraz dane), które mają modelować działanie mojej firmy. Ta struktura jest prawdziwa i istnieje niezależnie od używanego przeze mnie oprogramowania księgowego. (Nieuchronnie dany pakiet oprogramowania zawiera strukturę i zawartość same w sobie, ale częścią wyzwania jest zminimalizowanie tego narzutu).
Zasadniczo osoba ma pracę do wykonania. DDD powinno odpowiadać przepływowi i treści zadania. DDD polega na jawnym przedstawianiu wszystkich prac, które muszą być wykonane, całkowicie i niezależnie, jak to tylko możliwe. Następnie, miejmy nadzieję, interfejs użytkownika ułatwi wykonanie zadania w możliwie najbardziej przejrzysty i produktywny sposób.
Interfejsy dotyczą danych wejściowych i widoków zapewnianych dla odpowiednio zamodelowanego i niezmiennego rdzenia funkcjonalnego.
źródło
Cholera, przysięgam , że to powiedział wytrwałość.
W każdym razie jest to jeszcze jeden przykład tego samego: prawo Parnasa mówi, że moduł powinien zachować tajemnicę, a sekret to wymóg, który może się zmienić. (Bob Martin ma regułę, która jest inną wersją tego). W takim systemie prezentacja może się zmieniać niezależnie od domeny . Na przykład firma, która utrzymuje ceny w euro i używa francuskiego w biurach, ale chce przedstawiać ceny w dolarach z tekstem w języku mandaryńskim. Domena jest taka sama; prezentacja może się zmienić. Tak więc, aby zminimalizować kruchość systemu - to znaczy liczbę rzeczy, które trzeba zmienić, aby wprowadzić zmianę w wymaganiach - oddzielasz obawy.
źródło
Twoja prezentacja może odnosić się do warstwy domeny, ale nie powinno być żadnego powiązania bezpośrednio z interfejsu użytkownika do obiektów domeny. Obiekty domeny nie są przeznaczone do użytku z interfejsem użytkownika, ponieważ często, jeśli są odpowiednio zaprojektowane, są oparte na zachowaniach, a nie na reprezentacjach danych. Pomiędzy interfejsem użytkownika a domeną powinna istnieć warstwa mapowania. MVVM lub MVP jest dobrym wzorem do tego. Jeśli spróbujesz bezpośrednio powiązać swój interfejs użytkownika z domeną, prawdopodobnie sprawisz sobie wiele bólu głowy. Mają dwa różne cele.
źródło
Być może nie konceptualizujesz warstwy interfejsu użytkownika w wystarczająco ogólny sposób. Pomyśl w kategoriach wielu form odpowiedzi (strony internetowe, odpowiedzi głosowe, drukowane listy itp.) Oraz pod kątem wielu języków (angielski, francuski itp.).
Przypuśćmy teraz, że silnik mowy systemu połączeń telefonicznych działa na zupełnie innym typie komputera (na przykład Mac) niż komputer, na którym działa strona internetowa (być może Windows).
Oczywiście łatwo wpaść w pułapkę „No cóż, w mojej firmie zależy nam tylko na angielskim, prowadzimy naszą stronę na LAMP (Linux, Apache, MySQL i PHP) i wszyscy używają tej samej wersji Firefoksa”. Ale co za 5 lub 10 lat?
źródło
Zobacz także sekcję „Propagacja danych między warstwami” poniżej, która moim zdaniem przedstawia istotne argumenty:
http://galaxy.andromda.org/docs/andromda-documentation/andromda-getting-started-java/java/index.html
źródło
Z pomocą narzędzia takiego jak „ Value Injecter” ” i koncepcji „Mappers” w warstwie prezentacji podczas pracy z widokami, zrozumienie każdego fragmentu kodu jest znacznie łatwiejsze. Jeśli masz trochę kodu, nie zobaczysz korzyści od razu, ale gdy Twój projekt będzie się rozwijał coraz bardziej, będziesz bardzo zadowolony z pracy z widokami, aby nie musieć wchodzić w logikę usług, repozytoria, aby zrozumieć model widoku. View Model to kolejny strażnik w rozległym świecie warstwy antykorupcyjnej i na wagę złota w długoterminowym projekcie.
Jedynym powodem, dla którego nie widzę korzyści z używania modelu widoku, jest to, że projekt jest mały i wystarczająco prosty, aby widoki były powiązane bezpośrednio z każdą właściwością modelu. Ale jeśli w przyszłości zmieni się wymaganie i niektóre elementy sterujące w widokach nie zostaną przypisane do modelu i nie masz koncepcji modelu widoku, zaczniesz dodawać łatki w wielu miejscach i zaczniesz mieć starszy kod, który nie docenisz. Jasne, możesz dokonać refaktoryzacji, aby przekształcić model widoku w model widoku i postępować zgodnie z zasadą YAGNI, nie dodając kodu, jeśli go nie potrzebujesz, ale dla mnie jest to o wiele bardziej najlepsza praktyka, którą muszę przestrzegać, aby dodać warstwa prezentacji odsłaniająca tylko obiekty modelu widoku.
źródło
Oto prawdziwy przykład, dlaczego uważam, że dobrą praktyką jest oddzielanie jednostek domeny od widoku.
Kilka miesięcy temu stworzyłem prosty interfejs użytkownika, aby pokazać wartości azotu, fosforu i potasu w próbce gleby za pomocą serii 3 mierników. Każdy miernik miał sekcję czerwoną, zieloną i czerwoną, tj. Można było mieć za mało lub za dużo każdego składnika, ale na środku znajdował się bezpieczny zielony poziom.
Bez większego zastanowienia wymodelowałem swoją logikę biznesową, aby dostarczyć dane dla tych 3 składników chemicznych i oddzielnego arkusza danych, zawierającego dane o akceptowanych poziomach w każdym z 3 przypadków (w tym, która jednostka miary była używana, tj. Mole lub procent). Następnie wymodelowałem swój interfejs użytkownika, aby użyć zupełnie innego modelu, ten model dotyczył etykiet mierników, wartości, wartości granicznych i kolorów.
Oznaczało to, że kiedy później musiałem pokazać 12 komponentów, po prostu zmapowałem dodatkowe dane do 12 nowych modeli widoku miernika i pojawiły się one na ekranie. Oznaczało to również, że mogłem łatwo ponownie użyć kontrolki miernika i wyświetlić inne zestawy danych.
Gdybym połączył te wskaźniki bezpośrednio z jednostkami domeny, nie miałbym żadnej z powyższych elastyczności, a wszelkie przyszłe modyfikacje byłyby bólem głowy. Napotkałem bardzo podobne problemy podczas modelowania kalendarzy w interfejsie użytkownika. Jeśli istnieje wymóg, aby spotkanie w kalendarzu zmieniło kolor na czerwony, gdy jest ponad 10 uczestników, logika biznesowa do obsługi tego powinna pozostać w warstwie biznesowej, a cały kalendarz w interfejsie użytkownika musi wiedzieć, że został poinstruowany, aby zmieni kolor na czerwony, nie powinien wiedzieć dlaczego.
źródło
Jedynym rozsądnym powodem dodania dodatkowego mapowania między semantyką uogólnioną a semantyką specyficzną dla domeny jest to, że masz (dostęp do) istniejącego zbioru kodu (i narzędzi), które są oparte na uogólnionej (ale dającej się odwzorować) semantyce odmiennej od semantyki domeny.
Projekty oparte na domenie działają najlepiej, gdy są używane w połączeniu z ortogonalnym zestawem funkcjonalnych struktur domeny (takich jak ORM, GUI, przepływ pracy itp.). Zawsze pamiętaj, że semantyka domeny musi być ujawniona tylko w sąsiedztwie warstwy zewnętrznej. Zwykle jest to front-end (GUI) i trwały back-end (RDBM, ORM). Wszelkie skutecznie zaprojektowane warstwy pośrednie mogą i powinny być niezmienne w domenie.
źródło