Gruby model / cienki kontroler a warstwa usługowa [zamknięte]

84

Od wielu lat zajmuję się tworzeniem aplikacji dla przedsiębiorstw przy użyciu .Net Moje aplikacje zwykle mają model domeny zawierający jednostki mapujące na tabele SQL DB. Używam wzorca repozytorium, iniekcji zależności i warstwy usług.

Niedawno rozpoczęliśmy pracę nad projektami MVC 3 i debatowaliśmy, gdzie umieścić jaką logikę. Natknąłem się na cienką architekturę kontrolera / modelu FAT i zastanawiałem się, jak będzie pasować warstwa usług

Opcja 1 - Model rozmawia z usługami

Kontroler jest cienki, wywołuje metody w modelach. Modele „wiedzą”, jak załadować się z bazy danych i rozmawiać z repozytoriami lub usługami. Np. CustomerModel ma metodę Load (id) i ładuje klienta oraz niektóre obiekty podrzędne, takie jak GetContracts ().

Opcja 2 - Kontroler rozmawia z usługami

Kontroler prosi usługi o pobranie obiektów modelu. Logika ładowania / przechowywania itp. Znajduje się w warstwie usług. Model jest czystym modelem encji z samymi danymi.

Dlaczego opcja 1 miałaby być lepszym wyborem, zwłaszcza gdy mówimy o zastosowaniach korporacyjnych, moje doświadczenie podpowiada mi, aby oddzielić obawy, utrzymywać modele ORAZ kontrolery tak cienkie, jak to tylko możliwe, i mieć wyspecjalizowane usługi obsługujące logikę biznesową (np. Interakcja z bazą danych)

Dzięki za wszystkie rady i odniesienia do dobrych zasobów.

PeterFromCologne
źródło

Odpowiedzi:

95

Wszystko to zależy od intencji i wymagań aplikacji.

To powiedziawszy, oto moja sugestia dotycząca aplikacji internetowych „średniej skali” (nie lokalnej restauracji ani Twittera / Facebooka).

  1. Modelowanie Lean Domain

    Suche obiekty w stylu POCO, najlepiej ignorujące architekturę MVC Twojej aplikacji internetowej, aby pozostać możliwie luźno powiązanym z konkretną implementacją. Być może nawet biblioteka klas z możliwością przepakowania do użycia w aplikacji zewnętrznej, na przykład API REST za pośrednictwem usługi sieci Web WCF ).

    „Model” w MVC najdokładniej oznacza model znany Kontrolerowi, a tym samym model przeznaczony dla Widoku .

    W mniejszych aplikacjach (często samouczków) modele jednostek w „warstwie modelu aplikacji / domeny” są często tymi samymi obiektami z instancją, które kontroler wysyła do widoku.

    W większych aplikacjach programiści często wykorzystują założenia architektury MVVM i zaczynają używać oddzielnych obiektów View Model. Kontrolery często wywołują usługi warstwy pośredniej, które współpracują z niewidocznymi jednostkami poniżej. W tym scenariuszu M w MVC najdokładniej oznacza model widoku.

  2. Solidna warstwa usług

    Nie oznacza to otyłej logiki, ale dobrze napisane usługi przeznaczone do jednego celu. Podczas gdy kodowanie logiki biznesowej w usługach poza modelem jest nieco bardziej „proceduralne” niż zwykłe „OOP”, bardzo pomaga przy luźnym sprzężeniu, testowaniu i elastycznym wdrażaniu (np. Wdrażanie n-warstwowe).

    W swojej osobistej praktyce koduję usługi zarówno w warstwie danych, co uważam za modelowanie behawioralne obiektów POCO (mechanika trwałości, walidacja niskiego poziomu itp.), Jak i usługi wyższego poziomu (funkcja biznesowa / przepływu pracy) mechanika MVC.

  3. Lean Controllers

    Upewniam się, że mój kontroler jest tylko trenerem , ponieważ nie jest ani grą (usługi), ani graczem (model bytu lub model widoku), ale po prostu decyduje, kto gra na jakiej pozycji i jaką zagrać. Moje kontrolery robią dwie rzeczy:

    1. Wywołaj usługi, które współdziałają z modelami jednostki / domeny

    2. Przygotuj model widoku dla odpowiedniego widoku.

    Nawet uwierzytelnione / autoryzowane akcje kontrolera są wykonywane przez wstrzyknięte usługi / atrybuty.


EDYCJA 1:

Należy pamiętać, że nie oznacza to, że model jednostki / domeny jest lub musi być anemiczny. Mile widziane są ORM, repozytoria i fabryki, walidacja lub mechanika stanu. Oznacza to tylko dla aplikacji o umiarkowanej skali, Model w MVC reprezentuje model przeznaczony dla kontrolera, który ma być przekazany do Twojego widoku .

