Pretius: strategiczna fuzja jako odpowiedź na współczesne wyzwania
Pretius. Budujemy mądrzej:
strategiczna fuzja jako odpowiedź na współczesne wyzwania

Modułowa architektura oprogramowania: zalety i wady stosowania architektury monolitycznej, mikrousług oraz monolitu modułowego

Arkadiusz Rosłoniec

Senior Java Developer / Team Project Leader

  • 27 kwietnia, 2023

Spis

[Uwaga] Ten artykuł został pierwotnie przygotowany w języku angielskim i został przetłumaczony na język polski.

Architektura systemu – Mikroserwisy vs Monolit

W ostatnich latach architektura mikroserwisowa wysunęła się na prowadzenie w większości rozwiązań programistycznych i w wielu przypadkach jest najczęściej wybieraną architekturą, od której zaczynamy rozwój projektu. Warto jednak zadać sobie pytanie, czy zawsze jest to optymalny wybór. Co więcej, jeśli wybierasz mikroserwisy jako zestaw zasad, których chcesz się trzymać, czy na pewno jesteś świadomy konsekwencji tego wyboru?

Zalety mikroserwisów

Moim zdaniem mikroserwisy oferują dwie główne korzyści:

  • Niezależne wdrożenia bez przestojów (zero-downtime deployments)
  • Logiczny (czasem techniczny) podział systemu (również bazy danych) na moduły i submoduły biznesowe

Problem „rozproszonego monolitu”

Niestety, w większości przypadków, gdy wybierana jest architektura mikroserwisowa, zespół kończy z tak zwanym „rozproszonym monolitem”. Jeśli na początku pracy polegasz na silnych zależnościach między usługami lub bazami danych, a ostatecznie wdrażasz 90% usług jednocześnie, powinieneś przyznać, że łatwiej byłoby to zrobić jako pojedynczą jednostkę wdrożeniową. Zmniejszyłoby to wysiłek związany z implementacją, automatyzacją i utrzymaniem mikroserwisów, pozwalając skupić się intensywnie na problemach biznesowych.

Krótko mówiąc, musisz pamiętać, że styl architektury mikroserwisowej nie jest prosty i niesie ze sobą dużą złożoność technologiczną. Nie strzelaj z armaty do wróbla! Uruchamianie klastra Kubernetes dla jednej aplikacji lub usługi nie ma sensu, ponieważ koszty infrastruktury i wszystkich konfiguracji przewyższą koszty rozwoju. Istnieją inne „prostsze” rozwiązania chmurowe, np. AWS ECS, AWS Fargate, AWS Beanstalk, a nawet EC2 + prosty Load Balancing (inni dostawcy chmury mają podobne rozwiązania).

Poniżej przedstawiam kilka heurystyk, które mogą pomóc w podjęciu decyzji, którą architekturę wybrać.

Czego potrzebujesz? Mikroserwisy Monolit
Niezależne jednostki wdrożeniowe Tak, ale tylko przy dobrej separacji logicznej Tak
Prosta i szybka do zbudowania infrastruktura Nie Tak
Dynamiczne skalowanie Tak Nie
Autonomia logiki biznesowej Tak – jeśli poprawnie podzielimy domeny Tak – jeśli poprawnie podzielimy domeny
Dynamiczne skalowanie poziome konkretnych komponentów Tak Nie
Autonomia technologiczna Tak Nie
Niezależne zespoły deweloperskie Tak Nie
Szybki start projektu (kick-off) Nie Tak

Monolit nie musi być czymś złym – zwłaszcza z modularną architekturą

Termin „monolit” jest często używany jako synonim przestarzałych aplikacji (legacy). Poprzez odpowiednie zaprojektowanie aplikacji monolitycznej (właściwy dobór architektury wewnętrznej), można zdecydowanie skrócić start projektu, nie wykluczając ewentualnych zmian w przyszłości. Wciąż możesz przejść na mikroserwisy. W tym miejscu przydaje się podejście modularnego monolitu – a w szczególności podejście „monolith first”. Jeśli nie wiesz, jaki zakres będzie miał projekt w nadchodzących latach i nie wiesz, jak szybko będzie rósł, rozpoczęcie od dobrze ustrukturyzowanej aplikacji monolitycznej może być dobrym pomysłem.

Co oferuje Modularny Monolit?

  • Pojedynczą jednostkę wdrożeniową
  • Łatwiejsze utrzymanie
  • Otwartą drogę do ewentualnej późniejszej migracji do architektury rozproszonej
  • Prostą infrastrukturę
  • Uporządkowany kod

