5 asiaa reaktiivisesta ohjelmoinnista

Toimittaja Clement Escoffier 30. kesäkuuta 20176. elokuuta 2020

Reaktiivinen, mikä ylikuormitettu sana. Moni asia osoittautuu nykyään maagisesti Reaktiiviseksi. Tässä postauksessa puhumme reaktiivisesta ohjelmoinnista eli asynkronisten tietovirtojen ympärille rakentuvasta kehitysmallista.

Tiedän, että olet kärsimätön kirjoittamaan ensimmäisen reaktiivisen sovelluksesi, mutta ennen kuin teet sen, on pari asiaa tiedettävä. Reaktiivisen ohjelmoinnin käyttäminen muuttaa sitä, miten suunnittelet ja kirjoitat koodia. Ennen kuin hyppäät junaan, on hyvä tietää, mihin olet menossa.

Tässä postauksessa selitämme 5 asiaa reaktiivisesta ohjelmoinnista, jotta näet, mitä se muuttaa sinulle.

Käytettäessä reaktiivista ohjelmointia tietovirrat tulevat olemaan sovelluksesi selkäranka. Tapahtumat, viestit, kutsut ja jopa epäonnistumiset välitetään tietovirran avulla. Reaktiivisessa ohjelmoinnissa tarkkailet näitä tietovirtoja ja reagoit, kun arvo lähetetään.

Luot siis koodissasi tietovirtoja mistä tahansa ja mistä tahansa: klikkaustapahtumista, HTTP-pyynnöistä, syötetyistä viesteistä, käytettävyysilmoituksista, muuttujan muutoksista, välimuistitapahtumista, anturin mittauksista, kirjaimellisesti kaikesta, mikä voi muuttua tai tapahtua. Tällä on mielenkiintoinen sivuvaikutus sovellukseesi: siitä tulee luonnostaan asynkroninen.

