Architektura heksagonalna, zaproponowana przez Alistaira Cockburna w 2005 roku, otrzymała swoją nazwę dzięki sześciokątowi użytemu do przedstawienia tej koncepcji. Sześciokątny kształt jednak nie odzwierciedla bezpośrednio struktury kodu, z tego względu często używa się nazwy: architektura portów i adapterów, co bardziej oddaje sens działania tego podejścia, o czym przekonasz się w poniższym wpisie 🙂
Od Architektury Trójwarstwowej do Architektury Portów i Adapterów
Aby lepiej przedstawić architekturę portów i adapterów, zacznijmy od klasycznej architektury trójwarstwowej.
W tym modelu aplikacja dzielona jest na warstwę prezentacji, logiki biznesowej i dostępu do danych. Warstwa prezentacji odbiera żądania i przekazuje je do logiki biznesowej. Ta komunikuje się z warstwą dostępu. Choć to podejście może być wystarczające dla prostych aplikacji CRUD, staje się problematyczne przy bardziej złożonej logice biznesowej.
Architektura Portów i Adapterów
Głównym założeniem architektury portów i adapterów jest oddzielenie logiki biznesowej od pozostałych warstw. To pozwala na większą modułowość, elastyczność i testowalność aplikacji.
Tu jednak pojawia się kłopot. Jak to zrobić? Skoro często implementujemy aplikację tak, że w warstwie „logiki biznesowej” mamy serwisy, które wstrzykują repozytoria z warstwy dostępu do danych?
Rozwiązaniem zaproponowanych w architekturze heksagonalnej jest zdefiniowanie interfejsów w warstwie logiki biznesowej i implementowanie ich w warstwie dostępu do danych.
Taki interfejs nazywamy portem, a jego implementację adapterem, stąd nazwa architektura portów i adapterów.
Implementacja portów i adapterów
W architekturze portów i adapterów porty reprezentują każdy punkt wejścia i wyjścia do warstwy logiki biznesowej. Zaś adaptery, będące implementacjami tych portów, znajdują się w innych warstwach. Dlatego adaptery można podzielić na wejściowe (ang. driving, primary), które inicjują operacje w logice biznesowej. Jak i na wyjściowe (ang. driven, secondary), które umożliwiają komunikację logiki biznesowej ze światem zewnętrznym.
Często logikę biznesową otoczoną portami i nazywamy domeną. To właśnie tutaj stosujemy taktyczne wzorce z Domain-Driven Design (DDD), takie jak Agregaty czy Value Objects.
Warto podkreślić, że architektura heksagonalna jest ogólną koncepcją, która nie narzuca szczegółowej struktury logiki biznesowej ani organizacji pakietów. Dlatego można spotkać się z różnymi implementacjami tego podejścia, a jedną z nich znajdziesz na moim GitHubie, podpiętym na końcu tego wpisu.
Pamiętajmy, że tworzenie portów pomaga nam osiągnąć jakieś cele np. zwiększenie możliwości testowania komponentów, odroczenie decyzji na przyszłość, zwiększenie elastyczności przez możliwość dodania kilku implementacji. Dlatego to podejście jest stosowane, gdy przynosi realne korzyści. Jeśli znajdujemy się w takim etapie projektu, gdzie wiemy, że dla danego portu (interfejsu) mielibyśmy tylko jedną implementację, dodanie portu może nie przynieść znaczących korzyści. Należy jednak pamiętać, że adaptery mogą być tworzone wyłącznie na potrzeby testów, co zostanie omówione w osobnym wpisie.
Podsumowanie
Architektura portów i adapterów to podejście oddzielające logikę biznesową od punktów wejścia i wyjścia. Używa do tego interfejsów. Ta metoda przynosi korzyści przy rozbudowanej logice biznesowej. Pozwala na odroczenie decyzji, zwiększa elastyczność i autonomię komponentów i przede wszystkim ułatwia testowanie systemu. Niniejszy wpis miał na celu przedstawić ogólną ideę architektury portów i adapterów, a w kolejnych artykułach przedstawię konkretne przykłady zastosowania tego podejścia. Dlatego warto zapisać się na newsletter, żeby być na bieżąco!
Zostaw swój e-mail, a raz na jakiś czas wyśle Ci info o nowych postach na blogu. Tylko wartościowe e-mail!