5 dolog, amit a reaktív programozásról tudni kell

By Clement Escoffier June 30, 2017August 6, 2020

Reaktív, milyen túlterhelt szó. Sok dologról kiderül, hogy varázslatosan Reaktívvá válik manapság. Ebben a bejegyzésben a reaktív programozásról, azaz az aszinkron adatfolyamok köré felépített fejlesztési modellről fogunk beszélni.

Tudom, hogy türelmetlenül szeretnéd megírni az első reaktív alkalmazásodat, de mielőtt megtennéd, van néhány dolog, amit tudnod kell. A reaktív programozás használata megváltoztatja a kódtervezés és -írás módját. Mielőtt felpattansz a vonatra, jó, ha tudod, hová tartasz.

Ebben a bejegyzésben 5 dolgot fogunk elmagyarázni a reaktív programozásról, hogy lásd, mit változtat meg számodra.

A reaktív programozás használatakor az adatfolyamok lesznek az alkalmazásod gerince. Az eseményeket, üzeneteket, hívásokat és még a hibákat is egy adatfolyam fogja közvetíteni. A reaktív programozással megfigyeli ezeket a folyamokat, és reagál, amikor egy értéket bocsát ki.

A kódjában tehát adatfolyamokat fog létrehozni bármiből és bármiből: kattintási események, HTTP-kérések, bevitt üzenetek, rendelkezésre állási értesítések, változások egy változóban, cache-események, egy érzékelőtől származó mérések, szó szerint bármi, ami változhat vagy történhet. Ennek van egy érdekes mellékhatása az alkalmazásodra: eredendően aszinkron lesz.

