5 Things to Know About Reactive Programming

By Clement Escoffier June 30, 2017August 6, 2020

Reactive, co za przeładowane słowo. Wiele rzeczy okazuje się być magicznie Reaktywne w dzisiejszych czasach. W tym poście będziemy mówić o Programowaniu Reaktywnym, czyli modelu rozwoju zorganizowanym wokół asynchronicznych strumieni danych.

Wiem, że jesteś niecierpliwy, aby napisać swoją pierwszą reaktywną aplikację, ale zanim to zrobisz, jest kilka rzeczy, które musisz wiedzieć. Używanie programowania reaktywnego zmienia sposób, w jaki projektujesz i piszesz swój kod. Zanim wskoczysz do pociągu, dobrze jest wiedzieć, dokąd zmierzasz.

W tym poście zamierzamy wyjaśnić 5 rzeczy na temat programowania reaktywnego, aby zobaczyć, co to zmienia dla ciebie.

Gdy używasz programowania reaktywnego, strumienie danych będą kręgosłupem twojej aplikacji. Zdarzenia, wiadomości, połączenia, a nawet awarie będą przekazywane przez strumień danych. Z programowaniem reaktywnym, obserwujesz te strumienie i reagujesz, gdy wartość jest emitowana.

Więc, w swoim kodzie, będziesz tworzyć strumienie danych z czegokolwiek i od czegokolwiek: zdarzenia kliknięcia, żądania HTTP, wiadomości, powiadomienia o dostępności, zmiany na zmiennej, zdarzenia pamięci podręcznej, środki z czujnika, dosłownie wszystko, co może się zmienić lub zdarzyć. Ma to interesujący efekt uboczny dla twojej aplikacji: staje się ona z natury asynchroniczna.

