Przejdź do treści

DevStyle - Strona Główna
Architektura Ewolucyjna, DDD i Fitness Functions. Jak budować skalowalne systemy? (Q&A)

Architektura Ewolucyjna, DDD i Fitness Functions. Jak budować skalowalne systemy? (Q&A)

Team devstyle

29 stycznia 2026

Backend

Zamiast zgadywać, co będzie potrzebne za trzy lata, skup się na tym, co jest potrzebne dzisiaj. W 135. odcinku DevTalk Maciek Jędrzejewski (Head of IT w OEKO-TEX®) wyjaśnia, jak budować systemy, które ewoluują razem z wymaganiami, nie drenując budżetu na start.

Poniżej znajdziesz wybrane pytania i odpowiedzi z tej rozmowy.

Q: Co to jest architektura ewolucyjna?

A: W najprostszym ujęciu architektura ewolucyjna polega na realizowaniu w danej chwili wyłącznie tego, co jest niezbędne do spełnienia obecnych wymagań, ewentualnie uwzględniając potrzeby, które pojawią się w bardzo bliskiej perspektywie, na przykład w ciągu dwóch, trzech tygodni lub miesiąca.

Przez lata pracy zauważyłem tendencję do nadmiernego komplikowania rozwiązań już na samym starcie. Nawet gdy rozumiemy wymagania biznesowe, często przy wytwarzaniu oprogramowania chcemy wykorzystać wszystkie technologie, o których słyszeliśmy, co nie zawsze jest uzasadnione.

Q: Czy architekturę ewolucyjną można nazwać just-in-time architecture?

A: Tak, jednak z ważnym zastrzeżeniem. Określenie just-in-time pasuje, o ile opiera się na zdrowym rozsądku, a nie chaotycznym działaniu z dnia na dzień. Podejście to polega na reagowaniu w momencie, gdy widzimy realne ryzyko (np. że system wysypie się” w kolejnym kwartale), zamiast budowania rozwiązań na lata do przodu dla milionów użytkowników, których jeszcze nie ma.

Aby precyzyjnie określić ten „właściwy moment” na zmiany (czyli kiedy obecna architektura przestaje wystarczać), należy zweryfikować granice wytrzymałości obecnego rozwiązania. W tym celu warto wykorzystać framework k6 do przeprowadzania testów obciążeniowych na krytycznych elementach systemu.

Taki test (symulujący np. 10 000 użytkowników) pełni rolę pierwszej fitness function, która wyznacza nam limit obecnego rozwiązania . Dzięki temu nie działamy po omacku. Jeśli widzimy, że osiągnęliśmy np. jedną trzecią tego limitu, jest to sygnał, by z wyprzedzeniem zacząć planować wdrożenie bardziej skalowalnego rozwiązania.

Q: Czym są fitness functions, po co się je tworzy i do czego służą?

A: Termin fitness functions spopularyzowali twórcy koncepcji architektury ewolucyjnej: Neal Ford, Rebecca Parsons i Patrick Kua, w książce Building Evolutionary Architectures. Fitness functions pomagają zdefiniować granice wytrzymałości architektury. Zamiast opierać się na intuicji i zakładać, że problemy w danym obszarze mogą wystąpić za jakiś czas, warto dysponować twardymi danymi. Funkcje te zwracają uwagę na konkretne elementy systemu. 

Fitness function nam pozwala na to, żebyśmy zobaczyli, jak ten nasz system działa nie tylko od strony obsługi użytkownika, ale też od strony utrzymywalności naszego kodu, bo może się okazać, że architektura, którą sobie wymyśliliśmy, sprawdzała się do tej pory dobrze dla zespołu czteroosobowego, ale mamy teraz nagle 20 programistów, no i oni wszyscy depczą sobie po palcach, i mamy w tym momencie problem wydajnościowy, jeżeli chodzi o nasz team developerski.

Przykłady fitness functions:

  • Test zapewniający, że nasze endpointy API odpowiadają w akceptowalnym czasie (np. zakładamy, że 95% odpowiedzi mieści się poniżej 200 milisekund).
  • System jest w stanie utrzymać minimalną liczbę żądań na sekundę pod obciążeniem.
  • Weryfikacja czy wrażliwe dane są szyfrowane w tranzycie i spoczynku (funkcja dla bezpieczeństwa).
  • Utrzymanie minimalnych procentów pokrycia testami.
  • Używanie narzędzi do statycznej analizy kodu.

Więcej na temat fitness functions:

Q: Czy architektura ewolucyjna łączy się z DDD?

A: Tak, te podejścia idealnie się uzupełniają i nie wykluczają się wzajemnie. Fundamentem skutecznej architektury ewolucyjnej jest poprawne rozpoznanie domeny biznesowej jeszcze przed napisaniem pierwszej linii kodu.

