5 věcí, které je třeba vědět o reaktivním programování

Klement Escoffier 30. června 20176. srpna 2020

Reaktivní, jak přetížené slovo. Ukazuje se, že mnoho věcí se v dnešní době stává kouzelně reaktivními. V tomto příspěvku budeme mluvit o reaktivním programování, tedy o vývojovém modelu strukturovaném kolem asynchronních datových toků.

Vím, že už se nemůžete dočkat, až napíšete svou první reaktivní aplikaci, ale než se do toho pustíte, je třeba vědět pár věcí. Použití reaktivního programování mění způsob návrhu a psaní kódu. Než naskočíte do rozjetého vlaku, je dobré vědět, kam směřujete.

V tomto příspěvku si vysvětlíme 5 věcí o reaktivním programování, abyste věděli, co pro vás mění.

Při používání reaktivního programování budou páteří vaší aplikace datové proudy. Události, zprávy, volání, a dokonce i selhání budou přenášeny datovým tokem. Při reaktivním programování tyto proudy sledujete a reagujete, když je emitována nějaká hodnota.

V kódu tedy budete vytvářet datové proudy čehokoli a z čehokoli: události kliknutí, požadavky HTTP, přijaté zprávy, oznámení o dostupnosti, změny proměnné, události mezipaměti, měření ze senzoru, doslova cokoli, co se může změnit nebo stát. To má zajímavý vedlejší účinek na vaši aplikaci: stává se ze své podstaty asynchronní.

