Onion Architecture - problemy ze zrozumieniem

0

Cześć, przyznaję, że mam problem ze zrozumieniem co daje nam Onion Architeture.
W teorii wiem, że :

  • Powiązania zmierzają do środka
  • Nie ma powiązań w wewnętrznych warstwach z zewnętrznymi
  • Wszystko jest oparte na modelu domenowym
  • Wszystko jest połączone interfejsami

i wiele więcej.

To co widzę i "czuję" to, że projekt jest schludniejszy (programuję głównie w c#) wszystko ma swoje miejsce. Jednak nie rozumiem przewagi umieszczenia połączenia z bazą na zewnątrz okręgu. W przypadku UI to ma jak najbardziej sens, bo pewnego dnia zamiast wyświetlać dane w konsoli możemy chcieć to robić na stronie www.
Ale baza? Jasne, zgodnie ze sztuką to co zmieniane a raczej wymieniane jest najczęściej ląduje na zewnątrz.
Mocno upraszczajac, obecne zależności w projekcie webowym wyglądałyby tak:
Web Api/Infrastucture (czyli połączenie z bazą) -> Application -> Domain Service -> Domain Model
Komunikacja przy użyciu interfejsów a implementacja jest schowana przy użyciu abstrakcji. Co jest super, ale nie jest ściśle powiązane z Onion Architecture tylko jednak dobrymi praktykami w programowaniu.
Czyli dana warstwa udostępnai interfejs dla warstwy zewnętrznej, która go implementuje, czyli w .Net za pomocą Dependency Injection możemy sobie to fajnie ograć. Innymi słowy warstwa applikacji nie wie czy się łączy z mssql/mogno etc.
Wszystko super i działa, ale nie rozumiem jednego. Jaką daję nam to przewagę? A konkretnie chodzi mi o Infrastructurę na zewnątrz a nie gdzieś w środku?

mała dygresja
Jasne, jeśli umieścilibyśmy bazę w środku, to zmiana przeszła by przez wszystkie warstwy (na zewnątrz) co mogłoby prowadzić do niepotrzebnych zmian, bo np. domena nie może i nie powinna zależeć od infrastuktury.

Jasne podział na warstwy jest super i przy tym zostańmy, bardziej mi chodzi jak te warstwy wyglądają a dokładniej, gdzie się znajdują.
To, że Baza danych będzię na zewnątrz pozwala nam ją łatwo zastąpić. Ale jeżeli programujemy zgodnie z dobrymi praktykami to dostęp do bazy danych i tak będzie ukryty za interfejsem. Czy jeżeli zmieni się jego implementacja to warstwa czy już konkretna klasa będzie korzystała z interfejsu a kontener DI nam wstrzyknie co potrzebujemy.

Zatem, czemu podział na warstwy jest taki:
Web Api/Infrastucture (czyli połączenie z bazą) -> Application -> Domain Service -> Domain Model

A nie np. taki:
Web Api-> Application -> Infrastructure -> Domain Model ?

W przypadku .Net to jedna przewaga jaką widzę to taka, że Application dociągnie zależność z infrastructure (skoro z niego korzysta). Jeżeli zmienię bazę danych i nawet zacznę zapisywać do pliku, to i tak mam to ukryte pod interfejsem.
Ale może ktoś mi tutaj jakoś lepiej wyjaśni, bo przyznaję, że nie mogę sobie tego dobrze w głowie ułożyć. Z góry dzięki ;)

6

Idąc twoim tokiem myślenia wszystko można wrzucić do jednego projektu i dzielić folderami, np.

MyWebApp.csproj

  • API
  • Domain
  • Application
  • Persistence

i używać wszędzie interfejsów i będzie działać i będziesz mógł wymieniać implementacje bo używasz interfejsów. Ok. Nie mówiąc że wymiana bazy danych albo ORMa jest łatwa tylko w teorii i w blog postach traktujących o architekturze. W rzeczywistości jest to dramat, nawet jak używa się architektur Clean/Onion/Hexagonal.

Biorąc przykład z .NET jeśli solucja w VS ma następującą strukturę:

MyWebApp.sln

  • MyWebApp.API.csproj
  • MyWebApp.Domain.csproj
  • MyWebApp.Application.csproj
  • MyWebApp.Persistence.csproj
  • MyWebApp.CompositionRoot.csproj

i referencje pomiędzy projekatmi/warstwami idą do domeny to wtedy nie ma możliwości, że moja warstwa API ma dostęp do szczegółów implementacyjnych warstwy persystencji. Jedyny sposób w jaki mogę używać warstwy persystencji w API to wywołując odpowiednią metodę serwisu aplikacyjnego MyWebApp.Application, który ukrywa przed aplikacją to w jaki sposób działa baza danych, połączenie z kolejką, wywołania zewnętrznych serwisów, itd. A dlaczego tak jest? Bo API nie ma bezpośredniej referencji do dll-ki MyWebApp.Persistence.dll. Podobnie jest z referencją MyWebApp.Application.dll do MyWebApp.Persistence.dll - po prostu jej tam nie ma. W Onion/Clean/Hexagonal Architecture interfejs taki jak Repository siedzi w warstwie dziedzinowej (domain) a jego implementacja w warstwie persystencji. I to jest powód dla którego moje warstwy API i aplikacji nie mają dostępu do obiektów warstwy persystencji bo nie ma pomiedzy nimi bezpośredniej zależności, "współdzielą" jedynie interfejs, który jest w centralnym punkcie aplikacji - dziedzinie.

3
kenik napisał(a):i połączenie z bazą) -> Application -> Domain Service -> Domain Model

A nie np. taki:
Web Api-> Application -> Infrastructure -> Domain Model ?

Nie wiem, czy dobrze rozumiem strzałki ale w tym przypadku każda zmiana w infra pociąga za sobą zmiany w logice biznesowej. W onion chodzi o to, żeby te rzeczy było maksymalnie odseparowane, żebyś mógł zmieniać implementację w infra jak chcesz. Logika jest królem i zmiana w infra przy zachowanym interfejsie nie powinna pociągać zmiany w domenie. Dodatkowo taka separacja pozwala na używanie infry w lepszy sposób np. możesz otoczyć bazodanowe Repository przy pomocy Repository używającego redisa. Gdy infra i domena jest odzielonna to takie składanie jest bardzo proste

Same warstwy są bez znaczenia. Jeśli nie masz warstw ale wszystkie interfejsy i zależności są jak należy to i tak jest ok: można powiedzieć, że masz wartwy ale takie wynikające z topologi kodu a nie sztywnego podziału.

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