Podział projektu forum, sens i ewentualne poprawki

0

Szykuję się do nowego projektu, jakiegoś nieprzesadnie skomplikowanego forumowego CMSa w ASP.NET MVC i jestem na etapie organizacji projektów. Dotychczas wszystko zawierałem w jednym wielkim projekcie-matce i ewentualnie drugim z testami, niemniej jednak do CV juniora przydałoby się coś lepszego...

Więc forumowy CMS byłby oparty na następujących projektach (strzałki oznaczają referencje do danego projektu):

  • Infrastructure - rejestrowanie zależności dla DI, inicjalizacja bazy danych (w tym klasy z konfiguracjami Fluent API), logger, mapper
    -> Domain

  • App.Web - zwykły projekt ASP.NET MVC
    -> App.Services
    -> Infrastructure

  • App.Services - serwisy aplikacji, czyli albo odpowiedzialne za operacje ściśle webowe (typu odczyt pliku itp.) nienadające się na serwisy domenowe, albo wrappery na serwisy domene by kontrolery były jak najchudsze, dzięki czemu będzie można w banalny sposób wymienić je np. na WebAPI. Zawierają także ViewModele.
    -> Domain.Services

  • Domain.Services - serwisy operujące bezpośrednio na DbContextach i DbSetach (bez jako takich oddzielnych repozytoriów), a także obiekty DTO.
    -> Domain

  • Domain - wszystkie klasy POCO dla Entity Frameworka.

Przepływ wyglądałby następująco:
View (z jakimś wstrzykniętym ViewModelem) -> Controller (ViewModel) -> Serwis aplikacyjny (ViewModel na DTO) -> Serwis domenowy (DTO na POCO) -> DbContext

I w drugą stronę podobnie.

Teraz sekcja pytań:

  1. Czy taki podział ma sens? Wzoruję się na artykułach omawiających Onion Architecture, z drugiej strony nie chcę iść w DDD bo uważam że to trochę overkill dla forum które ma być projektem na GitHuba do pokazania, a nie konkurentem Coyote.

  2. W przypadku gdy nie chcę korzystać z jakichś własnych repozytoriów, a bezpośrednio wstrzykiwać DbContext czy tam DbSety, potrzebuję referencję do paczki EFa w dwóch projektach: Infrastructure (inicjalizacja, tu też byłyby implementacje repozytoriów gdyby... były :P) oraz właśnie w Domain.Services (gdzie gdybym wstrzykiwał własne repozytoria to dałoby się tego uniknąć). Rozumiem że ORMa raczej nigdy się nie zmienia, ale mimo wszystko nie wiem czy to nie zapowiedź jakichś problemów.

0

Lekka korekta projektu. Zaimplementowałem wyżej opisaną architekturę na przykładzie jednego serwisu i mam wrażenie że nadal jest to lekki overkill, już nie wspominając o tym że o ból serca przyprawia mnie Anemic Domain Model, który ponoć jest antywzorcem, i w ogóle programowanie proceduralne fuj. Stąd update:

Wyrzucony zostanie projekt App.Services - stwierdziłem że robienie adapterów dla realnych serwisów będzie męczące, a w zamian dostanę tylko niewiele chudsze kontrolery. Wniosek jest taki, że będzie trzeba tak napisać serwisy, by potem ewentualna zmiana projektu MVC na WebAPI była jak najmniej-bolesna (a planuję zrobić obie wersje i przy okazji nauczyć się jakiegoś Angulara, a nie że tylko Razor).

  • Infrastructure - rejestrowanie zależności dla DI, inicjalizacja bazy danych (w tym klasy z konfiguracjami Fluent API), logger, mapper, operacje na plikach.
    -> Domain
    -> Domain.Services

  • App.Web - zwykły projekt ASP.NET MVC z ViewModelami.
    -> Domain.Services
    -> Infrastructure

  • Domain.Services - serwisy operujące bezpośrednio na DbContextach i DbSetach (bez jako takich oddzielnych repozytoriów), a także obiekty DTO. Są to lekkie serwisy, mające jedynie za zadanie pobrać model, wywołać w nim akcję i zapisać. Opcjonalnie pobrać i zwrócić jako DTO, wiadomo.
    -> Domain

  • Domain - wszystkie klasy dla Entity Frameworka, w których będzie równocześnie większość logiki. Nie wprowadzam rozróżnienia między Persistent Model a Domain Model, ponieważ przerzuciłem masy artykułów i zrobienie tego w ładny sposób bez magicznych mapowań tak żeby zrozumiał to EF nie jest chyba prostą sprawą.

