Czy „odwrócenie kontroli” promuje „model domeny anemicznej”?

32

Kiedy użyłem IoC Container w moim ostatnim projekcie, skończyłem z anemicznymi podmiotami i większością mojej logiki biznesowej w Stateless Services.

Widziałem projekty napisane przez innych programistów, które wykorzystują „Inversion of Control” i zawsze są one „anemiczne”.

Skoro „Anemic Domain Model” ma anty-wzorzec, czy można korzystać z IoC i Rich Domain? Czy są jakieś dobre przykłady, które to robią?

Mag20
źródło
Myślę, że powinniśmy zobaczyć konkretne przykłady Twojego konkretnego przypadku, aby pomóc.
Martijn Verburg
1
Przepraszam, miałem na myśli fragmenty kodu :)
Martijn Verburg

Odpowiedzi:

11

Na początek: DI i IoC nie są synonimami. Przykro mi, ale muszę to zaznaczyć (wydaje mi się, że tak myślisz).

Jeśli chodzi o twoje zapytanie ... Cóż, wstrzykiwanie zależności jest tylko narzędziem. Sposób korzystania z tego narzędzia jest całkowicie odrębną sprawą. Istnieją również inne narzędzia (wzorce projektowe), które mogą przyczynić się do rozwiązania problemu. Na przykład uważam, że szerokie zastosowanie wzorca MVC jest jednym z kluczowych składników w tworzeniu anty-wzorca Anemic Domain Model: kontrolery (w prostszych aplikacjach, w bardziej skomplikowanych, które byłyby dodatkową warstwą usług) przejmują odpowiedzialność za sprawdzanie reguł biznesowych , wymuszając je, a także przekształcając jednostki DB w coś użytecznego, podczas gdy warstwa biznesowa zamienia się w prostą warstwę dostępu do danych, która jest zwykłym ORM z mapowaniem jeden-do-jednego do jednostek bazy danych.

Z pewnością to sposób projektowania aplikacji - jeśli chcesz, możesz stworzyć poprawny model domeny, a wszystkie te IoC, DI, MVC Cię nie zatrzymują. To, co może Cię zatrzymać, to Twój zespół. Musisz w jakiś sposób przekonać ich, aby wybrali właściwą ścieżkę, co może być trudne, ponieważ wielu programistów nie ma silnego zaplecza architektonicznego.

Paweł Dyda
źródło
Dodam do tego, że być może mógłbyś rzucić okiem na podejście DDD popierane przez Erica Evansa i in.
Martijn Verburg
1
Przeczytałem książkę Erica Evansa. Jest dobry dla ogólnej metodologii i wszechobecnego języka, ale brakuje mu trochę przykładów z prawdziwego świata.
Mag20
Dzięki za wskazanie różnicy między DI i IoC. Myślę, że ten problem miał więcej wspólnego z IoC niż DI. Zmieniłem pytanie, aby to odzwierciedlić.
Mag20
Z mojego doświadczenia z DI ram / pojemników (Wiosna DI, CDI, Unity), to rzeczywiście nie powstrzyma cię od stworzenia „prawidłowego Domain Model”, co dla mnie oznacza, że deweloperzy nie powinna być ograniczana z użyciem prawdziwe (tzn Stateful) obiektów . Ale DI tak naprawdę tego nie obsługuje.
Rogério
8

Większość (jeśli nie wszystkie) aplikacji to mieszanka problemów związanych z infrastrukturą i domenami. Po osiągnięciu pewnego poziomu złożoności łatwiej będzie zarządzać, jeśli domena zostanie oddzielona od infrastruktury, dzięki czemu łatwiej będzie się zastanowić i będzie mogła rozwijać się niezależnie.

Oczywiście model domeny nadal musi komunikować się z resztą systemu i zwykle będzie to dotyczyło usług bezstanowych (które są częścią domeny), które mają problemy z infrastrukturą (takie jak dostęp do bazy danych). Używanie kontenera IoC nie usuwa tej zależności, przenosi jego konfigurację do oddzielnego obszaru - ponownie ułatwiając rozumowanie i utrzymanie.

Podmioty przechowują stan i powinny być odpowiedzialne za reguły biznesowe. Jeśli Twoje usługi wymuszają wszystkie niezmienniki i inne reguły biznesowe, prawdopodobnie logika jest w niewłaściwym miejscu.

Teraz, jeśli masz logikę we właściwych miejscach, a mimo to nadal masz do czynienia z usługami, które są niczym więcej niż owijaniem wokół elementów infrastruktury i podmiotów, które są tylko torbami nieruchomości, to jest bardzo prawdopodobne, że domena nie jest wystarczająco złożona, aby uzasadnić koszty własne modelu. Prawie wszystko, co przeczytasz o DDD, będzie zawierało oświadczenie, że tak naprawdę jest ono przeznaczone tylko dla złożonych domen, ale wydaje się, że zbyt często jest o tym zapominany.

FinnNk
źródło
7

Idź do źródła. Zacznij od fragmentu Fowlera w Anemic Domain Models . Jako przykład dobrej praktyki odwołuje się do projektu opartego na domenach Erica Evana. Kod źródłowy tego jest tutaj . Pobierz to.

