Czy dobre praktyki programowania są potrzebne również w chmurach? Just Cloud
SOLID i inne dobre praktyki tworzenia oprogramowania są (mam nadzieję!) powszechnie znane i stosowane przez programistów na całym świecie. Pytamy o nie na rozmowach kwalifikacyjnych, wytykamy ich braki w przeglądzie kodu i mamy wyrzuty sumienia, gdy musimy przymknąć na nie oko, aby dostarczyć projekt na czas.
Szkoła Chmury przygotowała dla Was zniżkę na kursy Software Development w chmurze Azure i AWS na -30%. Wystarczy, że wprowadzicie kod: JUSTCLOUD30 i zyskacie dostęp do wartościowej wiedzy!
W ostatnich latach świat rozwoju oprogramowania gruntownie się zmienił i obecnie, aby być dobrym i pożądanym na rynku programistą, trzeba dołożyć do swojego pudełka z narzędziami chmurę publiczną. Jak to zrobić, aby utrzymać wysoką jakość kodu także w chmurze? Jakie są dobre praktyki rozwoju aplikacji chmurowych i czy bardzo odbiegają od tych, które już znamy?
Spis treści
Błędne założenia przy tworzeniu systemów rozproszonych
Jako programiści często czynimy założenia. Czasem pomagają nam one dojść do celu i pokonać napotkany problem, lecz bywa, że stwarzają zagrożenie na środowisku produkcyjnym. Polecam ten artykuł o tzw. błędnych założeniach przy tworzeniu systemów rozproszonych (ang. fallacies of distributed systems).
Na przykład przy tworzeniu usługi do komunikacji z Service Busem czy wrappera dla punktu końcowego w Azure Functions powinniśmy zakładać nie tylko działające ścieżki, czy ewentualne błędy logiczne, ale również obsługę przypadków pogorszenia się stanu usługi, z którą się komunikujemy. Takie scenariusze najlepiej wyłapywać już na poziomie testów automatycznych (zarówno integracyjnych, jak i jednostkowych).
Programowanie defensywne
Spora część zestawu praktyk zwanych Defensive Programming dotyczy zarówno zabezpieczania się przed niedostępnością usług trzecich czy problemami z asynchronicznością, jak i uwzględniania różnic w zachowaniu tych usług w zależności od środowiska. Aby skutecznie radzić sobie z podobnymi kwestiami, stworzono wiele wzorców, które możemy zaimplementować w kodzie:
- Circuit Breaker,
- Retry Pattern,
- Leader Election Pattern,
- Compensating Transaction Pattern,
- Indempotency Key.
Zastosowanie, chociażby jednej z tych praktyk znacząco zredukuje ryzyko konieczności spędzenia wielu długich godzin na gaszeniu pożaru na produkcji.
SOLID w chmurze
Już od dwóch dekad SOLID pomaga programistom tworzyć wysokiej jakości, łatwy w utrzymaniu kod. Ten prosty zestaw zasad powstał jednak w czasach, kiedy nikomu nie śniło się, że będziemy wdrażać aplikacje w jakiejś tam chmurze.
Jakiś czas temu Microsoft wydał ciekawy white paper na temat pierwszej zasady SOLID, Single Responsibility Principle (zasada pojedynczej odpowiedzialności). A co z kolejnymi? Spróbujmy przełożyć je na chmurę publiczną.
Open/Closed (otwarte-zamknięte)
Klasa, metoda, itd., powinny być otwarte na rozszerzenie swojej funkcjonalności, ale bez jednoczesnego bezpośredniego edytowania kodu źródłowego. Z doświadczenia wiem, że chociaż w teorii ta zasada brzmi prosto, to w codziennej pracy często o niej zapominamy. Jak przenieść to założenie do świata chmury?
Weźmy na przykład usługę Azure Function, która otrzymuje obraz, zmniejsza jego rozdzielczość, a następnie przesyła przetworzony plik do określonego folderu. Dodatkowo chcemy mieć również możliwość nakładania na pomniejszony obraz znaku wodnego. Zamiast rozszerzać tę konkretną funkcję o nowe linie kodu (i narażać się na wprowadzenie nowych błędów oraz złamanie pierwszej zasady SOLID), możemy stworzyć nową funkcję nasłuchującą na zmiany w folderze, do którego trafia pomniejszony obraz, i nakładającą znak wodny osobno na plik.
Liskov (zasada podstawienia Liskov)
Ta zasada mówi, że możliwość podstawienia obiektu o podtypie obiektu, który spodziewamy się otrzymać, nie powinna wymagać zmiany zachowania systemu. Zasadę podstawienia można zastosować nie tylko do interfejsu najmniejszych elementów w kodzie, takich jak klasy, ale również do interfejsów komunikacyjnych pomiędzy różnymi modułami systemu.
Komunikacja pomiędzy usługami w chmurze powinna być zaimplementowana w taki sposób, aby wymiana jednego z komponentów nie wiązała się z przepisywaniem wszystkich zależnych od niego modułów. Efekt taki można uzyskać, wykorzystując różne opcje komunikacji za pomocą eventów, wiadomości, czy poleceń, jak i stosując tradycyjną zasadę Liskov w kodzie – oddzielając się warstwą abstrakcji od konkretnej implementacji danej metody komunikacji.
Interface Segregation (segregacja interfejsów)
Żaden z bytów nie powinien zależeć od elementów interfejsu, których nie używa. Złamanie tej zasady ilustruje na przykład sytuacja, w której klasa ConsoleLogger implementuje interfejs IConsole z dwoma metodami ReadFromConsole i WriteToConsole. A to dlatego, że ConsoleLogger nie będzie używać metody czytającej dane wprowadzone przez użytkownika. Implementując ją, zanieczyszczamy logikę klasy, co może wpłynąć na jej późniejsze utrzymywanie.
Jak to przełożyć na chmurę? Np. kontener dockerowy z obrazem bazy danych nie potrzebuje wszystkich narzędzi zamkniętych w osobnym kontenerze, na którego obrazie budujemy komponenty systemu. Posegregowanie kontenerów i użycie ich do budowy nowych w zależności od faktycznych potrzeb pomoże uniknąć problemów z utrzymaniem takiego systemu.
Dependency Inversion (odwrócenie zależności)
Odwrócenie zależności to kwintesencja współczesnej chmury publicznej, w której większość tworzonej przez nas logiki może być zarządzana przez eventy dostarczane przez wiele usług typu EventGrid, IoT Hub, czy nawet przez zmiany w bazie danych. Zamiast tworzyć usługi, które bezpośrednio sterują logiką systemu od wewnątrz, można oprzeć kontrolę na reakcji na konkretne eventy i interakcje użytkowników z aplikacją (patrz Liskov).
Kluczowe wnioski
- Pisząc kod aplikacji korzystającej z chmury publicznej, zakładaj, że wszystko, co może pójść nie tak, pójdzie nie tak. Zabezpiecz swój kod na taką ewentualność, korzystając z istniejących już wzorców.
- SOLID ma zastosowanie nie tylko bezpośrednio w kodzie. Przełożenie praktyk na pracę z usługami w chmurze wpłynie pozytywnie na wydajność, łatwość utrzymywania i bezpieczeństwo Twojej aplikacji. Spróbuj znaleźć sposób na przełożenie jednej z zasad SOLID na Twój projekt i zaproponuj go swojemu zespołowi!
Zdjęcie główne artykułu pochodzi z unsplash.com.