Enterprise SOLID dla architekta czystych kodów – łączenie

utworzone przez | 01/03/2020 | Architektura, SOLID w czystej architekturze

Zaawansowana część cyklu o zasadach SOLID: odsłona druga. Wiesz jak prawidłowo grupować klasy wewnątrz komponentów. Teraz pora na zasady skutecznego łączenia ich ze sobą. Będzie o tym jak zachować zdrowe relacje, a na tych niezdrowych zaaplikować właściwą terapię.

W poprzedniej części wprowadziliśmy odrobinę teorii czym są zasady SOLID w odniesieniu do komponentów. Następnie skupiliśmy, się jak projektować komponenty, czyli w skrócie zapewniać właściwą koherencję klas (spójność) wewnątrz nich.

Zasady Łącz i działaj

Pora wprawić maszynerię w ruch, ucząc się jak budować relację między komponentami.

Żaden komponent nie jest samoistną wyspą: każdy stanowi ułamek aplikacji, część ekosystemu. 

Luźno, na podstawie cytatu z Ernesta Hemingwaya – Komu bije dzwon

Mozartify

Tomek, właściciel startupu Mozartify, z zadowoleniem patrzył na wykres pokazujący przyrost nowych użytkowników usługi. Wszystko dzięki Jankowi, który wraz ze swoim zespołem, w ekspresowym tempie zaimplementował niezbędny moduł subskrypcji.

Tomek wpadł na pomysł, aby spersonalizować ofertę dla obecnych użytkowników i wprowadzić okresowe promocje. Czyli atrakcyjny program lojalnościowy, polegający na ekstra punktach (biciach serca) dodawanych po przedłużeniu subskrypcji.

Janek zebrał wymagania i z zespołem zaczęli szkicować architekturę nowego rozwiązania.

Punkt wyjściowy

Pozwól, że przypomnę ci w telegraficznym skrócie układ katalogów i komponenty projektu. 

Nowy komponent Mozartify\Marketplace
Komponenty Mozartify

Mozartify składa się z trzech core’owych komponentów. Oto one, wraz z jednolinijkowym opisem ich odpowiedzialności:

  • Mozartify\Subscription – pakiety subskrypcji usługi, zasady ich kupowania
  • Mozartify\Marketplace – przygotowanie oferty dla nowych i istniejących subskrybentów
  • Mozartify\Player – techniczne odtwarzanie uwzględniające innowacyjne rozliczanie usługi.

Acyclic Dependencies Principle (ADP)

Gdzie umieścić zasady programu lojalnościowego? Na pewno nie w module subskrypcji. Pamiętasz, że zespół Janka celowo “wyrzucił” przygotowanie oferty do oddzielnego komponentu, celem zachowania zgodności z zasadą Common Reuse Principle.

Dobrym pomysłem wydaje się umieszczenie regułek lojalnościowych w komponencie Marketplace. 

Pierwsze podejście do programu lojalnościowego

Program lojalnościowy wpływa na parametry subskrybowanego pakietu. W zależności od stażu, z każdym kolejnym pakietem, przyznaje bonusowe punkty.

Program lojalnościowy – podejście pierwsze
Program lojalnościowy – podejście pierwsze

Czyli osiągamy coś takiego jak na powyższym obrazku. Przyjrzyj się uważnie zależnościom. Czarno na białym widać, że zasady subskrypcji zależą od marketplace.

Cykle w zależnościach komponentów to zło

Efektem umieszczenia LoyaltyRules w komponencie Marketplace jest powstanie cyklu. Jakie są tego skutki?

  • Zmiana w komponencie Subscription, będzie wymagała przygotowania nowej wersji Marketplace (konieczność dostosowania metody prepareOffer)
  • Zmiana w komponencie Marketplace, będzie wymagała przejrzenia i ewentualnej adaptacji kodu metody buyPackage.

Brzmi niegroźnie? Dodaj do wszystkiego mikroserwisowe opakowanie i komunikację po HTTP. Albo po prostu przypadek, kiedy każdy z komponentów utrzymuje inny zespół programistów. Co z kolei oznacza:

  • wspólne review
  • konieczność wdrożenia w tym samym momencie
  • czyli konieczność synchronizacji i zachowania spójności
  • lub zapewnienie kontraktu wstecz, a później usunięcie zbędnego kodu.

Grafy acykliczne w relacjach między komponentami

Janek wiedział, ze potrzebuje lepszego rozwiązania. Postanowił rozerwać łańcuch zależności i uzyskać drogi acykliczne w relacjach komponentów.

Graf acykliczny to graf niezawierający drogi zamkniętej

