Jak zostać architektem oprogramowania?

Aby projektować dobrą architekturę oprogramowania trzeba najpierw zaznajomić się z jej przesłankami, rodzajami, a także sposobami wdrażania. Architektura nie jest przecież czymś stałym, co wszędzie implementowane jest w jednakowy sposób.

Architektura oprogramowania

Poruszane dzisiaj zagadnienie nie jest terminem posiadającym sztywną definicję. Dzieje się tak, ponieważ architektura oprogramowania dzieli się na kilka grup, w różnych zakresach. Jednak ogólnie rzecz biorąc architektura oprogramowania to sposób na zorganizowanie systemu, środowiska, jego elementów oraz komunikacji pomiędzy nimi. Jednym z podziałów architektury, który możemy wyodrębnić jest podział ze względu na tzw. „głębokość” i to na nim się dzisiaj skupimy. Wyróżnić możemy trzy poziomy architektury w tym podziale: poziom przedsiębiorstwa, systemu oraz aplikacji. W tym wpisie wejdziemy głębiej w tematykę dwóch ostatnich, czyli architektury aplikacyjnej oraz systemowej.

Dlaczego architektura oprogramowania jest potrzebna?

Zanim przejdę do „mięsa” dzisiejszego wpisu, muszę powiedzieć trochę o tym dlaczego projektowanie architektury jest bardzo ważne. Wszyscy chyba zgodzą się ze mną, że etat dla architekta w systemie klasy CRUD będzie zbędny, jednak co w sytuacji kiedy nasz system jest trochę większy? Wyobraźmy sobie 20 programistów i programistek pracujących nad nowym, bardzo innowacyjnym systemem e-commerce. Zdaję sobie sprawę, że w internecie znajdziemy mnóstwo pomysłów na rozwiązanie takiego problemu, jednak załóżmy, że nasz system jest bardzo innowacyjny i potrzebujemy nowy produkt (heheszki z e-commerce’ów). Potrafisz wyobrazić sobie ten chaos kiedy Ci wszyscy programiści rzucą się do burzy mózgów? Zaczną się propozycje w stylu: „robimy mikroserwisy”, „słyszałem, że DDD jest fajne”, „rok temu na konferencji usłyszałem, że nie robi się już mikroserwisów tylko modularne monolity„, „użyjmy modnego graph ql”. Masz może flashbacki? Ja niestety mam. Systemy „projektowane” w ten sposób to tykające bomby. 

Dobieranie rozwiązań programistycznych na zasadzie wyboru tych modnych, zazwyczaj kończy się failem. Poprzedźmy development o miarodajny planning oraz analizę, z których wyniknie klasa złożoności naszego problemu, a do której dopasujemy styl programistyczny czy architektoniczny. Zacznijmy analizować i projektować tak, aby dobierać rozwiązanie do problemu, a nie na odwrót. I to jest właśnie zadanie architekta oprogramowania, aby zaprojektować coś, co później programiści wdrożą zgodnie z założeniami. Jednak czy można robić to bez architekta? Pewnie, że można, lecz wtedy zespół potrzebuje solidnego tech lead-a, który weźmie na siebie obowiązek projektowania i podejmowania decyzji architektonicznych.

Jak robi się architekturę?

