Przejdź do treści

Architektura warstwowa. Zło czy dobro? 🤔

Architektura warstwowa – zło konieczne a może optymalne rozwiązanie? Pewne jest jedno – jest to najpopularniejszy styl architektoniczny wśród developerów. Często (niestety) jedyny jaki znamy.


Cześć 🙂

Każdy z nas używał architektury warstwowej, czy to przechodząć przez tutorial w sieci czy implementując aplikacje komercyjne lub niekomercyjne. Jest ona na tyle popularna, że aż bardzo często użyta tam gdzie wcale nie sprawdza się najlepiej. Niemniej jednak, nie chcę żeby ten artykuł szedł w stronę, że architektura warstwowa jest złem. Absolutnie nie! Będąc świadomym programistą powinniśmy umieć dobrać odpowiednią architekturę do problemu jaki jest przed nami (i naszym zespołem!).

W dzisiejszym artykule:


Czym jest architektura warstwowa?

Na początku musimy zacząć w ogóle od wyjaśnienia czym jest architektura warstwowa. Jeżeli jeteś programistą (a zakładam, że jesteś) to na 100% już się z nią spotkałeś. W teorii zakłada ona podział strukturalny projektu na kilka warstw. W wielu przypadkach będą to głównie 3 warstwy: prezentacji, logiki oraz persystencji. Aczkolwiek nie ma problemu żeby warstw było 5 lub 2.

Żebyś mógł to sobie lepiej zobrazować to te 3 warstwy przyrównam do typowej aplikacji pisanej w springu:

    • warstwa prezentacji = kontrolery,
    • warstwa logiki = serwisy,
    • warstwa persystencji = repozytoria.

Architektura warstwowa ma dwa fundamentalne założenia:

    1. każda warstwa jest odseparowana od siebie – wykonuje tylko tą pracę do której została stworzona.
    2. komunikacja jest kierowana od góry do dołu (warstwa prezentacji wykorzystuję logikę a ta persystencję)
Obrazek pochodzi z kursu DNA

Pomimo, że zasada numer dwa, która mówi iż komunikacja jest kierowana od góry do dołu może sugerować wprowadzenie zależności pomiędzy warstwami to takie myślenie nie jest poprawne. Warstwy są od siebie niezależne. Są one tylko powiązane (wywołanie warstwy niższej przez warstwę wyższą) ale nie należy mylić tego z zależnością. W praktyce oznacza to, że implementacje warstw mogą być łatwo wymienne. Jeżeli chcemy zamienić persystencję z Hiberneta na MyBatis to nie powinno to wpływać jakkolwiek na inne warstwy.

Możemy sobie wyobrazić sytuacje kiedy piszemy bardzo prostego CRUD’a. Nie posiada on logiki biznesowej (lub posiada jej bardzo mało). Czy powinniśmy w takim razie tworzyć warstwę logiki? Są dwie szkoły. Jedna, bardziej restrykcyjna mówiąca, że obligatoryjnie tworzymy wszystkie warstwy wymagane w projekcie a przepływ w naszej aplikacji jest zawsze taki sam. Przy takim podejściu mówi się, że warstwy są zamknięte. Natomiast druga szkoła pozwala na rozluźnienie, warstwy mogą być otwarte. Które podejście jest lepsze? Oba są prawidłowe. W architekturze jest dużo abstrakcji i stety, niestety wyraz to zależy może być używany bardzo często.

Obrazek pochodzi z kursu DNA

Dlaczego to zależy? Zobacz, moglibyśmy zezwolić na wywołanie warstwy persystencji bezpośrednio przez warstwę prezentacji. Chyba byśmy tym nie zgrzeszyli? Natomiast pozwalając sobie na takie manewry rozluźniamy granice naszej aplikacji. Nie tylko my pozwalamy na rozluźnienie ale jest jeszcze cały zespół. Kiedy komunikacja w zespole nie jest na najlepszym poziomie lub nad modułami pracuje kilka zespołów (jest to uciążliwe zwłaszcza przy dużych projektach) nasza architektura staje się krucha. Nie kontrolujemy, które warstwy mogą być otwarte a które nie. Kod staje się cięższy w testowaniu i utrzymywaniu a zależności między warstwami narastają.


Rzeczywistość architektury