Oczywiście istnieje wiele innych czynników, które mogą wpłynąć na wybór architektury systemu. Biorąc jednak pod uwagę te, o których wspomniałem powyżej, lepiej nie zaczynać projektu z założeniem, że będzie on oparty na mikroserwisach. Jeśli nie masz pewności, jak cały system będzie wyglądał za 2–3 lata, zazwyczaj lepiej wybrać architekturę modularną. Zaczynasz od dobrze zaplanowanego monolitu, a następnie – w razie potrzeby – stopniowo przekształcasz go w monolit modularny.

Warto również pamiętać o dostępnych, prostych rozwiązaniach, które w ogóle nie wymagają architektury systemowej – takich jak rozwiązania serverless, AWS Lambda itp. Mogą one dobrze sprawdzić się w przypadku stosunkowo prostych, niezbyt skomplikowanych problemów.

W Pretius skupiamy się na projektach długoterminowych i długim cyklu życia (utrzymanie i rozwój), dlatego trwałość i rozszerzalność są dla nas zazwyczaj bardzo ważne. Wybór architektury systemu często sprowadza się do metody wdrażania i w konsekwencji infrastruktury, na której system jest uruchamiany.

Jednak z perspektywy programistów, infrastruktura i wdrażanie aplikacji powoli stają się tematami drugorzędnymi – istnieją specjaliści na dedykowanych stanowiskach (np. inżynierowie DevOps), którzy podejmują ważne decyzje i dbają o te problemy. My po prostu chcemy, aby system był dobrze utrzymany, działał bez problemów i nie generował długu technologicznego/biznesowego. Aby tak się stało, musimy skupić się na kodzie aplikacji.

Wewnętrzna architektura aplikacji

Gdy już zdecydujesz się na architekturę systemu, nadszedł czas, aby skupić się na architekturze poszczególnych aplikacji. Niestety, większość projektów opiera się na warstwach (architektura n-warstwowa). W przypadku złożonych projektów efekt końcowy jest zazwyczaj taki sam → Wielka Kula Błota (Big Ball of Mud – przykład na poniższym zrzucie ekranu).

Big Ball of Mud diagram

Źródło obrazu: Medium.

Nie jest to zły wybór dla prostych aplikacji typu CRUD lub kilku/kilkunastu usług, ale kiedy próbujesz ująć złożoną logikę w taki schemat, szybko okazuje się, że sieć zależności zaczyna powodować poważne problemy. Dobrym pomysłem jest posiadanie świadomości istnienia różnych stylów i poznanie ich bardziej szczegółowo.

Style architektury aplikacji:

Warto dodać, że style te można mieszać i dopasowywać. Nie trzeba fiksować się na konkretnym rozwiązaniu, ale po prostu wybierać narzędzia, które ułatwią życie. Dotyczy to również architektury systemu. Na przykład, jeśli okaże się, że w systemie mikroserwisowym musisz stworzyć większą (np. monolityczną) aplikację, nie powinieneś na siłę próbować dopasować jej do architektury mikroserwisowej. Zamiast tego wybierz architekturę wewnętrzną, podziel ją na oddzielne moduły / domeny biznesowe, a tym samym zmniejsz koszty pracy DevOps/konfiguracyjnej.

Złoty środek

Przy wyborze architektury można również spróbować znaleźć kompromis. Mówiąc szczerze, coś takiego jak „złoty środek” nie istnieje – ale można się do niego zbliżyć. Przed wyborem konkretnego stylu architektonicznego warto zebrać kilka metryk dotyczących projektowanego systemu. Im więcej informacji będziesz mieć do dyspozycji, tym bardziej wiarygodna będzie Twoja decyzja.

  • Złożoność systemu (Płytki vs Głęboki)
    • Płytki – wszystkie systemy typu CRUD bez lub z znikomą ilością logiki biznesowej
  • Głęboki – wysoka złożoność (biznesowa/technologiczna). Złożoność można określić na podstawie takich cech jak:
    • Komunikatywność
    • Zasady biznesowe
    • Algorytmy
    • Koordynacja
  • Perspektywa czasowa
    • Co ulegnie zmianie
    • Prawdopodobne/Niemożliwe zmiany
  • Podział odpowiedzialności – czy istnieje potrzeba pracy niezależnych zespołów nad rozwiązaniem?