Wikipedia: https://pl.wikipedia.org/wiki/Graf_(matematyka)

Co powiesz na poniższy schemat relacji między klasami komponentów? Zobacz jak teraz wygląda cykl zależności między Subscription a Marketplace. Widzisz ten cykl? Nie widzisz? To gitara, bo już go nie ma!

Eliminacja cyklu dzięki odwróceniu zależności
Eliminacja cyklu dzięki odwróceniu zależności

Janek zastosował tu odwrócenie zależności (DIP). Komponent Subscription definiuje abstrakcje opisujące, w jaki sposób naliczane są bicia serca (HeartbeatPolicy), natomiast Marketplace posłusznie dostarcza konkretną implementację. Komponent Subscription ponownie nie jest zależny od Marketplace. O to właśnie chodziło 🍾.

Wydzielenie komponentu

Drugi pomysł, który przyszedł Jankowi do głowy, to budowa nowego komponentu HeartbeatPolicy. Dzięki temu:

  • nadal zachowana jest acykliczna droga między klasami komponentów Subscription i Marketplace
  • komponenty Subscription i HearbeatPolicy mają jasno określone odpowiedzialności (zgodność z Common Reuse Principle)
Eliminacja cyklu dzięki wprowadzeniu nowego komponentu
Eliminacja cyklu dzięki wprowadzeniu nowego komponentu

Pojawia się jednak pewne zagrożenie. Wprowadzenie zmiany w HeartbeatsPolicy doprowadzi do konieczności przejrzenia kodu komponentów od niego zależnych: Subscription i Marketplace. Jest na to pewne rozwiązanie zahaczające o zagadnienia stabilności i abstrakcyjności. I już za moment je poznasz.

Stable Dependencies Principle (SDP)

Spacerujesz ulicą i widzisz ogromny dąb. Pomijając zgody formalne, fizycznie ciężko go wyrwać. Stabilny skubaniec, rośnie tu długo i ma mocne korzenie. Co się stanie jak będziesz go wyrywał? Ile rzeczy “związało” z nim swój los? Pewnie pociągnie za sobą spory kawałek obsadzonej roślinami ziemi, uszkodzi chodnik, kostkę na podjeździe, fragment asfaltu pobliskiej jezdni.

Teraz wyobraź sobie komponent. Istnieje od pradziejów w projekcie. Gdzie się nie obejrzysz, prawie wszystko z niego korzysta. Podejmiesz się usunięcia go z projektu? Odważysz się przebudować kod? Będzie trudno. Czyli im większa stabilność, tym większa trudność w pozbyciu się komponentu.

Po drugiej stronie jest inny komponent. Posiada tylko jedną relację przychodzącą (coś tam z niego korzysta). Reszta to relacje wychodzące, czyli odwołania do klas z innych komponentów. Definiując niestabilność jako łatwość usunięcia komponentu powiemy, że zdecydowanie jest on bardzo niestabilny.

Miara niestabilności

Jak najprościej liczbowo opisać niestabilność komponentu?

I = Out / In + Out

I (instability) – metryka niestabilności badanego komponentu
Out – wychodzące relacje, czyli od czego zależą klasy badanego komponentu
In – przychodzące relacje, czyli jakie klasy (komponenty) zależą od (klas) badanego komponentu

Case study przed wydzieleniem komponentu HeartbeatPolicy

Przeanalizujmy metryki niestabilności (I) komponentów Mozartify, zanim jeszcze pojawiły się regułki programu lojalnościowego.

Niestabilność przed wydzieleniem komponentu HeartbeatPolicy
Niestabilność przed wydzieleniem komponentu HeartbeatPolicy
Metryka niestabilnościInterpretacja
I(Subscription) = 0/2 = 0Zerowa niestabilność czyli komponent najbardziej stabilny. Bardziej być nie może.
I(Marketplace) = 1/2Takie pół na pół. Trochę od czegoś zależy, a trochę uzależnia.
I(Web) = 2/2 = 1Niestabilność równa jeden, to maksymalna wartość metryki. Nic nie uzależni się od tak opisanego komponentu.

Zrobię pewną żonglerkę kodem, abyś mógł popatrzeć na drugi przypadek.

Case study po wydzieleniu komponentu HeartbeatPolicy

Czy metryki niestabilności (I) zmieniły się po dodaniu komponentu HeartbeatPolicy? Zdecydowanie! Subscription nie jest już najbardziej stabilnym komponentem.

Niestabilność po wydzieleniu komponentu HeartbeatPolicy
Niestabilność po wydzieleniu komponentu HeartbeatPolicy