Problem z architekturą warstwową jest taki, że w rzeczywistości wygląda ona nieco inaczej. Mamy moduły naszej aplikacji i przepływ od góry do dołu. Dopóki aplikacja nie jest duża, udaje nam się utrzymać prawidłowy przepływ. Problemem jest moment w którym aplikacja masowo przyrasta – zwiększa się ilość zespołów nad nią pracujących, powstają nowe, szybkie featuer’y. Biznes chce widzieć efekty jak najszybciej, tworzy presję na developerach a to zazwyczaj prowadzi do tego, że nie myślimy o designie aplikacji jako całości. Skupiamy się wyłącznie na tym co chemy dostarczyć w tym momencie – jak najszybciej. Końcowo doprowadza to do architektury warstwowej, która już nie wygląda tak pięknie jak była przedstawiana w tutorialach.

Obrazek pochodzi z kursu DNA

Istnieje rozwiązanie tego problemu. Wymaga ono jednak zastanowienia się do czego będzie nam służyć dany feature. Czy nie powinien być on osadzony w osobnym module? Dodatkowy podział aplikacji na moduły – gdzie każdy z modułów ma swoją implementację architektury jest złotym środkiem. Wiem, że znajdą się przeciwnicy tego rozwiązania mówiąc, że robi nam się wtedy misz-masz różnych styli architektonicznych. Macie rację :). Trzeba to dopasować odpowiednio do umiejętności zespołu. Co na przykład stoi na przeszkodzie żeby jeden moduł wykorzystywał architekturę trójwarstwową a drugi dwuwarstwową? Moim zdaniem nic. Należy tylko umieć odpowiednio zdiagnozować problem jaki rozwiązujemy. Sprawdzić, czy robimy CRUD’a czy coś co wymaga bardziej złożonej logiki. No i jeszcze bardzo ważne – trzymać się założeń jakie poczyniliśmy.

(Ot takie moje dumanie..)


Wady i zalety architektury warstwowej

Zalety:

  • Powszchechna. Większość ludzi ją zna i nie będzie miało problemu żeby odnaleźć się w projekcie.
  • Zmniejsza złożoność – warstwy niskopoziomowe możemy zastąpić warstwami wyższymi. Coś a’la fasada.
  • Separuje odpowiedzialność – pozwala na wymianę implementacji poszczególnej warstwy bez wpływu na inną

Wady:

  • Zmiany wymagane w wielu warstwach. Zmieniając warstwę widoku prawdopodobnie będziemy musieli również dotknąć warstwy logiki i persystencji.
  • Ukryty cel – patrząc na strukturę projektu nie jesteśmy w stanie powiedzieć jaki problem rozwiązuje. Dopiero spojrzenie w klasy znajdujące się w pakietach coś nam zaczyna podpowiadać.

W wielu wpisach na mediach jako zaletę tej architektury wymienia się również testowalność. Nie zgadzam się z tym stwierdzeniem w 100% ale też nie neguję. Owszem, możemy testować wyłącznie jedną warstwę, tylko problem jaki widzę jest taki, że kończy się to na mockowaniu 99 obiektów i testowaniu jednej malutkiej funkcjonalności. To jest złe ale nie jest tragiczne. Tragedia przychodzi kiedy w mockowanych API powstają zmiany i nasz test dalej przechodzi pomimo, że już nie powinien. W taki sposób powstają testy, które zadawalają biznes pokryciem kodu ale w rzeczywistości są do wyrzucenia… to jest temat na inny wpis.


Podsumowanie

Architektura warstwowa to dobre rozwiązanie w wielu przypadkach. Pozwala na szybki rozwój aplikacji w początkowych fazach a dodatkowo dzięki jej zastosowaniu wiemy, że każdy nowy członek zespołu wdroży się w miarę szybko. Jeżeli tworzymy aplikację, która nie jest duża to moim zdaniem architektura warstwowa może spełnić swoje zadanie doskonale.

Czasami mamy inne potrzebny a realia są niestety takie, że większość programistów nie zna stylów architektury. To powoduje, że bez edukacji zespołu nie jesteśmy w stanie wdrożyć czegoś bardziej odpowiedniego. Dlatego ważne jest aby szerzyć wiedzę i uczyć się nowych rzeczy – również o architekturze 🙂

Źródła:


Za tydzień

Kolejny wzorzec architektoniczny: Event-Driven Architecture. Myślę, że przelecimy przez wszystkie wzorce z książki Mark’a Richards’a. Jest to edukujące i ciekawe.

5 3 votes
Article Rating
Subscribe
Powiadom o
guest
0 komentarzy
najnowszy
najstarszy oceniany
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x