Backend

Aplikacje zależne od siebie. Co zrobić, gdy nie działają?

Ewolucja w projektowaniu i wytwarzaniu aplikacji internetowych przeszła przez kilka etapów. W latach dziewięćdziesiątych ubiegłego wieku mieliśmy „Spaghetti-oriented Architecture”, która charakteryzowała się długimi jak makaron metodami, pełnymi ifów i zależności. Można było znaleźć dużo powtórzeń tego samego kodu, a programiści mogli się wtedy szczycić podejściem: trudno było napisać, trudno będzie zrozumieć.


Maciej Rynkiewicz. Software Development Manager w Wakacje.pl. Inżynier z zamiłowaniem do pracy twórczej, programista, architekt systemów i lider. Potrafi zrozumieć potrzeby biznesu i znaleźć rozwiązanie dobre dla wszystkich. Zawsze stawia na zespół, w którym pracuje i transparentną relację. Ma kilkanaście lat doświadczenia w branży IT, w której zaliczył niejedną porażkę, ale odniósł też wiele sukcesów.


Następnie przyszły lata dwutysięczne, które przyniosły rewolucję pt.: „Lasagne-oriented Architecture”. Prawdziwy przewrót: mamy aplikację podzieloną na warstwy, które świetnie wydzielają obszary działania, czasy świetności MVC. Wspaniałe rozwiązanie do czasu gdy aplikacje tak urosły, że utrzymanie oraz ich rozwój jest trudny i czasochłonny. Na szczęście kilka lat później pojawiły się mikroserwisy, które miały być lekiem na całe zło. I faktycznie były, ale żeby dawać wartość biznesową muszą działać razem, czyli przede wszystkim komunikować się.

Komunikacja w sieci jednak niesie za sobą dużo potencjalnych ryzyk i problemów, bo co jeśli Curl nie nawiąże połączenia, albo aplikacja odpowie błędem 500? Jak to dobrze zaplanować, żeby potem nie mieć problemów?

System rozproszony bez względu na złożoność i wartość biznesową jaką przynosi może mieć podobne problemy, z którymi każdy programista musi umieć sobie poradzić. Podstawa to komunikacja, nie jest odkryciem, że serwery, które ze sobą współpracują muszą „widzieć się” i być w stanie przesłać odpowiednią ilość danych, jak i utrzymywać czasem długie połączenia. Następnie aplikacje muszą „dogadać się”, czyli mieć możliwość połączyć się ze sobą za pomocą protokołu sieciowego i rozumieć, co jedna „mówi” a czego druga „oczekuje”.

Nieoceniona staje się w tym miejscu dokumentacja techniczna, a także kluczowy fakt: czy API posiada wersjonowanie i czy możliwe jest zawarcie kontraktu pomiędzy właścicielami technicznymi obu serwisów. Na koniec zostają te najtrudniejsze obszary, czyli niespodziewane błędy aplikacji, które często są błędami w kodzie lub nieprzewidzianymi przypadkami działania. Nie można zapominać także o błędach w działaniu, które wynikają z flow biznesowego lub zależności od zewnętrznego zasobu np. kolejnego API.

Skoro już znamy problemy jakie mogą nas spotkać porozmawiajmy o rozwiązaniach. Chciałbym wyróżnić trzy najpopularniejsze.

Połączenie synchroniczne – przeważnie CURL

Najbardziej popularne i często wystarczające rozwiązanie. Warto używać do komunikacji w miejscach, gdzie przesyłamy małą ilość danych, a także API, do którego łączymy się odpowiada szybko i jest stabilne.

Plusy:

  • Proste rozwiązanie, nie wymaga dodatkowej infrastruktury, nie jest skomplikowane,
  • Szybkie w implementacji,
  • Łatwe w debugowaniu błędów.

Minusy:

  • Ograniczony czas połączenia (zgodny z konfiguracją klienta i serwera),
  • Blokuje aplikacje na czas wykonania całej operacji.

Komunikacja za pośrednictwem systemu kolejkowania

Bardziej skomplikowane rozwiązanie, które wymaga od nas znajomości dodatkowych rozwiązań (np. Kafka, AMQP), do którego odkładamy żądanie obsłużenia dalszej komunikacji identycznej, jak w pkt. 1. Po wykonaniu zadania, skrypt może poinformować aplikację o wykonaniu zadania, jeśli jest taka potrzeba.

Plusy:

  • Asynchroniczne rozwiązanie, które nie blokuje aplikacji,
  • Umożliwia implementację bardziej skomplikowanych rozwiązań bez wpływu na aplikację, której używa użytkownik końcowy,
  • Idealne rozwiązanie dla operacji, które nie wymagają potwierdzenia – można dzięki temu ustawić ponowienia lub odpowiednią reakcję na niepowodzenie,
  • Dobre rozwiązanie dla komunikacji z niestabilnymi serwisami.

Minusy:

  • Złożone technicznie rozwiązanie, które wymaga dodatkowej infrastruktury,
  • Trudniejsze w naprawianiu błędów, debugowaniu i testowaniu.

Komunikacja na zasadzie call back’ów

Rozwiązanie, które wymaga zaangażowania obu stron, ponieważ cała logika odpowiedzi, na którą nasza aplikacja musi być gotowa, leży po stronie serwera (w komunikacji klient-serwer). Polega to na wysłaniu żądania do serwera, który potwierdza przyjęcie żądania, następnie wykonuje zleconą operację i odpowiada na zdefiniowane API klienta zlecającego.

Dodatkowo konieczne jest ponawianie nieobsłużonych requestów przez serwer, co znacznie komplikuje całość.

Plusy:

  • Rozwiązanie angażujące aplikację klienta do wykonania operacji w minimalnym stopniu,
  • Działanie w pełni asynchroniczne,
  • Proste rozwiązanie techniczne, w stosunku do możliwości jakie daje.

Minusy:

  • Wymaga dodatkowej konfiguracji – adres na jaki mają wpadać odpowiedzi musi być przygotowany i stabilny,
  • Po stronie serwera wymagana jest implementacja ponowień, jeśli serwis nie przyjmuje odpowiedzi.

Każdą funkcjonalność powinno się projektować indywidualnie, tak aby rozwiązywała problemy, a nie tworzyła nowych. Ważne jest też znalezienie złotego środka i nie popadanie w skrajności. Powyższe propozycje rozwiązań są w stanie obsłużyć prawie wszystkie znane mi przypadki, jednak warto dobrze się zastanowić, czy aby nie wyjeżdżamy z armatą na muchę. Wszystkie mają plusy i minusy, oraz każde z nich wymaga zbierania logów i ustawienia odpowiedniej konfiguracji niezbędnej do prawidłowego działania.

Jestem przekonany, że łatwo jest napisać dużo fajnego kodu, ale trudniej jest tworzyć rozwiązania łatwe w utrzymaniu i dostosowane do naszych potrzeb.

najwięcej ofert html

Grafika główna artykułu pochodzi od benorama.

.

Podobne artykuły