Proces ten przebiega według następujących kroków:

  1. Rozpoznanie procesów: wykorzystanie technik warsztatowych, takich jak Event Storming czy Domain Storytelling, do zmapowania procesów z ekspertami domenowymi.
  2. Wyodrębnienie poddomen: pogrupowanie procesów w obszary („pudełeczka”), które stają się poddomenami biznesu (jest to element strategicznego DDD) .
  3. Definicja Bounded Contexts: stworzenie wielu modeli zamiast jednego zunifikowanego, co prowadzi do powstania Bounded Contexts (ograniczonych kontekstów) i map kontekstów .
  4. Wydzielenie modułów: wykorzystanie Bounded Contexts do wydzielenia fizycznych modułów aplikacji technicznej (np. folderów w projekcie), co zapobiega powstaniu tzw. „potworka” 

Q: Jakie praktyki w zespole pomagają w utrzymaniu architektury ewolucyjnej?

A: Najprostszym krokiem na start jest wprowadzenie Dziennika Decyzji Architektonicznych (Architecture Decision Log). To narzędzie wymusza spotkania w gronie developerów i wspólne uzasadnianie wyborów technologicznych.

W zależności od potencjału zespołu, warto stopniowo wdrażać kolejne usprawnienia:

  • Architecture Decision Record: zapisywanie problemu, decyzji, konsekwencji i alternatyw.
  • Karuzele developerskie: codzienne, krótkie spotkania wyłącznie dla programistów, służące omawianiu bieżących blokad technicznych.
  • Techniki pracy grupowej: wprowadzenie praktyk takich jak pair programming czy swarming.

Q: Do jakich projektów pasuje architektura ewolucyjna?

A: Architektura ewolucyjna jest rekomendowana przede wszystkim do projektów typu Greenfield (nowych systemów), gdzie budowę rozpoczynamy od zera. Podejście to pozwala zachować pragmatyzm, uniknąć kosztownych błędów na starcie i dopasować technologię do realnych potrzeb biznesowych.

Oto szczegółowy podział zastosowań:

  1. Projekty Greenfield (Idealne środowisko). Dla każdego nowego systemu rekomendowane jest podejście pragmatyczne, czyli ewolucyjne. Kluczowe korzyści w tym obszarze to:

  • Szybkie MVP: Umożliwia wypuszczenie produktu w 2–3 tygodnie w celu weryfikacji rynku.
  • Unikanie overengineeringu: Chroni przed pokusą użycia skomplikowanych technologii (wielka trójka”: Kubernetes, Kafka, Redis), gdy na starcie wystarcza prosta infrastruktura (np. App Service i baza danych).
  • Zarządzanie niepewną skalą: Zamiast projektować system na miliony użytkowników (jak dla Billa Gatesa czy Elona Muska), budujemy go na obecne potrzeby i najbliższy realny wzrost.

  1. Projekty w specyficznym kontekście organizacyjnym Architektura ewolucyjna adaptuje się do otoczenia, a definicja prostoty” nie jest sztywna:

  • Jeśli firma posiada już rozwiniętą infrastrukturę (np. klastry Kubernetes i zespół utrzymaniowy), to rozwiązaniem prostym i ewolucyjnym” jest wpięcie się w ten ekosystem.
  • Decyzje opierają się na rozpoznaniu kompetencji zespołu, a nie tylko na podręcznikowych definicjach.

  1. Projekty Legacy (Ograniczone zastosowanie) W przypadku starych, istniejących systemów (Legacy) architektura ewolucyjna działa inaczej:

  • Nie da się zacząć od zera” w modelu ewolucyjnym.
  • Wymagane jest podejście polegające na wydzielaniu części systemu do nowych struktur (na bazie analizy biznesowej i Bounded Contexts), zamiast organicznego wzrostu całego systemu.

Q: Co zawiera repozytorium do książki „Master Software Architecture”?

A: Repozytorium na GitHubie zawiera kompleksowy opis autorskiego podejścia do architektury ewolucyjnej, opracowanego przez Macieja Jędrzejewskiego i Kamila Bączka. Jego wizytówką jest bardzo szczegółowy plik Readme, który prowadzi czytelnika przez całą ścieżkę budowy oprogramowania.

Od wielu osób usłyszeliśmy, że jest to najlepsze Readme, jakie czytali w otwartych repozytoriach na GitHubie.

Treść repozytorium podzielona jest na cztery rozdziały, odpowiadające 4 krokom ewolucji aplikacji:

  1. Prostota (Simplicity): Rozwiązania na start projektu.
  2. Utrzymywalność (Maintainability): Poprawa struktury kodu, gdy staje się trudny w utrzymaniu.
  3. Wzrost (Growth): Reakcja systemu na zwiększony ruch i skalę.
  4. Złożoność (Complexity): Wprowadzanie zaawansowanych wzorców (np. agregaty) w odpowiedzi na złożoność biznesową.

Każdy z tych rozdziałów stanowi „zamkniętą pigułkę wiedzy”, która na praktycznych przykładach pokazuje analizę domeny, procesy, wyznaczanie Bounded Contexts oraz tworzenie fizycznych modułów.

Architektura ewolucyjna to nie pójście na łatwiznę, ale czysty pragmatyzm, który chroni przed overengineeringiem. Aby zobaczyć, jak to podejście przekłada się na konkretne linijki kodu, odwiedź repozytorium na GitHubie. A po pełny kontekst i lekcje z 13-letniej kariery gościa (od C++ po Node.js), włącz 135. odcinek DevTalk!

 

Zobacz również