A reaktív eXtension (http://reactivex.io, a.ka. RX) a reaktív programozási elvek megvalósítása “aszinkron és eseményalapú programok összeállítása megfigyelhető szekvencia segítségével”. Az RX segítségével a kódod létrehozza és feliratkozik az Observables nevű adatfolyamokra. Míg a reaktív programozás a koncepciókról szól, az RX egy csodálatos eszköztárat biztosít. A megfigyelő és az iterátor minták és a funkcionális idiómák kombinálásával az RX szuperképességeket ad. Funkciók arzenálja áll rendelkezésedre az adatfolyamok kombinálásához, egyesítéséhez, szűréséhez, átalakításához és létrehozásához. A következő kép az RX használatát szemlélteti Javában (a https://github.com/ReactiveX/RxJava segítségével).

Az RX ugyan nem az egyetlen implementációja a reaktív programozási elveknek (idézhetjük például a BaconJS-t – http://baconjs.github.io), de ma ez a leggyakrabban használt. A bejegyzés további részében az Rx Java-t fogjuk használni.

2. Az Observables lehetnek hidegek vagy melegek – és ez számít.

Ez a pont, ahol megpróbálod átlátni, hogy mik azok a különböző folyamokat (vagy megfigyelőket), amelyekkel a programodban foglalkozni fogsz. De az adatfolyamoknak két osztálya van: a forró és a hideg. A különbség megértése kulcsfontosságú a reaktív programozás sikeres használatához.

A hideg megfigyelhetők lusták. Nem csinálnak semmit, amíg valaki el nem kezdi őket megfigyelni (subscribe in RX). Csak akkor kezdenek el futni, amikor elfogyasztják őket. A hideg folyamok aszinkron akciók ábrázolására szolgálnak, például arra, hogy addig nem hajtják végre, amíg valakit nem érdekel az eredmény. Egy másik példa lenne egy fájl letöltése. Nem kezdi el húzni a bájtokat, ha senki sem fog csinálni semmit az adatokkal. A hideg folyam által előállított adatok nem kerülnek megosztásra a feliratkozók között, és amikor feliratkozol, megkapod az összes elemet.

A forró folyam már a feliratkozás előtt aktív, mint például egy tőzsdei ketyegő, vagy egy érzékelő vagy egy felhasználó által küldött adatok. Az adatok függetlenek az egyes előfizetőktől. Amikor egy megfigyelő feliratkozik egy forró megfigyelhetőre, megkapja a folyam összes olyan értékét, amely a feliratkozás után kerül kibocsátásra. Az értékek az összes feliratkozó között megosztásra kerülnek. Például, ha senki sem iratkozott fel egy hőmérőre, akkor is méri és közzéteszi az aktuális hőmérsékletet. Amikor egy előfizető feliratkozik a folyamra, automatikusan megkapja a következő mérést.

Miért olyan fontos megérteni, hogy a folyamod forró vagy hideg? Mert ez megváltoztatja, hogy a kódod hogyan fogyasztja a közvetített elemeket. Ha nincs feliratkozva egy forró megfigyelhetőre, akkor nem kapja meg az adatokat, és ezek az adatok elvesznek.

Develop a Red Hat legértékesebb termékeivel

A tagsága felszabadítja a Red Hat termékeit és a vállalati felhőalapú alkalmazásfejlesztéssel kapcsolatos technikai képzéseket.

JOIN RED HAT DEVELOPER

Rosszul használt aszinkronitás harap

A reaktív programozás definíciójában van egy fontos szó: aszinkron. Aszinkron – azaz a fő programfolyamtól függetlenül – értesítést kapunk, ha adatot adunk ki a folyamban. Azzal, hogy a programodat adatfolyam köré strukturálod, aszinkron kódot írsz: olyan kódot írsz, amelyet akkor hívsz meg, amikor a folyam új elemet bocsát ki. A szálak, a blokkoló kód és a mellékhatások nagyon fontos dolgok ebben az összefüggésben. Kezdjük a mellékhatásokkal.

A mellékhatások nélküli függvények kizárólag argumentumaikon és visszatérési értékeiken keresztül lépnek kölcsönhatásba a program többi részével. A mellékhatások nagyon hasznosak lehetnek, és sok esetben elkerülhetetlenek. De vannak buktatóik is. Ha reaktív programozást használunk, kerülni kell a felesleges mellékhatásokat, és világos szándékkal kell rendelkeznünk, ha mégis használjuk őket. Fogadja el tehát a megváltoztathatatlanságot, és az oldalhatásmentes függvényeket. Bár bizonyos esetekben indokolt, az oldalhatásokkal való visszaélés zivatarokhoz vezet: szálbiztonság.

Ez a második fontos pont: a szálak. Jó dolog megfigyelni a folyamokat, és értesülni, ha valami érdekes történik, de soha nem szabad elfelejteni, hogy ki hívja, pontosabban melyik szálon hajtják végre a függvényeidet. Erősen ajánlott elkerülni a túl sok szál használatát a programodban. A több szálra támaszkodó aszinkron programok kemény szinkronizációs fejtörővé válnak, ami gyakran holtpontvadászattal végződik.

Ez a harmadik pont: soha ne blokkolj. Mivel a téged hívó szál nem a tiéd, ezért ügyelned kell arra, hogy soha ne blokkold. Ha ezt teszed, akkor elkerülheted a többi kibocsátandó elemet, azok addig pufferelnek, amíg … a puffer meg nem telik (ilyenkor beindulhat a back-pressure, de ez nem ennek a posztnak a témája). Az RX és az aszinkron IO kombinálásával mindened megvan ahhoz, hogy nem blokkoló kódot írj, és ha ennél többet akarsz, nézd meg az Eclipse Vert.x-et, egy reaktivitást és aszinkronitást elősegítő reaktív eszközkészletet. A következő kód például a Vert.x webkliens és annak RX API-ját mutatja be egy JSON dokumentum lekérdezéséhez a szerverről és a névbejegyzés megjelenítéséhez:

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

Figyeljünk a subscribe metódusra ebben az utolsó részletben. Egy második metódust vesz fel, amelyet akkor hív meg, amikor az egyik feldolgozási szakasz kivételt dob. Mindig kapjuk el a kivételeket. Ha nem teszed, órákat fogsz azzal tölteni, hogy megpróbálod megérteni, mi a baj.

4. Tartsd egyszerűnek a dolgokat

Mint tudod, “A nagy hatalommal nagy felelősség jár”. Az RX rengeteg nagyon klassz funkciót biztosít, és könnyű a sötét oldal felé hajlani. A flapmap, retry, debounce és zip láncolatától nindzsának érezheted magad… DE sose felejtsd el, hogy a jó kódnak más számára is olvashatónak kell lennie.

Vegyünk néhány kódot…

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); });