Spójrz na tabelkę poniżej. Zobaczysz jak bardzo zmiana wpłynęła na połączenia komponentów.

Metryka niestabilnościInterpretacja
I(HeartbeatPolicy) = 0/2 = 0Zmiana lidera w konkursie na najbardziej stabilny komponent. Zerowa niestabilność, czyli komponent od niczego nie zależy.
I(Subscription) = 1/3Po zmianie komponent subskrypcji, zależy od HeartbeatPolicy.
I(Marketplace) = 2/3Marketplace uzależnił się od HeartbeatPolicy i Subscription. Relacja przychodząca z komponentu Web zwiększa jego stabilność.
I(Web) = 2/2 = 1Nadal najmniej stabilny komponent.

Inwestuj w dobre relacje

Zanim zdefiniujemy dobrą zasadę budowania relacji komponentów, popatrz raz jeszcze na schemat “Niestabilność po wydzieleniu komponentu HeartbeatPolicy”. Są tam takie małe szczególiki – groty strzałek. Pokazują relację “zależę od X”.

Szukaną “X” można uogólnić, osiągając ostateczna wersję zdania: “zależę od komponentu bardziej stabilnego niż ja sam”.

Uzależniaj się od komponentów bardziej stabilnych niż ten, który piszesz. Komponenty stabilne zmieniają się rzadko. Dlaczego? Ponieważ trudno je zmienić. Jeśli trudno je zmienić, to bardzo małe jest prawdopodobieństwo, że pojawi się zmiana, która przełoży się na konieczność adaptacji twojego komponentu.

Przykład. Popatrz na biblioteki standardowe języków programowania. Kojarzysz nagminnie pojawiające się sytuacje, w których musiałeś zmieniać swój kod, bo pojawiła się w nich jakaś zmiana? 

Tylko że… w przypadku HeartbeatPolicy chcielibyśmy mieć możliwość zmiany reguł. Czy organizując komponenty opisany sposób, utrudnimy sobie wprowadzanie zmian w przyszłości? Tak, jeśli nie wykonamy jeszcze jednego istotnego kroku.

Stable Abstraction Principle (SAP)

Pozwól, że wprowadzę pojęcie stabilnej abstrakcji i abstrakcyjnej stabilności, czyli definicję komponentu idealnego. Zanim jednak dotrzemy do definicji, zatrzymajmy się na moment przy abstrakcyjności.

W mega uproszczeniu, abstrakcje w programowaniu obiektowym, to nic innego jak interfejsy i klasy abstrakcyjne. Przy czym nie jest konieczne, aby używany język programowania definiował słowa kluczowe abstract i interface. Abstrakcja to nazwanie zbioru cech i zachowań, a później operowanie już tą „abstrakcyjną” nazwą. To pozwala skupić się na algorytmie przetwarzania, bez wchodzenia w najdrobniejsze szczegóły implementacyjne.

Miara abstrakcyjności

Jest sobie taki oto wzór:

A = Na / Nc

A – metryka abstrakcyjności
Na – liczba interfejsów i klas abstrakcyjnych w komponencie
Nc – całkowita liczba wszystkich klas i interfejsów w komponencie.

W celu zrozumienia, do czego przyda się metryka abstrakcyjności, musisz spojrzeć na wykres zależności niestabilności(I) od abstrakcyjności (A) komponentu.

Komponenty bezużyteczne i trudne

zależność niestabilności(I) od abstrakcyjności (A) komponentu.
zależność niestabilności(I) od abstrakcyjności (A) komponentu

Jeśli komponent jest

  • bardzo abstrakcyjny,
  • ale też niestabilny (czyt. nic albo niewiele od niego zależy)

to znaczy, że w praktyce jest nic z niego nie korzysta = jest bezużyteczny.

Jeśli komponent jest

  • w niewielkim stopniu abstrakcyjny,
  • ale bardzo stabilny (czyt. wiele innych komponentów opiera o niego swe działanie)

to znaczy, że będzie trudno, bardzo trudno dokonać zmiany w jego kodzie.

Takie komponenty są niezmiernie niepożądane i z chęcią je pożegnamy.

Komponenty idealne

Nasza podróż przez świat komponentów, zmierza do definicji ostatecznej. Komponent idealny powinien być tak abstrakcyjny jak jest stabilny.

Wracając na moment do interpretacji graficznej – im bliżej niebieskiej linii się znajduje, tym lepiej.

Posłużmy się przykładem HeartbeatPolicy. Policzyliśmy jego niestabilność (I) otrzymując wartość równą 0 (zero). Czyli jest ekstremalnie stabilny, wiele miejsc w projekcie z niego korzysta. Biznesowo zależy nam na plastyczności takiego komponentu. Chcemy, aby pozwalał na łatwe wprowadzanie modyfikacji.