Przepływ wyglądałby następująco:
View (z jakimś wstrzykniętym ViewModelem) -> Controller (ViewModel na DTO) -> Serwis domenowy (DTO na DO) -> Pobranie i wykonanie akcji w modelu.

Jedyny problem widzę w umiejscowieniu klas odpowiedzialnych za jakąś autoryzację userów, ale to pewnie do infrastruktury się wrzuci i potem będzie injectowane do kontrolerów.

To nadal nie jest DDD i nie dążę do tego, ale pewne rzeczy z niego chcę wyciągnąć bo wydaje mi się interesującą koncepcją.

0

Czyli ADM Ci przeszkadza, ale mutowalna domena oblepiona szczegółami dostępu do danych już nie?

Trochę nie rozumiem, czemu Infrastructure ma mieć zależność od Domain, w każdym znanym mi projekcie jest odwrotnie. Ale to chyba przez to, że w ogóle nie rozumiem idei tego Infrastructure, z opisu wygląda, że tam będzie wszystko, pomieszanie konfiguracji aplikacji z warstwą dostępu do danych.
Czemu tam ma być rejestrowanie zależności? Każdy moduł powinien rejestrować swoje, a punkt startowy aplikacji powinien je wszystkie wczytać i zaaplikować.
Konfigurację EF wyrzuciłbym do warstwy dostępu do danych.
Jaki logger? Do tego są przecież gotowe biblioteki.
Jaki mapper? Nawet jeśli chcesz mapować ręcznie, to i tak powinieneś to robić w warstwie, która takich mapowań potrzebuje.

0

Przez te kilka dni trochę mi się pozmieniało i znowu zacząłem ładować logikę do serwisów (tj. głównie LINQ na DbSetach, w końcu forum to rasowy CRUD), natomiast modele EFowe zostawiłem jako klasy POCO (ewentualnie z małymi rzeczami typu: właściwość ModifyTime zmienia się automatycznie gdy zmieniona jest właściwość Content).

Ogólnie to myślałem czy nie zrobić tego jeszcze lepiej, i miec oddzielny Domain Model i Persisten Model (czyli te EFowe cuda), ale wtedy wypadałoby zrobić już jakieś Aggregate Rooty, repozytoria itp. To planuję na kolejny projekt, natomiast w tym chciałem zrobić jeszcze według tradycyjnego podejścia SOA.

Infrastructure z założenia miała taka być, tj. zawierać konfigurację jakichś DI, ORMa itp. Loggera faktycznie nie było potrzeby tam wrzucać, NLog czyta sobie z jakichś configów. Natomiast jeśli chodzi o mappery, to jest prawie tak jak piszesz, tj. każdy projekt ma jakąś klasę dziedziczącą po AutoFacowym Module i tam rejestruje zależności. Natomiast Infrastructure rejestruje te moduły i przekazuje do aplikacji startowej (ta dodatkowo musi jeszcze zarejestrować swoje kontrolery, podsumowując, nie wyszło to zbyt ładnie).

Z tego wszystkiego wynika, że brakuje mi jeszcze jakiegoś DAL, gdzie przerzuciłbym konfiguracje modeli EFa.

Jest jeszcze jednak koncepcja, tj. użyć obiekty DTO jako ViewModele, a walidację nie załatawić adnotacjami, tylko jakimś FluentValidator. Na pewno by kilka rzeczy uprościło, ale nie wiem na ile nie zrobiłoby to nowych problemów.

Anyway, dzięki za ocenę :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1