Odpowiedź na to pytanie nie jest trudna, jest długa. Jak już wcześniej wspomniałem architektura to nie jest tylko wybór wzorców projektowych, sposobu modularyzacji czy technologii. W głównej mierze jest to zadanie wyboru konkretnych rozwiązań, ale na podstawie wiedzy o systemie, który chcemy zaprojektować. Przejdźmy teraz przez jedne z najważniejszych, ogólnych etapów tworzenia architektury systemu. 

  1. Swoją przygodę z projektowaniem architektury powinniśmy rozpocząć od poznania biznesu. Odkrycie jego procesów, domen, nałożenie bounded contextów, a także zrozumienia celu oprogramowania, które ma powstać lub już istnieje. Metod odkrywania biznesu jest bardzo wiele, lecz gorąco polecam Event Storming, który pozwala na łatwe modelowanie systemu na każdym poziomie. 
  2. Stosując ES w połączeniu z Domain Driven Design odkryjemy wiele czynników architektonicznych motywujących nasze późniejsze wybory, a także częściowo zaprojektujemy nasz system. Architectural drivers to zbiór wymagań, wyzwań czy warunków, które muszą zostać uwzględnione podczas tworzenia architektury. Przykładowo, nasz system może wymagać dużej szybkości zapisu danych, ale niekoniecznie ich spójności, co prawdopodobnie determinować będzie użycie bazy nierelacyjnej.
  3. Posiadając wiedzę o biznesie, który stoi za oprogramowaniem oraz wymagania i jego środowisko, możemy zacząć podejmować decyzje architektoniczne. Architectural decision records to zbiór decyzji, jakie podjęliśmy lub podejmiemy (zbiór decyzji, który żyje zawsze i zawsze powinien być aktualny!) uwzględniając zagrożenia, wymagania i inne drivery architektoniczne poznane podczas odkrywania biznesu. 
  4. Rozumiejąc zagrożenia, wymagania jakości i posiadając już pewne podjęte decyzje, możemy przejść do projektowania oprogramowania. Musimy uwzględnić tutaj wszystko czego dowiedzieliśmy się do tej pory, a następnie przekuć to w gotowy plan systemu. Pomocne będą tutaj wyniki sesji Event Stormingowych połączonych z DDD. Udzielą nam one informacji na temat modułów i sposobu interakcji pomiędzy nimi. Poznamy reguły i niezmienniki domenowe zagnieżdżone w odkrytych procesach, co pozwoli nam na ich implementację. To tutaj musimy podjąć decyzje o tym, jaką architekturę systemową i aplikacyjną powinniśmy wybrać. Całość wypada uwiecznić, tak, aby możliwy był powrót do naszej wizji. Może to być UML, własna notacja lub coś, co już istnieje i doskonale się do tego nada: model wizualizacji architektury C4 (context, container, component, code).
  5. Nadzór i pomocna dłoń dla zespołów wykonujących „prace rzemieślnicze” czyli tzw. technical leadership. Konieczna jest kontrola procesu wdrażania systemu, a także korygowanie wizji o pojawiające się w trakcie implementacji nowe drivery architektoniczne.

Architektura systemowa

Zgodnie z obietnicą ze wstępu, spróbuje teraz wskazać różnice pomiędzy dwoma najgłębszymi rodzajami architektury. Na początek weźmy na tapet architekturę systemową. Tak, jak wspomniałem wcześniej, jest to wysoki poziom abstrakcji systemu opisujący jego kształt, środowisko i sposoby komunikacji w obrębie nadgrup funkcjonalnych. Architekturą systemową nazywać będziemy więc sposób w jaki zorganizujemy wspomniane aspekty w naszym oprogramowaniu. Większość z nas zapewne słyszała takie terminy jak: mikroserwisy, modularne monolity czy monolity. Są to właśnie rodzaje architektury systemowej, o których powiem w przyszłości, jednak aby nie zostawić Cię bez pewnej dawki wiedzy, spróbuję po krótce przejść po najpopularniejszych rodzajach architektury systemowej.

  • Architektura monolityczna cechuje się wysokimi współzależnościami funkcji i komponentów systemu. Jedna jednostka wdrożeniowa nieposiadająca atomowości, co skutkuje problemami ze skalowalnością. Z drugiej strony: łatwe testowanie oraz wdrożenie, a także niska złożoność. 
  • Architektura modularnego monolitu, to sposób na rozwiązanie niektórych problemów czystych monolitów. Wciąż posiadamy jedną jednostkę wdrożeniową, jednak w jej obrębie istnieje wiele podmodułów, które działają niezależnie od siebie (brak silnych powiązań pomiędzy nimi). Co dają nam te moduły? Swobodę architektury aplikacyjnej w ich wnętrzu, własne API czy kolejkę. Dodatkowym atutem jest możliwość szybkiego przejścia do architektury typu SOA.
  • Architektura zorientowana na usługi (SOA), to wiele jednostek wdrożeniowych, które mogą się ze sobą komunikować, a niedostępność jednej nie skutkuje unieruchomieniem całego systemu. Daje to swobodę wyboru technologii, architektury aplikacyjnej, a także niezależność zespołów programistycznych. Rozwiązuje się problem skalowalności, ponieważ możemy teraz skalować jedynie te elementy systemu, które tego wymagają. Ten rodzaj architektury ma jednak sporo wad, m.in. konieczność rozproszonej kompensacji (wcześniej transakcje bazodanowe rozwiązywały ten problem), złożoność technologiczna, wiele elementów wymagających utrzymania i wiele wiele więcej.