Zauważ, że używa Inversion of Control (szukaj @Autowired) i ma klasy usług (BookingService) oraz klasy „procesów biznesowych” (np. ItineraryUpdater).

Oryginalny artykuł Fowlera rozpoczyna szlak do szukanego przykładu.

Jamie
źródło
Ta przykładowa aplikacja w rzeczywistości nie jest zgodna z DDD, jak opisano w książce. Konkretna sprzeczność z książką polega na tym, że całkowicie narusza ona pojęcie „infrastruktury”, ponieważ zawiera kod specyficzny dla domeny; na przykład VoyageRepositoryHibernateklasa, która została umieszczona w warstwie infrastruktury, ale w rzeczywistości zależy od warstwy domeny.
Rogério
Tak, książka mówi na stronie 73, że warstwa infrastruktury znajduje się „poniżej” warstwy domeny i „nie powinna mieć specjalnej wiedzy na temat obsługiwanej domeny”. To po prostu nigdy nie miało dla mnie sensu. Rozważ projekt, który ma dwie implementacje VoyageRepository: VoyageRepositoryHibernate i VoyageRepositoryJDBC. Ich wdrożenia są z konieczności bardzo różne i zależą od technologii. Czy należą one do warstwy domeny? Czy warstwa infrastruktury? W naszym kodzie, zgodnie z książką, robimy to wstecz: warstwa infrastruktury może odwoływać się do warstwy domeny, ale nie odwrotnie.
jamie
Należą do warstwy domenowej, tak. Implementacja oparta na JDBC zawiera kod SQL powiązany z tabelami i kolumnami w bazie danych aplikacji, które są specyficzne dla domeny. Umieszczenie dowolnego kodu specyficznego dla domeny lub aplikacji w warstwie infrastruktury jest po prostu błędne, ponieważ „kod infrastruktury” powinien być używany wyłącznie do rozwiązywania problemów technicznych i (najlepiej) może być w pełni wykorzystywany ponownie między różnymi aplikacjami i domenami. Rozwiązaniem problemu posiadania kodu „niskiego poziomu” (np. SQL) w warstwie domeny nie jest jego całkowite przeniesienie, ale wdrożenie go w oparciu o lepszą infrastrukturę, taką jak ORM.
Rogério,
Dla mnie wdrożenie save (MyDomainObject foo) jest kwestią czysto techniczną. YMMV.
jamie
Tylko jeśli nie prowadzi to do naruszenia podstawowej zasady architektury warstwowej: niższa warstwa nie może zależeć od wyższej warstwy. Tak więc, jeśli zaimplementowałeś save(foo)kod, który może ulec zmianie, gdy zmienia się model domeny (na przykład, jeśli dodawany jest nowy atrybut MyDomainObject), wówczas (z definicji) musi należeć do warstwy domeny; w przeciwnym razie nie możesz już mówić o „warstwach”.
Rogério,
7

czy można korzystać z IoC i Rich Domain? Czy są jakieś dobre przykłady, które to robią?

Zakładam, że masz na myśli DI zamiast IoC, a projekt, nad którym pracowałeś, wykorzystuje pojemnik DI, taki jak Spring. IoC ma dwa główne smaki: DI i wzór lokalizatora. Nie rozumiem, dlaczego wzór Lokalizatora powinien być problemem, więc skupmy się na DI.

Nie sądzę, żeby to było możliwe, a przynajmniej byłoby bardzo niepraktyczne. Głównym aspektem kontenerów DI jest to, że kontrolują tworzenie obiektów, gdy wstrzykują je innym („obiektom zarządzanym”). Zestaw zarządzanych obiektów, który żyje podczas uruchamiania projektów, jest niezależny od tego, które elementy domeny istnieją w projekcie, ale zależy od tego, w jaki sposób obiekty są okablowane i jakie zakresy (singleton, prototyp) są do nich przypisane.

Dlatego nie chcesz, aby kontener DI zarządzał obiektami domeny. Ale jeśli tworzysz obiekty ręcznie (z nowym), nie możesz wstrzykiwać innych obiektów do obiektów domeny. (Pozostawiając potencjalne obejścia z ręcznym okablowaniem na bok.) Ponieważ te zastrzyki są potrzebne do zastąpienia implementacji innymi, nie można zastąpić funkcjonalności bogatych obiektów domeny za pomocą DI. W związku z tym nie będziesz chciał umieszczać funkcji w obiektach domeny lub utracisz funkcje DI.

Nie rozumiem, jak mógłby działać hipotetyczny kontener DI, który nie zarządza twoimi obiektami, i żadna z istniejących implementacji na to nie pozwala. Można więc śmiało twierdzić, że DI polega na zarządzaniu obiektami. Dlatego zawsze kusi cię do podzielenia potencjalnych obiektów Rich Domain na jedną klasę anemiczną i jedną lub kilka klas skryptów transakcyjnych.

Wolfgang
źródło
Ta odpowiedź naprawdę uderza w głowę, jeśli chodzi o napięcie między bogatym modelem domeny a wstrzykiwaniem zależności.
jrahhali,