Obecnie czekam na książkę PoEAA ale, żeby mieć co robić zanim ją dostanę sporo czytałem o tym jak powinna wyglądać architektura projektu, głównie w .net core. W internecie jest pełno sprzecznych informacji, jeśli chodzi o repository pattern, podejście ddd itp. W tutorialach mieniących się nagłówkami: clean architecture, controllery są grube jak świnki, wykonują logikę, często nawet skomplikowaną itp. Przewertowałem również sporo wątków na tym forum, odnośnie dobrych praktyk itp. i doszedłem do czegoś takiego (schemat niżej), jeśli się mylę proszę poprawcie mnie ewentualnie nakierujcie co powinienem zmienić.
przykład nr 1. - bardzo uproszczona wypożyczalnia sklepu Web Api
Wypożyczalnia.Api
- Controllers -> do controllera wstrzykujemy implementacje serwisów - I___Services
- FilmController -> IFilmServices
- UseController -> IUserServices
Wypożyczalnia.Core
- Domain -> (domain classes, anemic-classes?), proste klasy z właściwościami, które zmapujemy na tabele i kolumny w bazie danych. Dodajemy adnotacje pomagające przy walidacji.
- Film -> public int Id { get; private set; } [Required]
- User
- Services -> logika aplikacji np. stworzenie konta, dodanie filmu, filtrowanie w tym przypadku to chyba prosty CRUD
- IFilmServices -> GetById(int id), ...
- IUserServices -> Create(UserDto user) vs Create(UserViewModel)?
Wypożyczalnia.Infrastructure
- DAL -> konfiguracja EF, NHibernate lub innego ORM'a
- AppDbContext
- MigrationHistory
- EntityConfigurations -> klasy z ustawieniami, nadpisanie domyślnych ustawień mapowania za pomocą EF Fluent Api
- Services -> implementujemy interfaces z Core
- FilmServices -> private readonly AppDbContext _context i bezpośrednio korzystamy z ORM'a bez tworzenia dodatkowej warstwy abstrakcji
- UserServices -> zwracamy np. UserDto, mapowanie odbywa się w services, żeby controller dostał Dto, nasz uproszczony model, bez zbędnych z punktu widzenia użytkownika właściwości
Wypożyczalnia.Tests
- UnitTests -> reference to Core
- E2ETests -> reference to Infrastructer
- Czy to jest dobrze rozplanowana architektura prostej aplikacji?
- Controller wysyła tylko żądanie do services i tam wykonujemy logikę a następnie otrzymujemy przetworzone dane, przez co metoda w controllerze ma zwykle 1 czasami do 3 linijek a sam controller o niczym nie wie, czy to jest dobre podejście i powinienem się go trzymać?
- W przypadku Api zwracamy Dto czy viewmodel czy to zależy od operacji? np. GetUser(id) zwróci UserDto po odpytaniu przez HTTP GET bo z tego co wiem nie powinienem przekazywać User, żeby nie ujawniać wewnętrznej implementacji, ale gdybym chciał pobrać listę użytkowników i ich filmów wtedy, muszę skorzystać z dwóch serwisów i ich wyniki - dwa Dtosy połączyć i to się chyba nazywa viewmodelem, czy w podejsciu z wykorzystaniem Api powinienem jakiś nowy Dto stworzyć zbudowany z 2 innych, mam nadzieję, że wiecie o co mi chodzi
- Czy konfigurację np. AutoMappera, Autofaca powinienem trzymać w Infrastructure?
- Jeśli np. chcę szyfrować hasła, to IEncrypter powinien być w Core i implementacja w Infrastructure czy interface i implementacja razem trzymane w Infrastructure?
- Podobne pytanie do powyższego np. Logger i inne usługi jeśli bym chciał dodać do projektu to ich interfaces mam w Core trzymać czy w Infrastructure razem z implementacją? Myśląc o tym chyba do drugiego rozwiązania bym się skłaniał bo Logger nie jest w żaden sposób powiązany z moją domeną to jest coś z zewnątrz dostarczane ale chcę zapytać bardziej doświadczonych.
- Odnośnie modelu i anemic-classes jak to ma wyglądać. Przykładowo User ma kolekcję wypożyczonych filmów i teraz trzymając się powyższej implementacji mam:
- zrobić anemic classes a w services dodać możliwości dodania filmu do list bądź usunięcia
- w klasie User stworzyć metody pozwalające na dodanie, usunięcie filmów włącznie z walidacją np. czy film który chcę usunąć jest wypożyczony itp.
Które podejście jest lepsze w zwykłym CURDzie? Druga opcja nie idzie w kierunku metodyki DDD?
- Walidacja np. czy są filmy na stanie w celu wypożyczenia? powinienem w services robić czy klasa powinna być wyposażona w odpowiednie metody?
- Jakie jest wasze podejście do walidacji w modelu (chodzi mi np. walidację formularza który zostanie wypełniony przez użytkownika)? Pisać metody czy korzystać z adnotacji?
- @somekind w którymś wątku pisałeś, żeby we własnych projektach zrezygnować z interfaces dla każdej klasy bo to nie ma sensu, w powyższym przykładzie powinienem, gdzieś z nich zrezygnować? Tworzę np. IEncrypter potem jego implementację z której korzysta poprzez DI jakiś serwis. Powinienem tak robić czy lepiej bez interfejsu?
Odnośnie pierwszego przykładu chyba już nie mam pytań. Drugie podejście, przykład będzie się tyczył DDD, jak będę miał chwilkę to zamieszczę na forum bo muszę jeszcze parę spraw odnośnie architektury i podejścia przemyśleć.
Mam nadzieję, że ktoś to wypracowanie przeczyta i będzie w stanie udzielić odpowiedzi :0
Od razu z góry dziękuję za pomoc i poświęcony czas.