Reactive eXtension (http://reactivex.io, a.ka. RX) on reaktiivisen ohjelmoinnin periaatteiden toteutus ”asynkronisten ja tapahtumapohjaisten ohjelmien kokoamiseksi havainnoitavaa sekvenssiä käyttäen”. RX:n avulla koodisi luo ja tilaa Observables-nimisiä tietovirtoja. Vaikka reaktiivisessa ohjelmoinnissa on kyse käsitteistä, RX tarjoaa sinulle hämmästyttävän työkalupakin. Yhdistämällä observer- ja iteraattorimallit sekä funktionaaliset idiomit RX antaa sinulle supervoimia. Sinulla on arsenaali funktioita, joilla voit yhdistää, yhdistää, suodattaa, muuntaa ja luoda tietovirtoja. Seuraava kuva havainnollistaa RX:n käyttöä Javassa (käyttäen https://github.com/ReactiveX/RxJava).

Vaikka RX ei ole ainoa reaktiivisen ohjelmoinnin periaatteiden toteutus (voimme mainita esimerkiksi BaconJS:n – http://baconjs.github.io), se on nykyään käytetyin. Loppupuolella tätä viestiä käytämme Rx Javaa.

2. Havaintoaineistot voivat olla kylmiä tai kuumia – ja sillä on väliä.

Tässä vaiheessa yrität hahmottaa, mitä eri virtoja (tai havaintoaineistoja) aiot käsitellä ohjelmassasi. Mutta virtoja on kahta luokkaa: kuumia ja kylmiä. Eron ymmärtäminen on avainasemassa, jotta voit menestyksekkäästi käyttää reaktiivista ohjelmointia.

Kylmät havaintovirrat ovat laiskoja. Ne eivät tee mitään ennen kuin joku alkaa tarkkailla niitä (subscribe in RX). Ne alkavat toimia vasta, kun niitä kulutetaan. Kylmiä havaintovirtoja käytetään kuvaamaan esimerkiksi asynkronisia toimintoja, että sitä ei suoriteta ennen kuin joku on kiinnostunut tuloksesta. Toinen esimerkki olisi tiedoston lataus. Se ei ala vetää tavuja, jos kukaan ei aio tehdä tiedoilla mitään. Kylmän virran tuottamaa dataa ei jaeta tilaajien kesken, ja kun teet tilauksen, saat kaikki kohteet.

Kylmät virrat ovat aktiivisia ennen tilausta, kuten pörssin tiketti tai anturin tai käyttäjän lähettämä data. Tiedot ovat riippumattomia yksittäisestä tilaajasta. Kun havaitsija tilaa kuuman havaintovirran, se saa kaikki virran arvot, jotka lähetetään sen tilauksen jälkeen. Arvot jaetaan kaikkien tilaajien kesken. Esimerkiksi vaikka kukaan ei olisi tilannut lämpömittaria, se mittaa ja julkaisee senhetkisen lämpötilan. Kun tilaaja rekisteröityy streamiin, se saa automaattisesti seuraavan mittauksen.

Miksi on niin tärkeää ymmärtää, onko streamisi kuuma vai kylmä? Koska se muuttaa sitä, miten koodisi kuluttaa välitettyjä kohteita. Jos et ole tilannut kuumaa havainnoitavaa, et saa tietoja, ja nämä tiedot menetetään.

Kehitä Red Hatin arvokkaimpien tuotteiden avulla

Jäsenyytesi avaa Red Hatin tuotteita ja teknistä koulutusta yritysten pilvisovellusten kehittämiseen.

LIITY RED HAT DEVELOPERIIN

Väärin käytetty asynkronisuus puree

Reaktiivisen ohjelmoinnin määritelmässä on yksi tärkeä sana: asynkroninen. Sinulle ilmoitetaan, kun dataa lähetetään virtaan asynkronisesti – eli ohjelman päävirrasta riippumatta. Rakentamalla ohjelmasi tietovirtojen ympärille kirjoitat asynkronista koodia: kirjoitat koodia, jota kutsutaan, kun tietovirta lähettää uuden kohteen. Säikeet, estävä koodi ja sivuvaikutukset ovat tässä yhteydessä hyvin tärkeitä asioita. Aloitetaan sivuvaikutuksista.

Funktiot, joilla ei ole sivuvaikutuksia, ovat vuorovaikutuksessa muun ohjelman kanssa yksinomaan argumenttiensa ja paluuarvojensa kautta. Sivuvaikutukset voivat olla hyvin hyödyllisiä ja ovat monissa tapauksissa väistämättömiä. Mutta niillä on myös sudenkuoppia. Reaktiivista ohjelmointia käytettäessä on vältettävä tarpeettomia sivuvaikutuksia ja oltava selkeä aikomus, kun niitä käytetään. Hyväksy siis muuttumattomuus ja sivuvaikutuksista vapaat funktiot. Vaikka jotkut tapaukset ovat perusteltuja, sivuvaikutusten väärinkäyttö johtaa ukkosmyrskyihin: säikeiden turvallisuuteen.

Tässä on toinen tärkeä kohta: säikeet. On mukavaa tarkkailla säikeitä ja saada ilmoitus, kun jotain mielenkiintoista tapahtuu, mutta et saa koskaan unohtaa, kuka sinua kutsuu, tai tarkemmin sanottuna missä säikeessä funktiosi suoritetaan. On erittäin suositeltavaa välttää liian monen säikeen käyttöä ohjelmassasi. Useisiin säikeisiin tukeutuvista asynkronisista ohjelmista tulee kova synkronointipalapeli, joka usein päättyy umpikujaan.

Tässä on kolmas kohta: älä koskaan blokkaa. Koska et omista sinua kutsuvaa säiettä, sinun täytyy olla varma, ettet koskaan blokkaa sitä. Jos teet niin, voit välttää muita lähetettäviä kohteita, niitä puskuroidaan, kunnes … puskuri on täynnä (vastapaino voi potkaista tässä tapauksessa, mutta se ei ole tämän viestin aihe). Yhdistämällä RX:n ja asynkronisen IO:n sinulla on kaikki, mitä tarvitset lukkiutumattoman koodin kirjoittamiseen, ja jos haluat enemmän, katso Eclipse Vert.x, reaktiivisuutta ja asynkronisuutta edistävä reaktiivinen työkalupakki. Esimerkiksi seuraavassa koodissa Vert.x Web Client ja sen RX API hakee JSON-dokumentin palvelimelta ja näyttää nimimerkinnän:

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

Huomaa subscribe-metodi tässä viimeisessä pätkässä. Se ottaa toisen metodin, jota kutsutaan, kun jokin käsittelyvaiheista heittää poikkeuksen. Ota poikkeukset aina kiinni. Jos et tee niin, käytät tunteja yrittäessäsi ymmärtää, mikä menee pieleen.

4. Pidä asiat yksinkertaisina

Kuten tiedät, ”Suuren vallan mukana tulee suuri vastuu”. RX tarjoaa paljon erittäin hienoja toimintoja, ja on helppo kallistua pimeälle puolelle. Flapmap-, retry-, debounce- ja zip-ketjujen ketjuttaminen saa sinut tuntemaan itsesi ninjaksi… MUTTA, älä koskaan unohda, että hyvän koodin on oltava jonkun muun luettavissa.

Katsotaanpa vähän koodia…

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

Tämmöisen esimerkin antaminen voi olla vaikeasti ymmärrettävää eikö? Se ketjuttaa useita asynkronisia operaatioita (flatmap), yhdistää toisen joukon operaatioita (zip). Reaktiivinen ohjelmointikoodi vaatii ensin mielenmuutoksen. Sinulle ilmoitetaan asynkronisista tapahtumista. Sitten API voi olla vaikea ymmärtää (katso operaattorien luetteloa). Älä väärinkäytä, kirjoita kommentteja, selitä tai piirrä kaavioita (olet varmasti asciiart-taiteilija). RX on voimakas, sen väärinkäyttö tai selittämättä jättäminen saa työtoverisi murjottamaan.

5. Reaktiivinen ohjelmointi != Reaktiivinen järjestelmä

Varmasti hämmentävin osa. Reaktiivisen ohjelmoinnin käyttäminen ei rakenna reaktiivista järjestelmää. Reaktiiviset järjestelmät, kuten reaktiivisessa manifestissa määritellään, ovat arkkitehtuurityyli reagoivien hajautettujen järjestelmien rakentamiseen. Reaktiivisia järjestelmiä voisi pitää oikein tehtyinä hajautettuina järjestelminä. Reaktiiviselle järjestelmälle on ominaista neljä ominaisuutta:

  • Reagoiva: reaktiivisen järjestelmän on käsiteltävä pyynnöt kohtuullisessa ajassa (annan sinun määritellä kohtuullisen).
  • Joustava: reaktiivisen järjestelmän on pysyttävä reagoivana vikojen (kaatuminen, aikakatkaisu, 500 virhettä… ) edessä, joten se on suunniteltava vikojen varalle ja käsiteltävä niitä asianmukaisesti.
  • Elastinen: reaktiivisen järjestelmän on pysyttävä reagoivana erilaisissa kuormituksissa. Näin ollen sen täytyy skaalautua ylös- ja alaspäin ja pystyä käsittelemään kuormitusta minimaalisilla resursseilla.
  • Viestiohjattu: reaktiivisen järjestelmän komponentit ovat vuorovaikutuksessa keskenään käyttäen asynkronista viestien välittämistä.

Vaikka nämä reaktiivisten järjestelmien perusperiaatteet ovat yksinkertaisia, sellaisen rakentaminen on hankalaa. Tyypillisesti jokaisen solmun on omaksuttava asynkroninen lukkiutumaton kehitysmalli, tehtäväpohjainen samanaikaisuusmalli ja käytettävä lukkiutumatonta I/O:ta. Jos et mieti näitä kohtia ensin, siitä tulee nopeasti spagettilautanen.

Reaktiivinen ohjelmointi ja Reactive eXtension tarjoaa kehitysmallin asynkronisen pedon kesyttämiseen. Käyttämällä sitä viisaasti koodisi pysyy luettavana ja ymmärrettävänä. Reaktiivisen ohjelmoinnin käyttäminen ei kuitenkaan muuta järjestelmääsi reaktiiviseksi järjestelmäksi. Reaktiiviset järjestelmät ovat seuraava taso.

Johtopäätös

Olemme vihdoin päässeet tämän postauksen loppuun. Jos haluat mennä pidemmälle ja olet kiinnostunut reaktiivisuudesta, suosittelen tutustumaan Eclipse Vert.x – työkalupakettiin reaktiivisten ja hajautettujen järjestelmien rakentamiseen (http://vertx.io) ja Reactive Microservices in Java minikirjaan, joka on saatavilla osoitteesta https://developers.redhat.com/books/building-reactive-microservices-java. Vert.x:n ja Reactive eXtensionin yhdistäminen vapauttaa reaktiivisen supervoimasi. Voit paitsi käyttää reaktiivista ohjelmointia myös rakentaa reaktiivisia järjestelmiä ja päästä käsiksi jännittävään ja kasvavaan ekosysteemiin.

Happy coding!

Lataa Eclipse Vert.x -huijauslappu, tämä huijauslappu tarjoaa vaiheittaisia yksityiskohtia, joiden avulla voit luoda sovelluksesi haluamallasi tavalla.

Vastaa

Sähköpostiosoitettasi ei julkaista.