Architektura oprogramowania ≠ projektowanie oprogramowania

Architektura oprogramowania stosunkowo często mylona jest z projektowaniem oprogramowania nawet przez samych developerów. I nie jest to kwestia tylko i wyłącznie polska (“Zleciłem jednemu architektowi zaprojektowanie mi domu”). Zakorzenione skojarzenia potrafią przedrzeć się przez najsilniejsze mury wiedzy. W dzisiejszym wpisie poprawiamy rozmyte linie technicznych pojęć.

Transparent Data
Blog Transparent Data
6 min readOct 28, 2019

--

Architektura oprogramowania: definicja

Najczęściej podaje się, że architektura oprogramowania to tworzenie podstawowej organizacji systemu (jego komponentów, reguł budowy i rozwoju), ale powinniśmy raczej mówić, że to proces przekształcania takich cech oprogramowania jak elastyczność, skalowalność, wykonalność, możliwość ponownego użycia czy bezpieczeństwo w ustrukturyzowane rozwiązanie spełniające oczekiwania techniczne i biznesowe.

Atrybuty jakości a architektura oprogramowania

Ta definicja lepiej opisuje wzajemne powiązania wszystkich osób zaangażowanych w proces wytwórczy danego rozwiązania i prowadzi nas do pytania o cechy oprogramowania (tzw. atrybuty jakości), które mogą wpływać na projekt architektury oprogramowania. Istnieje długa lista cech, które reprezentują głównie wymagania biznesowe i operacyjne, oprócz samych wymagań technicznych, a znaleźć ją możecie choćby na Wiki [LINK DO LISTY CECH OPROGRAMOWANIA].

Dla przykładu: jeżeli dany Klient, który zleca nam stworzenie produktu, działa na szybko zmieniającym się rynku i wiemy, że jego model biznesowy będzie się często zmieniał, architektura produktu powinna uwzględniać takie atrybuty jak rozszerzalność, modułowość i utrzymywalność nazywaną też czasem w naszym języku pielęgnacyjnością (extendable, modular and maintainable). W przeciwnym wypadku produkt nie sprosta szybkim modyfikacjom pod presją czasu.

Wzorce architektury oprogramowania

Gdy zaczynamy mówić o architekturze oprogramowania, nie sposób nie wspomnieć o istniejących wzorcach. Architektura mikroserwisów, architektura warstwowa, peer-to-peer, bezserwowa czy sterowana zdarzeniami — to tylko niektóre z nich.

Cytując Wikipedię:

Wzorzec architektoniczny (ang. architectural pattern) — uznany i sprawdzony sposób rozwiązania danego problemu z zakresu architektury oprogramowania. Wzorce architektoniczne określają ogólną strukturę danego systemu informatycznego, elementy z jakich się składa, zakres funkcji realizowany przez dany element jak również zasady komunikacji pomiędzy poszczególnymi elementami.

Spójrzmy dla przykładu na architekturę mikroserwisów, która stała się jednym z najpopularniejszych wzorców architektonicznych ostatnich lat.

Achitektura mikroserwisów

Architektura tzw. MicroServices opiera się na opracowaniu małych, niezależnie działających od siebie usług modułowych, w których każda usługa rozwiązuje określony problem lub wykonuje unikalne zadanie.

Istotnym jest, że moduły te komunikują się ze sobą za pośrednictwem dobrze zdefiniowanego interfejsu API, który służy realizacji wskazanego celu biznesowego.

Architektura mikroserwisów

Skoro usługi są stosunkowo małe, niezależne i luźno powiązane (możemy podpinać je dowolnie w ramach jednego API), to nie muszą korzystać z tych samych bibliotek, technologii ani struktur. Każda usługa (mikroserwis) jest również samodzielnie odpowiedzialna za przechowywanie swoich wyników. Użytkownicy końcowi nie wywołują bezpośrednio usług, a mają do nich dostęp za pośrednictwem bramy interfejsu API.

Dzięki temu, usługi można modyfikować i wdrażać bez konieczności aktualizacji wszystkich użytkowników i całego systemu. Architektura mikroserwisów przydaje się zatem przede wszystkim przy ogromnych aplikacjach, które powinny być łatwo skalowalne i otwarte na wdrażanie szybkich zmian. Niezależne wdrożenia i niezależne opracowywanie usług — to właśnie te cechy wyniosły wzorzec MicroServices na developerskie podium.

O zaletach i wadach architektury mikroserwisów pisaliśmy też w oddzielnym artykule, porównując ją z monolitami:

Inne wzorce architektur (wybrane dwa — na prawą i lewą nogę)

Architektura bezserwerowa

Innym znanym przykładem wzorca architektury oprogramowania jest architektura bezserwowa. W tym szkielecie zarządzanie złożonością serwerów i zarządzanie zapleczem zależy od firm trzecich i to, co rzuca się w oczy, to podział na dwie główne kategorie: „Backend as a service (BaaS)” oraz „Functions as a Service (FaaS)”.

Architektura bezserwowa

Architektura sterowana zdarzeniami

Ta architektura zależy od producentów zdarzeń i konsumentów zdarzeń.