Reaktivní rozšíření (http://reactivex.io, a.ka. RX) je implementace principů reaktivního programování pro „sestavování asynchronních a na událostech založených programů pomocí pozorovatelné posloupnosti“. Pomocí RX váš kód vytváří a přihlašuje se k datovým tokům pojmenovaným Observables. Zatímco reaktivní programování je o konceptech, RX vám poskytuje úžasnou sadu nástrojů. Kombinací vzorů observer a iterátor a funkcionálních idiomů vám RX poskytuje superschopnosti. Máte k dispozici arzenál funkcí pro kombinování, slučování, filtrování, transformování a vytváření datových proudů. Další obrázek ilustruje použití RX v Javě (pomocí https://github.com/ReactiveX/RxJava).

Ačkoli RX není jedinou implementací principů reaktivního programování (můžeme uvést například BaconJS – http://baconjs.github.io), je dnes nejpoužívanější. Ve zbytku tohoto příspěvku budeme používat Rx Java.

2. Pozorovatelné objekty mohou být studené nebo horké – a na tom záleží.

V tuto chvíli se snažíte zjistit, s jakými různými toky (neboli pozorovatelnými objekty) budete ve svém programu pracovat. Existují však dvě třídy proudů: horké a studené. Pochopení rozdílu je klíčem k úspěšnému používání reaktivního programování.

Studené pozorovatelné objekty jsou líné. Nedělají nic, dokud je někdo nezačne pozorovat (subscribe v RX). Začnou běžet, až když jsou spotřebovány. Studené toky se používají k reprezentaci asynchronních akcí, například že se neprovede, dokud někoho nezačne zajímat výsledek. Dalším příkladem může být stahování souborů. Nezačne stahovat bajty, pokud se nikdo nechystá s daty něco dělat. Data vytvořená studeným proudem nejsou sdílena mezi odběrateli a při odběru získáte všechny položky.

Horké proudy jsou aktivní před odběrem, jako například burzovní tiker nebo data odeslaná senzorem či uživatelem. Data jsou nezávislá na jednotlivém odběrateli. Když se pozorovatel přihlásí k odběru horké pozorovatelné, získá všechny hodnoty ve streamu, které jsou emitovány po jeho přihlášení. Tyto hodnoty jsou sdíleny mezi všemi odběrateli. Například i když se k teploměru nikdo nepřihlásil, měří a zveřejňuje aktuální teplotu. Když se odběratel zaregistruje do streamu, automaticky obdrží další měření.

Proč je tak důležité pochopit, zda jsou vaše streamy horké nebo studené? Protože to mění způsob, jakým váš kód spotřebovává přenášené položky. Pokud nejste přihlášeni k horké sledovatelné položce, data nedostanete a tato data jsou ztracena.

Vyvíjejte pomocí nejcennějších produktů Red Hat

Vaše členství odemyká produkty Red Hat a technická školení o vývoji podnikových cloudových aplikací.

PŘIPOJTE SE K RED HAT DEVELOPER

Zneužívané asynchronní kousky

V definici reaktivního programování je jedno důležité slovo: asynchronní. Jste upozorněni, když jsou data emitována do proudu asynchronně – to znamená nezávisle na hlavním toku programu. Tím, že svůj program strukturujete kolem datových proudů, píšete asynchronní kód: píšete kód, který se vyvolá, když proud emituje novou položku. Vlákna, blokující kód a vedlejší efekty jsou v tomto kontextu velmi důležité záležitosti. Začněme vedlejšími efekty.

Funkce bez vedlejších efektů komunikují se zbytkem programu výhradně prostřednictvím svých argumentů a návratových hodnot. Vedlejší účinky mohou být velmi užitečné a v mnoha případech jsou nevyhnutelné. Mají však také svá úskalí. Při použití reaktivního programování byste se měli vyhnout zbytečným vedlejším efektům a měli byste mít jasný záměr, když je použijete. Přijměte tedy neměnnost a funkce bez vedlejších efektů. I když jsou některé případy oprávněné, zneužívání vedlejších efektů vede k bouři: bezpečnosti vláken.

To je druhý důležitý bod: vlákna. Je hezké sledovat proudy a být upozorněn, když se stane něco zajímavého, ale nikdy nesmíte zapomenout, kdo vás volá, přesněji řečeno, na kterém vlákně se vaše funkce vykonávají. Silně se doporučuje nepoužívat ve svém programu příliš mnoho vláken. Asynchronní programy spoléhající na více vláken se stávají těžkým synchronizačním rébusem, který často končí jako honba za deadlockem.

To je třetí bod: nikdy neblokujte. Protože vám volající vlákno nepatří, musíte si být jisti, že ho nikdy nezablokujete. Pokud to uděláte, můžete se vyhnout dalším položkám, které mají být emitovány, budou bufferovány, dokud … nebude buffer plný (v tomto případě může nastat zpětný tlak, ale to není tématem tohoto příspěvku). Kombinací RX a asynchronního IO máte vše, co potřebujete k psaní neblokujícího kódu, a pokud chcete víc, podívejte se na Eclipse Vert.x, reaktivní sadu nástrojů podporující reaktivitu a asynchronnost. Například následující kód ukazuje webového klienta Vert.x a jeho rozhraní RX API pro načtení dokumentu JSON ze serveru a zobrazení položky se jménem:

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

Všimněte si metody subscribe v tomto posledním úryvku. Přebírá druhou metodu, která se volá, když některá z fází zpracování vyhodí výjimku. Vždy zachycujte výjimky. Pokud to neuděláte, strávíte hodiny snahou pochopit, co se děje špatně.

4. Udržujte věci jednoduché

Jak víte, „S velkou mocí přichází velká odpovědnost“. RX poskytuje spoustu velmi skvělých funkcí a je snadné přiklonit se na temnou stranu. Řetězení flapmap, retry, debounce a zip vám dává pocit, že jste ninja… ALE nikdy nezapomínejte, že dobrý kód musí být čitelný i pro někoho jiného.

Podívejme se na nějaký kód…

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

Podle příkladu, jako je tento, může být těžké pochopit ne? Zřetězí několik asynchronních operací (flatmap), připojí další sadu operací (zip). Reaktivní programový kód vyžaduje nejprve změnu myšlení. Jste informováni o asynchronních událostech. Pak může být těžké pochopit API (stačí se podívat na seznam operátorů). Nezneužívejte, pište komentáře, vysvětlujte nebo kreslete diagramy (určitě jste asciiartový umělec). RX je mocné, jeho zneužívání nebo nevysvětlování způsobí, že vaši spolupracovníci budou nevrlí.

5. Zkuste se podívat, co je to RX. Reaktivní programování != Reaktivní systém

Pravděpodobně nejzmatenější část. Použitím reaktivního programování se nevytváří reaktivní systém. Reaktivní systémy, jak jsou definovány v Reaktivním manifestu, jsou architektonickým stylem pro budování reaktivních distribuovaných systémů. Reaktivní systémy lze považovat za správně provedené distribuované systémy. Reaktivní systém se vyznačuje čtyřmi vlastnostmi:

  • Reaktivní: reaktivní systém musí zpracovat požadavky v rozumném čase (rozumný čas nechám definovat vás).
  • Odolný: reaktivní systém musí zůstat citlivý i při selhání (pád, timeout, 500 chyb… ), takže musí být navržen pro selhání a vhodně se s nimi vypořádat.
  • Pružný: reaktivní systém musí zůstat citlivý při různém zatížení. V důsledku toho se musí škálovat nahoru a dolů a musí být schopen zvládnout zátěž s minimálními prostředky.
  • Řízený zprávami: komponenty reaktivního systému spolu komunikují pomocí asynchronního předávání zpráv.

Přes jednoduchost těchto základních principů reaktivních systémů je sestavení takového systému složité. Obvykle musí každý uzel přijmout asynchronní neblokující vývojový model, model souběžnosti založený na úlohách a používat neblokující vstupy a výstupy. Pokud se nad těmito body nezamyslíte jako první, rychle z toho bude talíř špaget.

Reaktivní programování a Reactive eXtension poskytuje vývojový model pro zkrocení asynchronní bestie. Jeho rozumným používáním zůstane váš kód čitelný a srozumitelný. Použitím reaktivního programování se však váš systém nepromění v reaktivní systém. Reaktivní systémy jsou další úrovní.

Závěr

Konečně se dostáváme na konec tohoto příspěvku. Pokud chcete jít dál a zajímáte se o reaktivní systémy, doporučuji vám podívat se na Eclipse Vert.x – sadu nástrojů pro vytváření reaktivních a distribuovaných systémů (http://vertx.io) a na miniknihu Reactive Microservices in Java, která je k dispozici u https://developers.redhat.com/books/building-reactive-microservices-java. Kombinace Vert.x a Reactive eXtension uvolní vaši reaktivní superschopnost. Můžete nejen používat reaktivní programování, ale také vytvářet reaktivní systémy a mít přístup ke vzrušujícímu a rostoucímu ekosystému.

Šťastné kódování!“

Stáhněte si tahák Eclipse Vert.x, tento tahák obsahuje podrobnosti krok za krokem, které vám umožní vytvářet aplikace podle vašich představ.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.