Płytki system łatwo rozpoznać, ponieważ jego interfejs użytkownika w pełni odzwierciedla struktury w bazie danych i w kodzie aplikacji (→ CRUD). Nie ma tu złożonych integracji ani skomplikowanych algorytmów. Z kolei główną cechą systemów głębokich jest to, że od momentu interakcji użytkownika do efektu końcowego odbywa się szereg niewidocznych dla niego operacji – mniej lub bardziej złożonych. Wyszukiwarka Google czy system do procesowania wniosków leasingowych to dobre przykłady systemów głębokich.

Trudno mówić o zasadach wyboru architektury – lepszym terminem wydają się być „heurystyki”, które mogą skierować nas ku konkretnemu wyborowi.

Dla płytkich, nieskomplikowanych systemów tworzonych przez mały zespół, można wybrać prostsze architektury, np. aplikacje warstwowe i monolityczne. Kiedy jednak od początku wiadomo, że złożoność będzie wysoka, projekt będzie trwał latami i wymagał pracy dużych lub wielu zespołów, kluczowy będzie odpowiedni podział aplikacji i dążenie do separacji odpowiedzialności. Można to osiągnąć zarówno w architekturze mikroserwisowej, jak i we wspomnianym wcześniej modularnym monolicie. Istnieją również aspekty techniczne, które należy wziąć pod uwagę przy wyborze konkretnego stylu.

Stary dobry brainstorming – lub jego nowsza forma, event storming – to jedne z narzędzi, których można użyć do stworzenia wstępnego zarysu modułów/usług. Celem takich ćwiczeń jest uformowanie wstępnego zarysu domen – lub ich braku – w danym biznesie. Następnie powinieneś być w stanie oszacować wielkość systemu. Poniżej znajduje się przykład pierwszego zarysu domen/modułów po analizie diagramu obiektów (oznaczonych kolorami).

Baza danych

Database Diagram

Model bazy danych jest często zaniedbywany, gdy zespoły wybierają architekturę dla swojego projektu. Dzielą usługi na mniejsze lub większe, uruchamiają je w chmurze i budują całą otoczkę związaną z produkcją mikroserwisów, ale nadal projektują bazę danych tak, jakby była częścią dużej splątanej aplikacji monolitycznej. To nie jest dobre podejście – jeśli zdecydujesz się na mikroserwisy, baza danych musi odzwierciedlać logiczny podział, który zastosowałeś w warstwie aplikacji. Wiązanie usług na poziomie bazy danych jest jednym z głównych problemów we współczesnych architekturach mikroserwisowych, prowadzącym do Wielkiej Kuli Błota (pokazanej na jednym z powyższych obrazków) i późniejszych trudności w utrzymaniu.

Schematy

Jeśli nie możesz pozwolić sobie na oddzielne bazy danych dla każdej usługi, podział na schematy wystarczy na początek. Schematy sprawdzą się również w modularnych monolitach. Jeśli chodzi o warstwę danych w mikroserwisach, powinieneś korzystać z możliwości, jakie one oferują – mianowicie powinieneś dopasować typ bazy danych do modelu biznesowego, a nie odwrotnie. Przy odrobinie wysiłku wszystko można spłaszczyć do modelu relacyjnego, ale swoboda architektury mikroserwisowej pozwala nam tego nie robić.

Powszechnym sposobem projektowania bazy danych jest tworzenie struktur w oparciu o dane, które musimy zebrać (np. na podstawie informacji otrzymanych od klienta). Dobrym ćwiczeniem jest próba zaprojektowania modelu danych w oparciu o funkcjonalności, które aplikacja musi spełniać. Wynikowy model jest zazwyczaj znacznie „cieńszy” niż pierwotne założenia i okazuje się w pełni wystarczający.

ORM vs SQL

W wielu projektach Pretius wykorzystywaliśmy narzędzie MyBatis do komunikacji z bazą danych. Pozwala to zachować 100% kontroli nad tym, co dzieje się w bazie, ale ma też często niezauważalny efekt uboczny – Anemiczny Model Domenowy (Anemic Domain Model). Pisanie złożonych instrukcji SQL często zniechęca programistów do tworzenia złożonych relacji wewnątrz modelu po stronie kodu aplikacji. Inną konsekwencją tego jest odejście od paradygmatu programowania obiektowego (brak enkapsulacji, logika w serwisach).

Prawie każdy deweloper może nauczyć się i obsługiwać rozwiązania takie jak MyBatis (oraz inne alternatywy, jak np. Hibernate), więc są one jak najbardziej warte rozważenia. Są to jednak tylko narzędzia i nie zwolnią Cię z obowiązku myślenia o skutkach ubocznych i konsekwencjach Twoich decyzji.