Główną koncepcją jest oddzielenie poszczególnych części systemu, a każda część zostaje uruchomiona, gdy uruchomione zostaje interesujące wydarzenie z innej części. Na przykład — moduł zakupu i moduł dostawcy: jeśli klient dokona zakupu, moduł zakupu wygeneruje zdarzenie orderPending, którego “wyczekuje” moduł dostawcy, po to by z kolei wypełnić swoje zakodowane zadania, takie jak np. zamówienie większej ilości produktu do magazynu itp.

Architektura sterowana zdarzeniami

Jak się za chwilę przekonacie, koncepcja wzorców architektonicznych jest bardzo podobna do koncepcji wzorców projektowych. Te ostatnie dotyczą problemów z komunikacją, tworzeniem lub organizacją obiektów i klas.

Projektowanie oprogramowania: definicja

Jak już możecie się domyślić, skoro architektura oprogramowania odpowiedzialna jest za opracowanie szkieletu i infrastruktury oprogramowania, to projektowanie oprogramowania odpowiedzialne jest za tworzenie samego kodu — metod, klas i funkcji. Z tak jakby wysokiego poziomu projektowania schodzimy zatem na niski.

Jak tworzyć dobry kod? Zasady SOLID

Jeśli kod ma być naprawdę czysty, to wypada tu wspomnieć o pięciu podstawowych zasad projektowania oprogramowania, stworzonych przez słynnego Roberta Martina, SOLID.

SOLID czyli S jak Single Responsibility, O jak Open/Closed, L jak Liskov Substitution, I jak Interface Segregation oraz D jak Dependency Inversion:

  • Single Responsibility — zasada pojedynczej odpowiedzialności traktuje o tym, że ​​każda klasa musi mieć jeden cel, odpowiedzialność i powód zmiany. Innymi słowy, każda klasa ma być odpowiedzialna za jedną konkretną rzecz/zadanie, a jeśli ją modyfikujemy, to z jednego, znów bardzo konkretnego powodu. W ten sposób, z pozoru zwiększa się liczba klas, ale jednocześnie i eliminujemy liczbę klas, które zawierają tyle funkcjonalności, że linijki ich kodu mierzymy w setkach i tysiącach. A każdy doświadczony programista doskonale wie, że mocno rozbudowane klasy w pewnym momencie prowadzą do ogromnych problemów i z czasem stają coraz mniej czytelne,
  • Open/Closed — zasada otwarty/zamknięty mówi o tym, że klasa powinna być otwarta na rozszerzenia, ale zamknięta dla modyfikacji. Krótko mówiąc, powinieneś być w stanie dodać więcej funkcji do jednej klasy, ale nie edytować istniejących już metod. Jak bowiem powszechnie wiadomo, zmiana w jednym miejscu kodu, często prowadzi do zmiany w innym miejscu, a to z kolei nierzadko powoduje awarie systemu,
  • Liskov — zasada podstawienia Liskov (od programistki, Barbary Liskov) obliguje programistę do korzystania z dziedziczenia w sposób, który nie złamie logiki aplikacji w żadnym momencie i w skrócie sprowadza się do tego, że w miejscu klasy bazowej można zawsze użyć dowolnej klasy pochodnej. Zatem jeśli klasa potomna o nazwie XyClass dziedziczy od klasy nadrzędnej AbClass, klasa potomna nie będzie replikować funkcji klasy nadrzędnej w sposób, który zmienia zachowanie klasy nadrzędnej. Można więc łatwo używać obiektu XyClass zamiast obiektu AbClass bez naruszania logiki aplikacji.
  • Interface Segregation — zasada segregacji interfejsu podkreśla, że należy tworzyć stosunkowo małe, dobrze skategoryzowane interfejsy, tak aby klasy nie musiały implementować metod, których nie używają i nie potrzebują. Innymi słowy, należy tak ustrukturyzować kod, aby klasa nigdy nie była zmuszana do implementacji funkcji, która nie jest ważna dla jej celu.
  • Dependency Inversion — zasada inwersji zależności traktuje o tym, że metody nie powinny zależeć od konkretnego typu, a od interfejsu. Inaczej mówiąc, jeśli pewna klasa ex: Hajs zależy od klasy Użytkownicy, wówczas tworzenie instancji obiektu użytkownika powinno pochodzić spoza klasy Hajs.

Co jeszcze warto wiedzieć o projektowaniu programowania?

Poza zasadami SOLID, pojęcie które powinno Ci się obić o uszy, gdy mowa o projektowaniu oprogramowania, to tzw. design patterns, czyli wzorce projektowe.

Nie będzie ich tutaj szczegółowo opisywać, ale factory pattern czy adapter pattern, to wzorce z których korzysta każdy programista w swojej codziennej pracy. Wzorce projektowe, to najprościej mówiąc, uniwersalne, sprawdzone w praktyce rozwiązanie często pojawiających się problemów projektowych. Opisuje powiązania i zależności pomiędzy klasami i obiektami, a także upraszcza tworzenie, modyfikację oraz pielęgnację kodu źródłowego.

Pełną listę wzorców projektowych znajdziecie na Wiki [LINK].

Mogą zainteresować Cię również:

--

--