Miejmy nadzieję, że ten punkt uspokoi apostołów Fowlera, którzy uważają anemiczny model danych za anty-wzór . W tym samym czasie, to nie odzwierciedlają kąt nieco bardziej proceduralne niż OOP, gdzie jest bardziej czysta obejmuje zachowanie w modelowanych klas.

Nie ma „ostatecznej prawdy”, ale korzystając z tego wzorca, łatwo będzie budować, testować i wdrażać swoje aplikacje - zachowując przy tym wiele możliwości ponownego użycia i skalowalności.


EDYCJA 2:

To powiedziawszy, nawet w przypadku aplikacji o niewielkich rozmiarach, nadmierna architektura (którą wymyślili słowo frajerzy?) Jest zbyt powszechna. Na przykład opakowanie ORM wzorcem repozytorium, a następnie napisanie usług do korzystania z repozytorium ... wszystko to jest dobre do oddzielenia problemów i tym podobnych, ale jeśli twój projekt nie wymaga (i jest mało prawdopodobne, że wkrótce będzie wymagał ) takie rzeczy, nie buduj tego. Nie ma nic złego w pomijaniu całego repozytorium, pisaniu cienkich usług biznesowych (np. Klas zapytań) na ORM, a nawet rozmowie z kontrolerem bezpośrednio. Wszystko zależy od skali.


EDYCJA 3:

Chciałem zauważyć, że to wyjaśnienie i rada dotyczą kontekstu architektury MVC po stronie serwera, takiej jak ASP.Net, a nie ram po stronie clenta, takich jak Knockout lub Backbone.

one.beat.consumer
źródło
11
Jest to prawie ten sam wzorzec projektowy, którego używam, z wyjątkiem tego, że kontroler nie ma wiedzy o repozytorium. Kontroler współdziała tylko z usługami, które z kolei współdziałają z repozytoriami.
Lester
2
@Lester Edytowałem, aby to wyjaśnić. W 95% przypadków moje też nie, idea jest taka, że ​​usługi to robią. W przypadku małych aplikacji może to być przesada, ale jest to dobra praktyka dla każdego i znacznie łatwiejsza w utrzymaniu dzięki kontenerowi IoC
one.beat.consumer
1
+1 @ one.beat.consumer: to jest to samo podejście, które przyjmuję w moich projektach ... czasami zbyt purystyczne podejście do zasad prowadzi do zbyt skomplikowanych rozwiązań i możesz doświadczyć więcej korzyści z prawdziwego, sprawdzonego rozwiązania, które nie idealnie podąża za wzorcami GOF
themarcuz
7
@ivowiblo Model w MVC to dowolny model danych, który kontroler przygotowuje i przekazuje do widoku. Dlatego twój „model aplikacji” (model domeny, warstwa modelu, cokolwiek-oznaczysz) może być całkowicie nieświadomy bibliotek MVC, a nawet istnieć poza twoim rozwiązaniem w oddzielnie rozproszonym systemie. W MVC żądanie jest po prostu kierowane do kontrolera. Sterownik montuje model widoku (dane dla warstwy prezentacji). Jeśli ten model to ten sam obiekt, którego instancja została użyta w mechanice trwałości, może to oznaczać kiepską praktykę, ale jest to dozwolone, co oznacza, że ​​nie ma wyłącznej definicji.
one.beat.consumer
2
+1 dla Pamiętaj „Model” w MVC najdokładniej oznacza model, którego Kontroler zna, a tym samym model przeznaczony dla Widoku.
Luiz Damim
16

Musisz dowiedzieć się więcej o MVC, zanim przejdziemy dalej i omówimy, gdzie umieścić wszystko. Cóż, jeśli chcesz podążać za wzorem. W przeciwnym razie możesz teraz przestać czytać.

Wzór jest bardzo luźno określony. Nic nie mówi, jak powinien wyglądać kontroler, widok lub model ani jak powinny być zbudowane. Wzorzec po prostu stwierdza, że ​​należy oddzielić części i jak powinny ze sobą współdziałać. Przyjrzyjmy się więc dokładniej, czym one są (moja interpretacja).

MVC

Model Model może być dowolny. Może to być usługa internetowa, repozytoria, klasy usług lub po prostu modele domeny. Model to wszystko, co jest używane, aby uzyskać potrzebne informacje. Traktuj „Model” jako warstwę zamiast pojedynczego obiektu.

Kontroler Kontroler to klej. Pobiera informacje z Modelu i dostosowuje je do widoku i odwrotnie.

Widok Widok powinien renderować tylko to, co widzi użytkownik.