Komunikacja

Jeśli chodzi o komunikację w architekturze mikroserwisów, preferowane jest podejście Asynchronous By Default (domyślnie asynchroniczne), ale z pewnością nie da się w pełni uniknąć korzystania z REST lub innej synchronicznej formy komunikacji (gRPC, SOAP itp.). Technologia to jedno, ale są ważniejsze pytania, które powinieneś sobie zadać. Dlaczego się komunikujesz? Czy te wywołania REST są konieczne? Czy logika została odpowiednio odseparowana do innego modułu/usługi?

Często mikroserwisy stają się siecią wzajemnych połączeń – mówiąc obrazowo, wszystko rozmawia ze wszystkim. Jest to zazwyczaj konsekwencja złego podziału/dekompozycji na domeny i jest już poważną wskazówką, że zbudowałeś rozproszony monolit, a nie mikroserwisy.

Problem ten nie ogranicza się tylko do komunikacji na poziomie aplikacji/usług. Musisz pamiętać, że te same zasady obowiązują na poziomie kodu – Usług, Fasad, Klas czy pakietów. W obu przypadkach warto zapoznać się z koncepcją Low coupling, High cohesion (niska zależność, wysoka spójność). Komunikacja w kontekście technicznym zazwyczaj nie jest problemem, ale transakcje rozproszone, sagi, kompensacje i fallbacki (które są czasem konsekwencją architektury rozproszonej) już tak. To jest obszar, na którym należy się skupić.

Kilka wzorców komunikacji w systemach rozproszonych, które powinieneś znać:

Tworzenie podstawowej struktury projektu

Struktura projektu powinna być ściśle powiązana z wybraną architekturą systemu i aplikacji. Oprócz komponentów, które powinny być wspólne, na przykład w ramach wymagań DevOps (dotyczy architektury systemu), wewnętrzna struktura samej aplikacji będzie determinowana przez wybraną architekturę aplikacji.

Poza architekturami, w celu zachowania lepszej czytelności kodu w kontekście biznesowym, można zastosować podejście „package by feature” (pakietowanie według funkcjonalności). Pomysł polega na umieszczaniu kodu zgrupowanego w pakietach dla konkretnej domeny/funkcjonalności/obszaru, a nie – jak to zazwyczaj bywa – podzielonego na pakiety techniczne, tj. kontrolery, serwisy, mappery itp.

Szczerze mówiąc, nie zalecam tworzenia szkieletów aplikacji, które można ponownie wykorzystać wewnątrz firmy. Istnieją darmowe narzędzia, takie jak Spring Initializr, za pomocą których można stworzyć taki zarys projektu w kilka sekund, więc lepiej rozważyć każdy przypadek niezależnie. Kopiowanie czegoś z innych projektów może prowadzić do długu technologicznego od samego początku – ponieważ nawet nie sprawdzasz, czy dostępna jest nowsza/lepsza opcja.

Jednak po wybraniu struktury dobrze jest się jej trzymać przez cały projekt, aby zachować spójność i przejrzystość.

Strategie testowania

Testing Pyramid

Źródło obrazu: Martin Fowler.

Piramida testów (zrzut ekranu powyżej) nie ma w pełni zastosowania w przypadku architektur rozproszonych. Oprócz testowania w ramach jednej jednostki wdrożeniowej, należy zapewnić testowanie na styku tych jednostek, ponieważ trzeba założyć, że taka komunikacja będzie obecna. Tak więc, oprócz standardowych testów integracyjnych między modułami/usługami, można również stosować Testy Kontraktowe jako część testowania API między modułami (dodatkowe informacje na ten temat dostępne są tutaj).

Również piramida testów będzie wyglądać inaczej w zależności od modułu. W przypadku płytkich modułów (powiedzmy CRUD) nie ma sensu przeprowadzać wszystkich rodzajów testów, ponieważ w końcu po prostu będziesz sprawdzać to samo kilka razy – główną różnicą będzie sposób wywoływania testów. Dla głębokich, złożonych modułów, gdzie logika biznesowa może być skomplikowana i rozbudowana, testy jednostkowe są kluczowe. Integracja modułów będzie z kolei wymagała więcej testów integracyjnych niż jednostkowych. Testcontainers to świetne narzędzie do testów integracyjnych, a jeśli chcesz wiedzieć, jak skutecznie go używać razem z Liquibase, sprawdź mój poprzedni artykuł: Testcontainers + Liquibase: Ułatw sobie testy integracyjne.

