W naszej branży istnieją sprawdzone w boju wzorce projektowania systemów. Możesz je wykorzystać, aby rozwiązywać problemy, na pewno natkniesz się w pewnym momencie pracy twojego produktu.
Dodatkowo, nie musisz odkrywać koła na nowo 😀
Pozostałe artykuły z cyklu Lider Techniczny przeczytasz tu: link.
Dlaczego warto wykorzystywać wzorce?
Tutaj widzę 3 duże argumenty, które zachęcają do wykorzystywania wzorców:
- Rozwój architektury we właściwym kierunku
- Określenie głównych zachowań aplikacji
- Zmniejszenie kosztu kognitywnego
Rozwój architektury we właściwym kierunku
Aplikacje tworzone bez docelowej architektury można rozpoznać po silnych powiązaniach między komponentami. Są kruche, trudne do zmiany, pozbawione jasnej wizji czy ukierunkowania.
Wybór wzorca architektury przed rozpoczęciem pisania kodu jest istotny dla sukcesu produktu (choć oczywiście nie definiuje sukcesu 😅). Dzięki temu będziesz w stanie odpowiedzieć na poniższe pytania dotyczące rozwoju i refaktoru systemu:
- Czy architektura jest skalowalna?
- Jakie są charakterystyki wydajnościowe systemu?
- Jak szybko jesteśmy w stanie wprowadzać zmiany?
- Co jest wymagane do wdrożenia systemu?
- Jak wielkie obciążenie jesteśmy w stanie obsłużyć?
Wykorzystując konkretne wzorce łatwiej unikniesz pułapek, jakie niesie za sobą „wielka kula błota". Stworzysz aplikację łatwą do utrzymania i rozwijania.
Tutaj przy wyborze wzorca na pewno przydadzą się drivery architektoniczne.
Określenie głównych zachowań aplikacji
Wzorce to narzędzie, którego celem jest zapewnienie określonego działania systemu. Umożliwiają wymuszenie konkretnych cech i zachowania. Dzięki nim jesteśmy w stanie narzucić wybrany sposób realizacji.
Np. wzorce integracyjne wymagają dodatkowych prac technicznych w ramach współpracy serwisów. Jednocześnie ich wykorzystanie zwalnia z prac przy wdrażaniu pojedynczych funkcjonalności. Obsługujesz komunikację pomiędzy serwisami, a wszystko się dzieje w tle.
Wykorzystujesz gotowe rozwiązanie, z którego korzystamy, często nawet o tym nie wiedząc.
Zmniejszenie kosztu kognitywnego
Wzorce definiują pewien stabilny model zachowań. Wzorce ułatwiają projektowanie aplikacji poprzez dostarczenie sprawdzonych rozwiązań. Dzięki temu programiści nie muszą poświęcać tyle czasu i wysiłku na rozwiązywanie powtarzających się problemów, co zmniejsza koszt kognitywny.
Członkowie zespołu wiedzą czego oczekiwać od produktu wykorzystującego dany wzorzec. W ramach nich możemy spójnie rozwijać system w większą liczbę osób. Wejście do zespołu się upraszcza. Łatwiej jest też dzielić się informacjami z innymi zespołami.
Wzorce
Na potrzeby tego artykułu podzieliłem opisywane wzorce na 4 rodzaje:
- Wzorce aplikacyjne
- Wzorce integracyjne
- Wzorce mikroserwisów
- Wzorce transakcji rozproszonych
Do każdego obszaru wzorców dodałem krótki opis tych wzorców oraz linki do dalszych materiałów.
Celowo nie opisuję tutaj głęboko poszczególnych wzorców. Zrobili to lepiej ode mnie twórcy do których linkuję 😉
Pamiętaj, że każdy wzorzec ma swoje mocne i słabe strony. Wybór odpowiedniego wzorca ma ogromne znaczenie dla jakości wdrażania nowych zmian. Dlatego ważne jest dokładne poznanie danego wzorca. Następnie wybranie tego, który najbardziej pasuje do specyfiki biznesowej oraz celów projektu.
Bez tego ani rusz!
Wzorce aplikacyjne
Wzorce aplikacyjne to fundamentalne elementy projektowania aplikacji. Przy projektowaniu wewnątrz pojedynczej aplikacji lub modułu, skupiamy się na strukturze wewnętrznej i reakcji na poszczególne żądania.
Do najciekawszych wzorców aplikacyjnych należą:
- CRUD, który jest często stosowany w przypadku prostych operacji na bazie danych.
- N-Layer, który pomaga w organizowaniu kodu w skupieniu na warstwy techniczne.
- Hexagonal/Clean/Onion, które zapewniają izolację aspektów domenowych.
- CQRS, który pomaga w separacji zapytań odczytu i zapisu.
- Vertical / Feature Driven pomagają w organizacji kodu zgodnie z funkcjonalnością, co ułatwia utrzymanie i rozwijanie aplikacji.
Wzorce integracyjne
Jak powiedział na jednej prezentacji Gregor Hohpe:
To, jak twoje komponenty są ze sobą połączone, określa zasadnicze właściwości twojego systemu.
Wzorce integracyjne określają sposoby rozwiązywania problemów pomiędzy niezależnymi serwisami, ułatwiając komunikację między nimi i rozwiązując główne problemy komunikacji międzyprocesowej.
Oprócz tego wzorce integracyjne umożliwiają spójne zdefiniowanie komunikacji w organizacjach, ułatwiając współpracę wewnętrzną i zewnętrzną. Stanowią również podstawę komunikacyjną dużej części bibliotek i serwisów chmurowych.
Znajomość wzorców integracyjnych jest kluczowa dla tworzenia skalowalnych, wydajnych i stabilnych systemów informatycznych.
Wzorców integracyjnych określono ponad 60. Na szczególną uwagę zasługują:
- Messaging Mapper - mapowanie wiadomości pomiędzy odbiorcami.
- Transactional outbox - transakcyjne wysyłanie wiadomości.
- Correlation Identifier - korelacja wiadomości wchodzącej z wychodzącą.
- Scatter-Gather - broadcast wiadomości do wielu dostawców.
- Dead Letter Channel - przeniesienie wiadomości na specjalną kolejkę, gdy jej obsługa się nie powiedzie.
- Message Router - koordynowanie wiadomościami do różnych odbiorców.
- Process Manager - zarządzanie procesem obsługi wiadomości przez jednego aktora.
- Routing Slip - informacja w wiadomości, który aktor powinien się zająć daną wiadomością.
- Idempotent Receiver - pojedyncze obsłużenie wiadomości przez aktora.
- Competing Consumers - aktorzy konkurują o wiadomości obsługując je równolegle.
Polecana książka:
- Enterprise Integration Patterns - Gregor Hohpe
Wzorce mikroserwisów
Wzorce mikroserwisów skupiają się na projektowaniu systemu, w którym jest on podzielony na wiele niezależnych jednostek wdrożeniowych, czyli mikroserwisów.
Każdy z tych serwisów jest odpowiedzialny za zarządzanie wewnętrzną logiką biznesową oraz strukturą danych. Na zewnątrz wystawia API umożliwiające komunikację z innymi serwisami. Mikroserwisy są zazwyczaj skupione na konkretnym obszarze biznesowym i zarządzane przez jeden zespół.
Taki podział na mniejsze jednostki umożliwia lepszą skalowalność, łatwiejsze zarządzanie, szybsze wdrażanie zmian i zwiększoną niezależność każdego z serwisów . Wzorce mikroserwisów są coraz częściej stosowane w przypadku dużych i złożonych systemów, gdzie łatwiejsze zarządzanie i szybka reakcja na zmiany są istotnym czynnikiem.
Wzorce mikroserwisów, którym warto przyjrzeć się z bliska:
- Event-Driven Architecture - zdarzenia jako jeden z głównych element komunikacji pomiędzyserwisowej.
- Retries / Circuit Breaker - metody na obsługę problemów w komunikacji.
- API Gateway - rozdział żądań do różnych biznesowo serwisów oraz dodatkowe operacje infrastrukturalne.
- Backend for Frontend - osobny backend dedykowany dla danego frontendu.
- Strangler Pattern - stopniowe zastępowanie (zaduszanie) systemu legacy przez nowy system.
- Blue-Green / Rolling / Canaries Deployment - metody na stopniowe wdrażanie w ramach mikroserwisu.
- Component Test - testy biznesowe mikroserwisu jako całość.
- Load Balancer - rozdział żądań do puli identycznych instancji tego samego serwisu.
- Client/Server Side Discovery - metody na zarządzanie odkrywaniem adresacji nowych serwisów.
- UI composition - składanie żądań z wielu mikroserwisów na froncie aplikacji.
- Service Mesh - warstwa infrastruktury zapewniająca komunikację i bezpieczeństwo pomiędzy mikroserwisami.
Polecane książki:
- Microservices Patterns - Chris Richardson
- Cloud Native Patterns – Cornelia Davis
Wzorce transakcji rozproszonych
Czym są transakcje rozproszone? To zestaw powiązanych operacji biznesowych które uruchamiają się na różnych serwisach. Trudność tutaj tworzy wyjście poza proces - transakcja rozproszona jest bardziej skłonna do niepowodzenia, przez problemy sieciowe. Często te problemy wyjdą dopiero na produkcji. Dobrze opisano to w Fallacies of distributed computing.
Saga podejście, które pozwala na rozwiązanie problemów transakcji rozproszonych. Wzorzec został opisany w 1987 roku przez Hector Garcaa-Molrna i Kenneth Salem w artykule naukowym o nazwie Sagas #niktsięniespodziewał 😀
Na czym polega wzorzec?
Transakcje te są połączone w sagę, która składa się z lokalnych transakcji. Każda z nich spełnia cel biznesowy i informuje kolejną transakcję o swoim powodzeniu lub niepowodzeniu. W przypadku niepowodzenia jednej z transakcji, sagę można zakończyć kompensacją, czyli wycofaniem zmian. Dzięki temu podejściu transakcje rozproszone stają się bardziej niezależne i odporniejsze na awarie.
Do wzorca transakcji rozproszonych możemy podejść dwutorowo: poprzez sagę choreography-based (choreografię) lub orchestration-based (orkiestrację).
W choreography-based każda transakcja biznesowa jest odpowiedzialna za wykonanie swojej roli w procesie biznesowym. Saga składa się z serii powiązanych ze sobą transakcji, które wymieniają wiadomości z innymi transakcjami. Każda transakcja reaguje na wiadomości od innych transakcji i podejmuje decyzje dotyczące swojego stanu na podstawie informacji otrzymanych z innych transakcji.
Podejście orchestration-based obejmuje komponent zwany orchestratorem. Jest on odpowiedzialny za koordynację całego procesu biznesowego. Orkiestrator podejmuje decyzje na podstawie odpowiedzi od poszczególnych transakcji,. określa kolejność ich wykonywania i informuje o tym, co powinno się dziać w przypadku niepowodzenia transakcji Każda transakcja otrzymuje instrukcje od orkiestratora i wykonuje określone zadanie zgodnie z nimi.
Obydwa podejścia mają swoje zalety i wady i są stosowane w różnych przypadkach. W podejściu choreography-based każda transakcja jest bardziej niezależna , co może prowadzić do lepszej skalowalności, ale jednocześnie może być trudniejsze do zrozumienia i debugowania, gdy coś pójdzie nie tak. Natomiast podejście orchestration-based jest bardziej scentralizowane i prostsze do zrozumienia, ale może być mniej elastyczne i trudniejsze do skalowania.
Więcej informacji możesz znaleźć w:
- Saga - Chris Richardson
- Saga - Microsoft
- Compensating Transaction pattern
Polecane książki:
- Microservices Patterns - Chris Richardson
- Software Architecture: The Hard Parts – Neal Ford, Mark Richards, Pramod Sadalage, Zhamak Dehghani
Po co używać wzorców w swojej pracy
Wzorce stanowią fundamentalny element projektowania pracy produktu. Umożliwiają określenie podstawowych cech i zachowania systemu.
Znając charakterystykę różnych wzorców, możesz wybrać te, które najlepiej odpowiadają potrzebom i celom biznesowym Twojego projektu.
A teraz najważniejsze: daj znać, których wzorców zabrakło w moim opracowaniu! 😉