Zwróć uwagę, że nie należy mylić modelu z modelami widoku. Microsoft naprawdę powinien był nazwać folder „Model” „ViewModels”, ponieważ tak właśnie jest. Nie użyłbym informacji z „Modelu” bezpośrednio w widokach. Niezastosowanie się do tego oznaczałoby, że będziesz musiał zmienić Model, jeśli Widok zostanie zmieniony i na odwrót.

Odpowiedź

Model nie jest modelem widoku, ale warstwą. Wszystko w modelu służy do pobierania informacji potrzebnych do widoku. Kontroler pobiera te informacje i umieszcza je w jednym modelu widoku.

Pojedyncza akcja kontrolera może używać jednego lub kilku wywołań „Modelu”, aby móc zebrać informacje wymagane przez widok.

Oznacza to, że druga opcja jest najbardziej odpowiednia, gdy chcesz uzyskać aplikację, która jest łatwa w utrzymaniu i rozszerzaniu.

Zwróć uwagę, że warstwa usług może nie być potrzebna. Możesz zadzwonić do OR / M bezpośrednio z kontrolerów. Ale jeśli zdarzy się, że powielasz kod lub otrzymujesz grube kontrolery, po prostu przenieś logikę do warstwy usług. Nic poza kontrolerem nie będzie miało wpływu na tę zmianę, ponieważ używasz odpowiednich modeli widoku.

jgauffin
źródło
3
Chciałbym, żeby zamiast tego nazwano ASP.NET MVC kontrolerem widoku ASP.NET ModelView. To byłaby okropna nazwa, ale przynajmniej przekazałaby jej prawdziwe znaczenie :)
Hector Correa
Zajęło mi trochę czasu, nawet po użyciu ASP.NET MVC, aby zdać sobie sprawę, że model nie oznaczał widoku modelu.
Lester
@ one.beat.consumer: Chodziło mi o to, że Model może być wszystkim. Tam jest tylko warstwa. Utwórz go tak, jak pasuje do aplikacji. Ujmę to w ten sposób, ponieważ tak wielu uważa, że ​​model w ASP.NET MVC jest modelem widoku lub że maszyna wirtualna i model są takie same.
jgauffin
Myślę, że odpowiadam na to pytanie. Moja interpretacja tego, customerModelo czym mówi w pytaniu, jest modelem widzenia. Jeśli zrozumie, że tak nie jest, odpowiedź jest bardziej oczywista.
jgauffin
2
Semantyka @jgauffin jest tutaj ważna - w MVC „model” nie oznacza „warstwy modelu”; to tylko oznacza, modelu obiektowego dopasowanie dla kontrolera przejść do widoku . W dużych aplikacjach architektura MVC często nawet nie jest świadoma istnienia warstwy modelu / danych ani tego, co wybierzesz, aby ją nazwać. Moja zredagowana odpowiedź próbuje wyjaśnić to zamieszanie ... głównie gdy aplikacje są małe, często nie ma potrzeby dodatkowego oddzielania modelu Model i View, więc ludzie mają tendencję do oznaczania swoich modeli i pozwalania kontrolerom na korzystanie z repozytorium itp. aplikacji pełnowymiarowych, rzadko się to zdarza.
one.beat.consumer
0

Opcja 1: Można by pomyśleć, że model == usługa. Model JEST również warstwą biznesową.

Opcja 2 to anty-wzór Anemic Domain Model. http://en.wikipedia.org/wiki/Anemic_domain_model

Imre L.
źródło
Pamiętaj, że nazywanie czegoś anty-wzorcem wymaga więcej kontekstu! Wiele aplikacji nie potrzebuje modelu domeny, ponieważ większość rzeczy, które robią, to operacje CRUD.
Rookian
Model domeny to tylko dane z „metadanymi”, jeśli nie masz metadanych, to dobrze. Usunąłem słowo „przeciw wzorowi”, ponieważ masz rację w tej części. Naprawdę podoba mi się zaakceptowana odpowiedź, a zamiast tego mój własny powinien być komentarz.
Imre L
0

Opcja 2 jest opisana jako architektura Fat Stupid Ugly Controllers ( odniesienie do autora tego wyrażenia ). To rozwiązanie jest generalnie sprzeczne z duchem MVC, ponieważ przerywa podział obaw.

Sergey Kudriavtsev
źródło
1
public ActionResult FetchApple() { return View(_groceryService.GetApple("Granny Smith")); }jest dość szczupła, jeśli o mnie chodzi.
one.beat.consumer
4
Moja lektura tego artykułu FSUC nie pasuje do opcji 2 powyżej. Przykład podany przez autora FSUC nie pokazuje zastosowania warstwy usług, w której cała logika porządkowania jest hermetyzowana. Zamiast tego pokazuje, że kontroler został załadowany logiką biznesową. A możliwość ponownego wykorzystania logiki biznesowej z racji przebywania w kontrolerze została utracona.
Marvo,