Scentralizowane przechowywanie logów

Architektura rozproszona (mikroserwisowa) będzie wymagała odpowiedniej metody zbierania logów aplikacji. Usługi mogą istnieć w środowisku produkcyjnym w wielu instancjach i działać na zupełnie różnych maszynach fizycznych. W rezultacie logowanie się na serwer i ręczne przeszukiwanie logów w plikach tekstowych staje się czasochłonne, a czasem może być wręcz niemożliwe. Rozwiązaniem tego problemu jest wdrożenie scentralizowanego magazynu logów, takiego jak dokumentowa baza danych, w której logi ze wszystkich aplikacji wchodzących w skład systemu będą gromadzone za pomocą narzędzi pomocniczych. Oprócz scentralizowanego magazynu logów, zainteresować Cię mogą narzędzia do replikacji danych, które pomagają zachować spójność danych (i ich dostępność w systemach rozproszonych).

Standardem rynkowym dla realizacji opisanego powyżej wymagania jest obecnie zestaw trzech narzędzi (ELK stack):

  • Logstash – aplikacja odpowiedzialna za zbieranie logów z aplikacji, ich przetwarzanie i agregację, a następnie przesyłanie ich do bazy danych
  • Opensearch/Elasticsearch (dokumentowa baza danych) – magazyn danych
  • Dashboard/Kibana – aplikacja odpowiedzialna za wizualizację zebranych logów

Konkretna baza danych i narzędzie do wizualizacji logów będą zależeć od projektu. Dwie najbardziej prawdopodobne opcje wymieniono w powyższych punktach.

Poniższy diagram przedstawia uproszczony przepływ logów ze stron internetowych/aplikacji do silnika bazy danych.

Log flow diagramZ Logstash można zintegrować się poprzez REST API, co pozwala na korzystanie z niego niezależnie od języka programowania użytego w aplikacji. Jeśli nie jest możliwe bezpośrednie zintegrowanie aplikacji z Logstashem, istnieje możliwość skorzystania z narzędzia Beats odpowiedzialnego za pobieranie logów z plików tekstowych, ich parsowanie, a następnie przesyłanie do narzędzia Logstash.

Monitoring

Jedną z konsekwencji stosowania architektury mikroserwisowej jest dość wysoka złożoność technologiczna. Aplikacje są rozproszone na wielu maszynach fizycznych, system może składać się z dziesiątek aplikacji i różnych komponentów wspierających. Dlatego bardzo ważnym aspektem w utrzymaniu systemów rozproszonych jest ich ciągły monitoring, czyli sprawdzanie kondycji systemu. Dzięki temu, gdy zauważymy awarię lub błąd systemu, jesteśmy w stanie maksymalnie skrócić czas reakcji.

Paradoksalnie, aby zapanować nad rosnącą złożonością architektury, musimy wdrożyć jeszcze więcej narzędzi, które nam w tym pomogą.

Co powinieneś monitorować?

  • Aplikacje biznesowe – aplikacje/usługi dostarczane przez zespoły software development będą stanowiły rdzeń platformy i będą spełniać główne wymagania biznesowe. Dlatego jest to kluczowy element, który należy monitorować. Istnieje kilka obszarów, na które warto zwrócić uwagę:
    • Metryki techniczne (mogą dotyczyć konkretnej aplikacji/usługi) – są one dostarczane w aplikacjach przez gotowe biblioteki, specyficzne dla każdego języka programowania i zależne od użytych technologii. Parametry techniczne aplikacji są podobne do tych w sekcji infrastruktury (użycie procesora, pamięci RAM, wolne miejsce na dysku), ale dotyczą one tylko konkretnej aplikacji lub jej instancji.
    • Metryki biznesowe – są to dane zbierane przez zespoły programistyczne. Może się to czasem wydawać nadmiarowe, ale może służyć jako alternatywa dla budowania statystyk przez inne zespoły.
    • Logi aplikacji – z logów aplikacji będziesz w stanie wyciągnąć zarówno informacje techniczne, jak i biznesowe.
  • Infrastruktura systemowa – oprócz aplikacji biznesowych, ważnym aspektem jest kondycja infrastruktury i maszyn fizycznych, na których działa platforma. Taki monitoring pozwala np. sprawdzić, ile wolnego miejsca zostało na dysku i poinformować o tym z wyprzedzeniem. Przykładowe parametry monitoringu infrastruktury to:
    • Wolne miejsce na dyskach twardych
    • Wolna/używana pamięć
    • Użycie procesora (CPU)
    • Ruch sieciowy
  • Alerty i powiadomienia – są nieodłącznym elementem monitoringu, który eliminuje konieczność obserwacji zebranych metryk przez człowieka. Tak więc, na przykład, gdy na podstawie zebranych metryk system stwierdzi, że dana aplikacja od 10 minut wykorzystuje 100% dostępnej pamięci RAM, automatycznie wysłany zostanie e-mail do zespołu utrzymaniowego, który będzie mógł podjąć odpowiednie działania.