Architektura aplikacyjna

Czymś, co wchodzi w skład modułów, serwisów czy całej instancji systemu jest architektura aplikacyjna. Określa ona strukturę i logiczny sposób działania mechanizmów w obrębie danej grupy. W przypadku SOA, grupą tą będą poszczególne usługi, które mogą implementować inną architekturę aplikacyjną. Podobnie będzie w przypadku modularnego monolitu, gdzie moduły mogą używać innych struktur. W przypadku monolitu, całe wnętrze określać będzie jeden typ architektury aplikacyjnej. Jak się pewnie domyślasz istnieje wiele typów takiej architektury. O nich również opowiem w przyszłych wpisach, jednak tak, jak poprzednio, przejdźmy teraz przez kilka popularnych rodzai architektury aplikacyjnej.

  • Architektura warstwowa, o której już niejednokrotnie wspominałem, to chyba najpopularniejszy rodzaj architektury aplikacyjnej. W tym podejściu mamy kilka warstw przez które przechodzi zapytanie. Każda z tych warstw ma inne zadanie: warstwa UI – odebranie zapytania i delegacja do niższej warstwy, warstwa logiki – realizacja procesów biznesowych, warstwa dostępu do danych – zapis i odczyt, np. na bazie danych.
  • Architektura hexagonalna nazywana także architekturą portów i adapterów, to architektura której głównym celem jest tworzenie słabo związanych ze sobą komponentów. Dzięki użyciu tzw. portów oraz adapterów możemy w łatwy sposób wymieniać poszczególne komponenty, co np. ułatwia testowanie.
  • Architektura pipes & filters, która w głównej mierze polega na posiadaniu jasno zdefiniowanego procesu za pomocą łańcucha połączonych ze sobą potoków i filtrów. Zapytania przetwarzane są w filtrach, a następnie za pomocą potoków (pipes) służących także do buforowania lub walidacji, delegowane są do kolejnych filtrów.
  • Architektura w stylu master-slave, zwana także generic kernel, to rodzaj architektury, w której do części generycznej systemu podpinane są niezależne komponenty (slaves). Jądro używa podłączonych komponentów do realizacji operacji, a na podstawie wyników których podejmuje kolejne kroki. 

Podsumowanie

  • Projektowanie dobrej architektury oprogramowania to proces długi i skomplikowany, który wymaga wysokiej wiedzy z przeróżnych zakresów z dziedziny IT.
  • Posiadanie architekta w projekcie nie jest czymś must have. W wielu przypadkach wystarczy tech lead z dużym doświadczeniem, który przejmie obowiązki roli architekta.
  • Projektując i wdrażając architekturę najczęściej pracujemy z jej dwoma najgłębszymi poziomami: architekturą systemową oraz aplikacyjną.
Autor wpisu

blog@orbisbit.com

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Sprawdź również
  • CQRS – Command Query Responsibility Segregation

    Command Query Responsibility Segregation czyli CQRS. Jest to wzorzec projektowy, który rozdziela zadania odczytu i zapisu do osobnych modeli. Sprawdź ten wpis, aby dowiedzieć się kiedy i jak z niego skorzystać.

    Zobacz wpis

  • GRASP – kolejny zbiór zasad Clean Code do zapamiętania

    Pewnie większość z Was słyszała o zasadach SOLID. Są one bardzo rozpowszechnione i dosyć często stosowane, ale czy słyszeliście o GRASP? General Responsibility Assignment Software Patterns, to kolejna dawka zasad czystego kodu do zapamiętania.

    Zobacz wpis

  • Wzorzec strategia (strategy pattern)

    Jeżeli masz dość if-ologii w swoim kodzie, to konieczne sprawdź czym jest czynnościowy wzorzec projektowy strategia. Pozwala on mądrze obsługiwać różne scenariusze w procesie i jednocześnie być fancy pod względem zasad SOLID.

    Zobacz wpis