Gdyby zasady czystej architektury wymagały specjalistycznej wiedzy na poziomie Architekta IT, byłyby bezużytecznym, czysto teoretycznym tworem. Gdyby wymagały przeczytania ton makulatury książek, utworzyłyby próg wejściowy nie do przekroczenia.
Na szczęście jest zupełnie inaczej. Prościutko i przyjemnie.
Trzy proste zasady
Zaprojektowanie aplikacji w duchu czystości architektonicznej wymaga poznania trzech prostych konceptów.
- Architektura dzieli przestrzeń kodu na warstwy
- Pomiędzy warstwami są granice
- Granice można przekraczać tylko w ściśle określony sposób.
Zasada 1. Warstwy architektoniczne
Nie ma znaczenia czy tworzysz aplikację webową, zaawansowany skrypt shellowy czy mikrokontrolerową magię. Nieistotne jest też, czy obierzesz kierunek klasycznej architektury warstwowej czy hexagonalnej. Warstwy architektoniczne są uniwersalne i można je podzielić na cztery kategorie.
Frameworki
Najbardziej zewnętrzna warstwa aplikacji. Często nawet nie modyfikujemy jej kodu. Nasza rola kończy się na wyborze i instalacji komponentów w tej warstwie.
Rutynowa praca to m.in.:
- Wybór silnika bazy danych
- Decyzja, że aplikacja będzie dostępna po HTTP i w stacku linux+nginx+php-fpm
- Wybór frameworka i instalacja
- Przygotowanie listy pakietów dla managera zależności
Kontrolery
Punkt styku i wymiany danych z użytkownikiem. Warstwę można nazwać adapterem interfejsów, zdefiniowanych w regułach biznesowych i przypadkach użycia.
Co możesz tutaj znaleźć?
- Końcówki API, czyli np.: routing HTTP/REST, wejście z CLI
- Autentykację, autoryzację i zarządzanie sesją użytkownika
- Walidację i transformację parametrów wejściowych odebranych od użytkownika
- Przygotowanie odpowiedzi na podstawie obiektów domeny (prezentery)
Przypadki użycia
Czyli nic innego jak czynności, które wykonuje aplikacja na encjach biznesowych. Czasem będą to moduły, a czasem klasy cośtamService.
Zawierający się w tej warstwie kod udziela odpowiedzi na temat odpowiedzialności aplikacji i jej możliwości. Jeśli szukasz odpowiedzi na pytanie Jak to działa? – zajrzysz właśnie tutaj.
Warstwa przypadków użycia jest dyspozytorem ruchu między kontrolerami a encjami. Odpowiada za przygotowanie wywołań encji, przekazanie i odebranie danych z obiektów i struktur domeny biznesowej.
Encje
Serce logiki biznesowej. Zbiór obiektów, metod, luźnych funkcji i struktur danych. Warstwa najwyższego rzędu, szkicująca ogólny obraz całej aplikacji.
Często spotykanym błędem jest anemiczność warstwy encji, czyli sprowadzenie jej roli do struktur danych. A przecież tu powinny się znaleźć walidatory parametrów wejściowych do operacji biznesowych, niezmienniki i kontrakty reguł biznesowych.
Tak jak normy ISO standaryzują procesy w organizacjach, tak warstwa encji odpowiada za definiowanie zachowań dla całej aplikacji. Pozostałe warstwy deklarują, że spełniają zdefiniowane tu standardy. Zamiast przeglądać dokumentację, często nieaktualną, warto zajrzeć do warstwy encji w poszukiwaniu wiarygodnych informacji.
Dodając jeszcze język wszechobecny, możemy uczynić z tej warstwy narzędzie wspólne dla developerów, analityków, ba, nawet dla project i product managerów (sprawdzone empirycznie 🤓).
Zasada 2. Granice i zależności
Wyobraź sobie, że kod to grupa państw. Warstwa to takie jedno państwo. Posiada ono unikalny przemysł i dobra naturalne. Ale musi współpracować, żeby przetrwać. Państwa nie mogą sobie podkradać zasobów. To doprowadziłoby do wojny. Dlatego, aby przekraczać granice, potrzebny nam jest paszport dobrych zasad i odpowiednia kontrola graniczna. Tylko wtedy zapanuje porządek.
Zasada zależności
To odpowiedni kierunek wzajemnych zależności wprowadza porządek, dzięki któremu kod osiąga równowagę Zen. Jest jeden słuszny kierunek – od warstwy hiperniskopoziomowych szczegółów typu: framework, sieć www, silnik bazy danych, po warstwę wysokiego poziomu (domena). O tym właśnie mówi zasada zależności.
Relacje między warstwami wyglądają w uproszczeniu tak:
- Encje to egoistyczne jednostki. Nie interesuje ich nic poza własnym kręgiem
- Przypadki użycia komunikują kontrolerom, w jaki sposób życzą sobie, by z nimi rozmawiano. Same niestety muszą akceptować egoistyczne encje.
- Kontrolery muszą być konformistami w stosunku do przypadków użycia. Ale nie interesuje ich konkretna implementacja bazy danych – operują na interfejsach i abstrakcjach.
- Adaptery znajdujące się w warstwie frameworków i sterowników posłusznie implementują zdefiniowane wyżej interfejsy. Nie znajdziesz tu nic wartościowego z punktu widzenia architektury. Co nie znaczy, że warstwa nie będzie posiadała pierwiastków kosmicznej technologii np. związanej z ultra optymalizacją.
Zasada 3. Przekraczanie granic
Pamiętasz porównanie do państw i kontroli granicznej? Wiesz już na jakich zasadach się odbywa. Nadal jednak potrzebujesz paszportu. Zaraz go wyrobimy (obędzie się bez fotki).
Abstrakcje i interfejsy
Widzisz interfejs StorageInterface, który pojawił się na powyższym obrazku? Interfejs jest następnie implementowany przez klasę MySqlAdapter, która tłumaczy obiektowy świat domeny na język relacyjnej bazy danych MySQL.
Interfejs StorageInterface jest twoim paszportem do przekroczenia granicy architektonicznej. Dziwi cię, że jest zdefiniowany w warstwie domeny? Nie powinno. To przecież reguły biznesowe mają śmiało akcentować, czego oczekują od pozostałych warstw aplikacji. Czyli wychodzi nam proste stwierdzenie, że domena jest elementem strategicznym czystej architektury – naszym poszukiwanym urzędem paszportowym 👮
Architektura, raz, na wynos poproszę!
Poznałeś 3 magiczne i zarazem bajecznie proste podstawy czystej architektury.
- Umiesz rozpoznawać i nazywać warstwy w kodzie aplikacji.
- Potrafisz wyznaczać nieprzekraczalne granice architektoniczne, których musisz strzec przed zakusami przekroczenia dla tego jednego, malutkiego wyjątku.
- Wiesz jak, zgodnie z zasadami zależności, wykorzystywać interfejsy i sterować ruchem na granicy.
Możesz śmiało zagłębić się w technikalia implementacji czystej architektury. Skocz do praktycznej części, czyli do cyklu “Czysta architektura w Pythonie”.
Funkcja trackback/Funkcja pingback