Narzędzia

Te same narzędzia są wykorzystywane dla wszystkich rodzajów metryk i alertów i mogą być zintegrowane z dowolnego języka programowania.

  • InfluxDB – otwarta baza danych do przechowywania danych szeregów czasowych (Time Series Database). Np. wartości wykorzystania procesora odczytywane z czujników co 1s.
  • Grafana – otwarta, wieloplatformowa aplikacja internetowa do analityki i interaktywnej wizualizacji. Po podłączeniu do wspieranych źródeł danych (SQL, NoSQL, Loki, InfluxDB), możemy tworzyć różnego rodzaju wykresy i ustawiać odpowiednie powiadomienia.

Domenowe podejście do logiki biznesowej

Aplikacje są często budowane w architekturze warstwowej. Rozumiem przez to techniczny podział na pakiety typu: controllers, services, model itp. W kodzie model jest zazwyczaj prostym mapowaniem kolumny bazy danych na pola w POJO (brak relacji, tylko referencja przez ID). Logika biznesowa natomiast jest w pełni zaimplementowana w pakietach „services”. Taki podział nie jest błędny, ale może działać nieco gorzej w dużych projektach.

Problemy architektury n-warstwowej:

  • Brak logicznego podziału odpowiedzialności (tworzysz kod w oparciu o aspekty techniczne zamiast biznesowych)
  • Łatwiej o sytuację, w której „wszystko rozmawia ze wszystkim”
  • Anemiczny Model Domenowy
  • Często kompletny brak enkapsulacji
  • Trudności w oddzieleniu warstwy abstrakcji. Obiekty POJO są zazwyczaj współdzielone w całej aplikacji
  • Łatwiej testować poszczególne komponenty, ale ze względu na to, że logika jest rozproszona, trudno testować konkretne, kompleksowe przypadki biznesowe
  • Klasy z dużą liczbą zależności – trudniejsze do przetestowania
  • Z czasem brak czytelności i trudności w nawigacji. Na przykład wszystkie 100 serwisów całej aplikacji może znajdować się w jednym pakiecie
  • 100% powiązanie logiki biznesowej z frameworkami, takimi jak Spring. Nie jest to wielki problem, bo rzadko zmienia się framework w trakcie projektu, ale może zaciemniać logikę biznesową

Oto kilka różnych podejść, które można zastosować zamiast warstw:

Podział logiczny na poziomie architektury systemu to nie koniec – często zapominamy o separacji w samych aplikacjach. Rzadko kiedy jeden serwis równa się jednej funkcjonalności. Należy również wydzielać domeny i subdomeny (może być ich wiele), które razem tworzą konkretną usługę lub aplikację. Zasady komunikacji między nimi powinny być podobne do tych stosowanych na poziomie architektury systemu: ustalone API, komunikacja przez interfejsy, enkapsulacja itp.

Oferta handlowa vs rzeczywistość – przejście do implementacji

Oferta jest zazwyczaj przygotowywana przez inną osobę (lub zespół) niż ta, która zajmuje się wdrożeniem. Z tego powodu warto zaangażować stronę trzecią do szybkiej walidacji propozycji architektury na etapie ofertowania. Cross-check na pewno się opłaci, niezależnie od Twojego doświadczenia.

Przede wszystkim warto sprawdzić, czy projekt architektoniczny nie jest zbyt rozbudowany (overkill) w stosunku do potrzeb klienta. Jeśli zaczniesz od mikroserwisów jako pierwszego pomysłu, łatwo możesz wybrać coś o wiele za skomplikowanego. Na przykład, musisz zaprojektować jedną, raczej małą aplikację (jedna domena, kilka funkcjonalności), ale dopasowujesz do niej architekturę mikroserwisową uruchomioną na Kubernetesie, ze stosem ELK, monitoringiem itp. Czy naprawdę chcesz robić coś takiego przy jednej aplikacji, jeśli nie wiesz, jakie są plany na przyszły rozwój projektu?