Wiesz już, że otwartość na rozbudowę, bez jednoczesnych modyfikacji kodu, osiągniesz stosując interfejsy (abstrakcje). Teraz wystarczy, że skompilujesz całą zdobytą wiedzę i zapewnisz, że odwołania do HeartbeatPolicy w komponentach Marketplace i Subscription, będą opierać się o te abstrakcje. 

Dobrym przykładem są też biblioteki dostępowe do bazy danych. Są to komponenty bardzo stabilne, wykorzystywane w mnóstwie miejsc w kodzie. A jednak są łatwe do modyfikacji. Dodanie nowego silnika bazodanowego, nie pociąga za sobą wielkiej przebudowy. Wykorzystanie bilbioteki ukryte jest elegancko za abstrakcjami.

Podsumowanie

No i koniec 😔. To ostatni artykuł cyklu “Zasady SOLID w czystej architekturze”. 

Cieszę się 😀, jeśli “Zasady SOLID w czystej architekturze” spowodowały, że:

  • nabrałeś odwagi i twoja przygoda z SOLID właśnie się rozpoczyna
  • poukładałeś swoją wiedzę, dzięki czemu kodowanie w duchu SOLID będzie bardziej świadome
  • przekonałeś się, aby stosować pochodne SOLID w szerszym kontekście niż pojedyncze klasy
  • zdobyłeś podstawy nawigacji w zagadnieniach grupowania i łączenia komponentów. 

To nie koniec. To dopiero początek 🚀.

Dziękuję za twoje dzielne dotrwanie do tego akapitu 💪.

PS. Masz pytanie? Wal śmiało 🥊: w komentarzu, na fanpage lub przez messenger migawka.it. Wolisz kontakt bezpośredni? Namiary na moje kanały w social media znajdziesz tutaj.

Powodzenia i do zobaczenia!
Michał

O autorze

O autorze

Michał Cisz

Wyznawca minimalizmu i maniak wszelkich idei, które mogą usprawnić komunikację i wymianę wiedzy w zespole. Fan czystej do bólu architektury, dbający o przestrzeganie zasad SOLID.

Czysta architektura okiem ekipy migawka.it

Jakie problemy napotkaliśmy na początku? W czym nam pomogła? Kiedy na pewno z niej nie skorzystamy?

Praca zdalna – komunikacja na czacie

Jak przenieść codzienne rozmowy z biura do świata online? Co z bezcennymi dyskusjami w kuchni? Najczęściej wrzucamy całą firmę na jakiś komunikator i liczymy, że zadzieje się magia. Nic bardziej mylnego i dziś opowiem ci jak sobie z tym poradzić.

Praca zdalna – jak nie zwariować?

Pandemia COVID-19 zmieniła wszystko. Większość z nas pracuje zdalnie. Pomożemy wam odnaleźć się w tej nowej rzeczywistości. Mamy doświadczenie w pracy „po kablach”, którymi chcemy się podzielić. Co ważne, choć to doświadczenie pochodzi z IT, to można je zastosować do każdej branży.

Enterprise SOLID dla architekta czystych kodów – łączenie

Zaawansowana część cyklu o zasadach SOLID: odsłona druga. Wiesz jak prawidłowo grupować klasy wewnątrz komponentów. Teraz pora na zasady skutecznego łączenia ich ze sobą. Będzie o tym jak zachować zdrowe relacje, a na tych niezdrowych zaaplikować właściwą terapię.

Enterprise SOLID dla architekta czystych kodów – grupowanie

Zaawansowana część cyklu o zasadach SOLID. To nie będą już pojedyncze klasy. To prawdziwa architektura z pełnią mocy i odpowiedzialności. Poznasz świat komponentów. Nauczysz się jak, zgodnie z zasadami czystej architektury, organizować je i składać z właściwych klas.

Premium SOLID dla praktykujących czystą architekturę

Praktykowanie zasad SOLID nie wymaga tajemnej wiedzy. Da się je stosować do projektów każdej wielkości. Nie generują narzutu i nie skutkują tym, że liczba klas w projekcie będzie rosła w tempie wykładniczym.

Funkcja trackback/Funkcja pingback

  1. Zasady SOLID w czystej architekturze - migawka.it - […] Klik! […]
  2. Enterprise SOLID dla architekta czystych kodów – grupowanie - migawka.it - […] Kolejna część: Enterprise SOLID – łączenie. Klik! […]

Prześlij komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Pozostań w kontakcie