Reactive eXtension (http://reactivex.io, a.ka. RX) jest implementacją zasad programowania reaktywnego do „kompilowania asynchronicznych i opartych na zdarzeniach programów poprzez użycie obserwowalnej sekwencji”. Z RX, twój kod tworzy i subskrybuje strumienie danych o nazwie Observables. Podczas gdy programowanie reaktywne jest związane z koncepcjami, RX dostarcza niesamowity zestaw narzędzi. Poprzez połączenie wzorców obserwatora i iteratora oraz idiomów funkcjonalnych, RX daje Ci supermoce. Masz do dyspozycji arsenał funkcji do łączenia, scalania, filtrowania, przekształcania i tworzenia strumieni danych. Kolejny obrazek ilustruje użycie RX w Javie (przy użyciu https://github.com/ReactiveX/RxJava).

Choć RX nie jest jedyną implementacją zasad programowania reaktywnego (dla przykładu można przytoczyć BaconJS – http://baconjs.github.io), to dziś jest najczęściej wykorzystywany. W pozostałej części tego postu będziemy używać Rx Java.

2. Observables mogą być zimne lub gorące – i to ma znaczenie.

W tym momencie próbujesz zobaczyć, jakie są różne strumienie (lub obserwowalne), z którymi będziesz miał do czynienia w swoim programie. Istnieją jednak dwie klasy strumieni: gorące i zimne. Zrozumienie różnicy jest kluczem do pomyślnego użycia programowania reaktywnego.

Zimne obserwowalne są leniwe. Nie robią nic, dopóki ktoś nie zacznie ich obserwować (subskrybować w RX). Zaczynają działać tylko wtedy, gdy są konsumowane. Zimne strumienie są używane do reprezentowania działań asynchronicznych, na przykład, że nie zostaną wykonane, dopóki ktoś nie będzie zainteresowany wynikiem. Innym przykładem może być pobieranie pliku. Nie zacznie on pobierać bajtów, jeśli nikt nie będzie chciał zrobić czegoś z danymi. Dane wytwarzane przez zimny strumień nie są udostępniane subskrybentom, a kiedy subskrybujesz, otrzymujesz wszystkie elementy.

Gorące strumienie są aktywne przed subskrypcją, jak np. ticker giełdowy lub dane wysyłane przez czujnik lub użytkownika. Dane są niezależne od indywidualnego subskrybenta. Kiedy obserwator subskrybuje gorącą obserwowalną, otrzyma wszystkie wartości w strumieniu, które są emitowane po jego subskrypcji. Wartości te są współdzielone pomiędzy wszystkich subskrybentów. Na przykład, nawet jeśli nikt nie zapisał się do termometru, mierzy on i publikuje aktualną temperaturę. Kiedy subskrybent rejestruje się do strumienia, automatycznie otrzymuje następny pomiar.

Dlaczego tak ważne jest zrozumienie, czy twoje strumienie są gorące czy zimne? Ponieważ zmienia to sposób, w jaki twój kod zużywa przekazywane elementy. Jeśli nie jesteś zapisany do gorącej obserwowalnej, nie otrzymasz danych, a te dane zostaną utracone.

Rozwijaj się, korzystając z najcenniejszych produktów firmy Red Hat

Twoje członkostwo odblokowuje produkty firmy Red Hat i szkolenia techniczne z zakresu tworzenia aplikacji w chmurze klasy korporacyjnej.

DOŁĄCZ DO RED HAT DEVELOPER

Nadużywane asynchrony gryzą

W definicji programowania reaktywnego jest jedno ważne słowo: asynchroniczne. Zostajesz powiadomiony, gdy dane są emitowane w strumieniu asynchronicznie – to znaczy niezależnie od głównego przepływu programu. Konstruując swój program wokół strumieni danych, piszesz kod asynchroniczny: piszesz kod wywoływany, gdy strumień emituje nowy element. Wątki, kod blokujący i efekty uboczne są bardzo ważnymi sprawami w tym kontekście. Zacznijmy od efektów ubocznych.

Funkcje bez efektów ubocznych oddziałują z resztą programu wyłącznie poprzez swoje argumenty i wartości zwracane. Efekty uboczne mogą być bardzo użyteczne i są nieuniknione w wielu przypadkach. Ale mają też swoje pułapki. Kiedy używasz programowania reaktywnego, powinieneś unikać niepotrzebnych efektów ubocznych i mieć jasną intencję, kiedy ich używasz. Tak więc, ogarnij niezmienność i funkcje wolne od efektów ubocznych. Podczas gdy niektóre przypadki są uzasadnione, nadużywanie efektów ubocznych prowadzi do burzy: bezpieczeństwo wątków.

To jest drugi ważny punkt: wątki. Miło jest obserwować strumienie i być informowanym, gdy dzieje się coś ciekawego, ale nigdy nie możesz zapomnieć, kto Cię wywołuje, a dokładniej, na którym wątku wykonywane są Twoje funkcje. Bardzo zalecane jest unikanie używania zbyt wielu wątków w swoim programie. Programy asynchroniczne polegające na wielu wątkach stają się trudną łamigłówką synchronizacyjną, często kończącą się polowaniem na impas.

To jest trzeci punkt: nigdy nie blokuj. Ponieważ nie jesteś właścicielem wątku wywołującego cię, musisz mieć pewność, że nigdy go nie zablokujesz. Jeśli to zrobisz, możesz uniknąć innych elementów, które mają być emitowane, będą one buforowane, dopóki … bufor nie będzie pełny (ciśnienie wsteczne może kopać w tym przypadku, ale nie jest to temat tego postu). Łącząc RX i asynchroniczne IO masz wszystko, czego potrzebujesz do pisania nieblokującego kodu, a jeśli chcesz więcej, spójrz na Eclipse Vert.x, reaktywny zestaw narzędzi promujący reaktywność i asynchroniczność. Na przykład, poniższy kod pokazuje klienta Vert.x Web Client i jego RX API do pobrania dokumentu JSON z serwera i wyświetlenia wpisu o nazwie:

client.get("/api/people/4").rxSend().map(HttpResponse::bodyAsJsonObject).map(json -> json.getString("name")).subscribe(System.out::println, Throwable::printStackTrace);

Zwróć uwagę na metodę subscribe w tym ostatnim wycinku. Pobiera ona drugą metodę wywoływaną, gdy jeden z etapów przetwarzania rzuci wyjątek. Zawsze łap wyjątki. Jeśli tego nie zrobisz, spędzisz godziny, próbując zrozumieć, co się dzieje nie tak.

4. Zachowaj prostotę

Jak wiadomo, „Z wielką mocą przychodzi wielka odpowiedzialność”. RX dostarcza wielu bardzo fajnych funkcji i łatwo jest przechylić się w stronę ciemnej strony. Łączenie flapmap, retry, debounce i zip sprawi, że poczujesz się jak ninja… ALE, nigdy nie zapominaj, że dobry kod musi być czytelny dla kogoś innego.

Popatrzmy na jakiś kod…

manager.getCampaignById(id) .flatMap(campaign -> manager.getCartsForCampaign(campaign) .flatMap(list -> { Single<List<Product>> products = manager.getProducts(campaign); Single<List<UserCommand>> carts = manager.getCarts(campaign); return products.zipWith(carts, (p, c) -> new CampaignModel(campaign, p, c)); }) .flatMap(model -> template .rxRender(rc, "templates/fruits/campaign.thl.html") .map(Buffer::toString)) ) .subscribe( content -> rc.response().end(content), err -> { log.error("Unable to render campaign view", err); getAllCampaigns(rc); });

Podany przykład jak ten może być trudny do zrozumienia, nie? Jest to łańcuch kilku operacji asynchronicznych (flatmap), dołącz do innego zestawu operacji (zip). Kod programowania reaktywnego wymaga najpierw zmiany umysłu. Otrzymujesz powiadomienia o zdarzeniach asynchronicznych. Następnie, API może być trudne do uchwycenia (wystarczy spojrzeć na listę operatorów). Nie nadużywaj, pisz komentarze, wyjaśniaj lub rysuj diagramy (jestem pewien, że jesteś artystą asciiart). RX jest potężny, nadużywanie go lub niewyjaśnianie sprawi, że twoi współpracownicy będą zrzędliwi.

5. Programowanie reaktywne != System reaktywny

Prawdopodobnie najbardziej zagmatwana część. Używanie programowania reaktywnego nie buduje systemu reaktywnego. Systemy reaktywne, jak zdefiniowano w manifeście reaktywnym, są stylem architektonicznym do budowania responsywnych systemów rozproszonych. Systemy reaktywne mogą być postrzegane jako systemy rozproszone zrobione dobrze. System reaktywny charakteryzuje się czterema właściwościami:

  • Responsywny: system reaktywny musi obsługiwać żądania w rozsądnym czasie (pozwalam ci zdefiniować rozsądny).
  • Odporny: system reaktywny musi pozostać responsywny w obliczu awarii (awaria, timeout, 500 błędów… ), więc musi być zaprojektowany na awarie i odpowiednio sobie z nimi radzić.
  • Elastyczny: system reaktywny musi pozostać responsywny przy różnych obciążeniach. W związku z tym musi skalować się w górę i w dół oraz być w stanie obsłużyć obciążenie przy minimalnych zasobach.
  • Message driven: komponenty systemu reaktywnego wchodzą w interakcje przy użyciu asynchronicznego przekazywania komunikatów.

Mimo prostoty tych podstawowych zasad systemów reaktywnych, zbudowanie jednego z nich jest trudne. Zazwyczaj każdy węzeł musi przyjąć asynchroniczny, nieblokujący model rozwoju, model współbieżności oparty na zadaniach i używa nieblokującego I/O. Jeśli nie pomyślisz najpierw o tych punktach, to szybko będzie to tablica spaghetti.

Reactive Programming and Reactive eXtension zapewnia model rozwoju, aby oswoić asynchroniczną bestię. Używając go mądrze, twój kod pozostanie czytelny i zrozumiały. Jednak używanie programowania reaktywnego nie przekształca twojego systemu w System Reaktywny. Systemy Reaktywne są następnym poziomem.

Wnioski

W końcu dotarliśmy do końca tego wpisu. Jeśli chcesz iść dalej i interesujesz się reaktywnością, polecam zajrzeć do Eclipse Vert.x – zestawu narzędzi do budowania systemów reaktywnych i rozproszonych (http://vertx.io), oraz do minibooka Reactive Microservices in Java dostępnego w https://developers.redhat.com/books/building-reactive-microservices-java. Połączenie Vert.x i Reactive eXtension uwalnia twoją reaktywną supermoc. Możesz nie tylko używać programowania reaktywnego, ale także budować systemy reaktywne i mieć dostęp do ekscytującego i rosnącego ekosystemu.

Szczęśliwego kodowania!

Ściągnij arkusz Eclipse Vert.x cheat sheet, ten cheat sheet zapewnia szczegóły krok po kroku, aby umożliwić Ci tworzenie aplikacji w sposób, w jaki chcesz.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.