Możesz również napotkać sytuację odwrotną – Twoja propozycja będzie niewystarczająca dla potrzeb klienta. Zdarzy się to prawdopodobnie rzadziej, ponieważ w ofertach wszystko jest zazwyczaj planowane z solidnym marginesem – ale jeśli tak się stanie, będziesz musiał znaleźć dobre argumenty na poparcie swojego podejścia. Dobrym pomysłem jest również ograniczenie się do architektury systemu na etapie oferty i pozostawienie architektury aplikacji na etap wdrożenia.

Co jeśli zrezygnujemy z mikroserwisów, a rok później okaże się, że są one jednak potrzebne? Jeśli zbudujesz aplikację monolityczną z odpowiednią strukturą i podziałem na domeny i subdomeny, zmiana architektury nie powinna wymagać rewolucji – będzie to po prostu naturalne przejście, które można przeprowadzić bez nadmiernego wysiłku.

Ograniczenia techniczne i biznesowe

Decyzje w tych obszarach będą ściśle zależeć od wymagań klienta – trudno tu zdefiniować sztywne zasady postępowania. Niektóre elementy, na które należy zwrócić uwagę:

  • Fizyczne rozmieszczenie maszyn
  • Aspekty prawne przechowywania danych
  • Dostępność technologii u danego dostawcy chmury
  • Ciężkie obliczenia algorytmiczne (serwery mogą być przystosowane specjalnie pod to)
  • Obciążenie systemu przez użytkowników

Duży ruch

Niezależnie od wybranego typu architektury systemu, aplikacja powinna być w stanie obsłużyć ruch określony przez klienta i być gotowa na ewentualne „nieoczekiwane” skoki. Trzeba uważać, aby nie wpaść w pułap „przedwczesnej optymalizacji”, ale jeśli masz już konkretne wymagania, musisz dostosować do nich rozwiązanie od samego początku.

Kilka rzeczy do rozważenia:

  • Skalowanie poziome i pionowe
  • Cache (pamięć podręczna)
  • Autoscaling
  • Load balancery
  • Testy wydajnościowe/obciążeniowe
  • Optymalizacja SQL
  • Replikacja bazy danych

Najlepszy scenariusz to taki, w którym klient jest w stanie zdefiniować konkretne metryki dotyczące wydajności systemu, takie jak liczba logowań na godzinę, X wizyt na konkretnej stronie w czasie X, 10 przetworzonych wniosków leasingowych, 100 wyszukiwań ofert na minutę itp. Na podstawie takich metryk można przygotować odpowiednie testy i właściwie dostosować system.

Przetwarzanie dużych plików lub ich dużej liczby

Należy tutaj wziąć pod uwagę dwa aspekty:

  • Aspekt architektoniczny – odseparowanie funkcjonalności „przetwarzania” do niezależnych usług technicznych, które mogą być skalowane zgodnie z aktualnymi potrzebami.
  • Aspekt techniczny – w większości przypadków przetwarzanie dużych plików sprowadza się do problemów z pamięcią. Jedną z metod, która może pomóc, jest przetwarzanie strumieniowe (nie ładujemy całego pliku do pamięci). Inną kwestią jest integracja z zewnętrznymi usługami obsługi plików, takimi jak AWS S3. Zawsze warto dokładnie zapoznać się z dokumentacją producenta i korzystać z dostarczonych rozwiązań. W przypadku S3 jest to API do przetwarzania plików w częściach – multipart uploads i downloads. Rozważ to na samym początku, nawet jeśli nie masz konkretnych wymagań co do rozmiaru przetwarzanych plików. Nie wymaga to zbyt wiele pracy, a zapewni Ci bezpieczeństwo w przyszłości.

Podsumowanie

Jak widać, system modularny może służyć jako dobra alternatywa dla mikroserwisów lub tradycyjnej architektury monolitycznej. Każde z tych podejść ma swoje zalety i ograniczenia. Które powinieneś rozważyć w swoim projekcie? Będzie to zależeć całkowicie od charakteru systemu, nad którym będziesz pracować. Aby nieco ułatwić tę decyzję, zapoznaj się z poniższymi tabelami podsumowującymi główne wady i zalety.