Egy ilyen példát adva nehéz lehet megérteni, nem? Több aszinkron műveletet (flatmap) láncol össze, egy másik műveletsorhoz (zip) csatlakozik. A reaktív programozási kód először is elmeváltást igényel. Értesítést kap az aszinkron eseményekről. Aztán az API-t nehéz lehet megérteni (elég csak megnézni az operátorok listáját). Ne élj vissza, írj kommenteket, magyarázz, vagy rajzolj ábrákat (biztos vagyok benne, hogy asciiart művész vagy). Az RX erős, ha visszaélsz vele, vagy nem magyarázod el, a munkatársaid morcosak lesznek.

5. Reaktív programozás != Reaktív rendszer

Vélhetően a legzavaróbb rész. A reaktív programozás használata nem épít reaktív rendszert. A reaktív rendszerek a reaktív kiáltványban meghatározottak szerint egy architektúrális stílus a reszponzív elosztott rendszerek építésére. A reaktív rendszereket tekinthetjük úgy is, mint jól csinált elosztott rendszereket. A reaktív rendszert négy tulajdonság jellemzi:

  • Reagáló: a reaktív rendszernek ésszerű időn belül kell kezelnie a kéréseket (az ésszerű meghatározást rád bízom).
  • Rugalmas: a reaktív rendszernek reagálónak kell maradnia a hibák (összeomlás, időkiesés, 500 hiba… ) esetén is, tehát a hibákra kell tervezni, és azokat megfelelően kezelni.
  • Rugalmas: a reaktív rendszernek különböző terhelések mellett is reagálónak kell maradnia. Következésképpen fel- és le kell skálázódnia, és minimális erőforrásokkal kell tudnia kezelni a terhelést.
  • Üzenetvezérelt: a reaktív rendszer komponensei aszinkron üzenettovábbítással lépnek kapcsolatba egymással.

A reaktív rendszerek ezen alapelveinek egyszerűsége ellenére egy ilyen rendszer megépítése trükkös. Általában minden csomópontnak egy aszinkron, nem blokkoló fejlesztési modellt, egy feladatalapú párhuzamossági modellt kell magáévá tennie, és nem blokkoló I/O-t kell használnia. Ha nem gondolja át először ezeket a pontokat, hamar spagettitányér lesz belőle.

A reaktív programozás és a reaktív eXtension olyan fejlesztési modellt kínál, amellyel megszelídítheti az aszinkron fenevadat. Ha okosan használod, a kódod olvasható és érthető marad. A reaktív programozás használata azonban nem alakítja át a rendszerét reaktív rendszerré. A reaktív rendszerek a következő szint.

Következtetés

Végre elérkeztünk a bejegyzés végére. Ha tovább akarsz menni, és érdekel a reaktív programozás, ajánlom figyelmedbe az Eclipse Vert.x – eszköztár reaktív és elosztott rendszerek építéséhez (http://vertx.io), valamint a Reactive Microservices in Java minikönyvét, amely a https://developers.redhat.com/books/building-reactive-microservices-java címen érhető el. A Vert.x és a Reactive eXtension kombinálása felszabadítja a reaktív szupererőt. Nemcsak reaktív programozást használhat, hanem reaktív rendszereket is építhet, és hozzáférhet egy izgalmas és növekvő ökoszisztémához.

Boldog kódolást!

Töltse le az Eclipse Vert.x puskát, ez a puskalap lépésről lépésre részletezi, hogy úgy készíthesse el alkalmazásait, ahogyan szeretné.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.