Mikroserwisy
Zalety Wady
  • Cloud Native
  • Fizyczna separacja modułów
  • Skalowanie poziome
  • Autonomia wdrożeniowa
  • Autonomia technologiczna
  • Wiele zespołów może współpracować nad niezależnymi komponentami
  • Płynne CI – brak konfliktów we współpracy
  • Luźne powiązanie (Loose coupling)
  • Trudna analiza komunikacji (projektowanie i wersjonowanie API)
  • Skomplikowana infrastruktura (logowanie, messaging, monitoring itp.)
  • Wysoki narzut na komunikację sieciową
  • Wiele jednostek wdrożeniowych
  • Duży wysiłek na starcie projektu
  • Trudne testowanie wszystkich funkcji biznesowych
  • Procesy CI/CD są zdecydowanie bardziej skomplikowane
  • Transakcje są często rozproszone

 

Monolit
Zalety Wady
  • Prosta infrastruktura
  • Szybkość i niezawodność komunikacji
  • Pojedyncza jednostka wdrożeniowa
  • Transakcyjność
  • Bezpieczeństwo komunikacji
  • Szybki start (kickoff)
  • Testowalność wszystkich funkcji biznesowych
  • Trudność w utrzymaniu struktury (ryzyko Big Ball of Mud)
  • Trudne utrzymanie – jedno miejsce, w którym coś może pójść nie tak
  • Trudniejsze skalowanie poziome (wymaga więcej zasobów, przynajmniej w teorii)
  • Utrudnione przejście do architektury rozproszonej
  • Trudne CI – dużo konfliktów i pracy nad wspólnymi komponentami
  • Stabilność – błąd w jednym module może wpłynąć na całą aplikację
  • Stałe przywiązanie do jednej technologii

 

Modularny Monolit
Zalety Wady
  • Prosta infrastruktura
  • Szybkość i niezawodność komunikacji
  • Pojedyncza jednostka wdrożeniowa
  • Bezpieczeństwo komunikacji
  • Szybki start (kickoff)
  • Łatwa migracja do architektury rozproszonej
  • Autonomiczne moduły biznesowe
  • Struktura modularna
  • Testowalność wszystkich funkcji biznesowych
  • Otwarta droga do przejścia z monolitu na mikroserwisy
  • Luźne powiązanie
  • Duplikacja danych
  • Trudniejsze utrzymanie spójności danych
  • Trudne utrzymanie – jedno miejsce, w którym coś może pójść nie tak
  • Trudniejsze skalowanie poziome (więcej zasobów, przynajmniej w teorii)
  • Stałe przywiązanie do jednej technologii

 

Przeanalizuj swoje potrzeby, porozmawiaj z zaufanymi członkami zespołu i wybierz architekturę, która najlepiej posłuży projektowi – nie tylko dzisiaj, ale jutro, a nawet za wiele lat.

W Pretius mamy ponad 15 lat doświadczenia w budowaniu skalowalnych rozwiązań programistycznych dla dużych przedsiębiorstw. Jeśli więc chcesz skonsultować swoje pomysły, napisz do nas na adres hello@pretius.com lub skorzystaj z poniższego formularza kontaktowego. Wstępne konsultacje są zawsze bezpłatne.

Dodatkowo, jeśli potrzebujesz więcej informacji na temat wzorców projektowych i architektonicznych, oto kilka źródeł, które warto przeczytać:

FAQ dotyczące modularnej architektury oprogramowania

Oto odpowiedzi na popularne pytania dotyczące modularnej architektury oprogramowania.

Jakie są korzyści z architektury mikroserwisowej?

Architektura mikroserwisowa oferuje liczne korzyści, takie jak natywne wsparcie dla chmury (cloud native), fizyczna separacja modułów, skalowanie poziome, luźne powiązanie, autonomia wdrożeniowa i technologiczna, płynne CI oraz możliwość współpracy wielu zespołów nad niezależnymi komponentami.

Co wyróżnia projektowanie architektury modularnej?

Modularny monolit łączy niektóre aspekty monolitu i architektury mikroserwisowej. Pozwala na zachowanie prostoty wdrożenia przy jednoczesnym logicznym podziale na autonomiczne domeny biznesowe.

Szukasz firmy tworzącej oprogramowanie?

Pracuj z zespołem, który pomógł już dziesiątkom rynkowych liderów. Umów spotkanie, by dowiedzieć się:

  • Jak działają nasze produkty
  • Jak możesz oszczędzić czas i pieniądze
  • Czym nasze rozwiązania różnią się od konkurencji

Przebieg kontaktu z Pretius

Dbamy o bezpieczeństwo Twoich danych: Certyfikat ISO

Działamy zgodnie z normą ISO 27001, zapewniając najwyższy poziom bezpieczeństwa Twoich danych.
certified dekra 27001
© 2026 Pretius. All right reserved.