5 lucruri de știut despre programarea reactivă

De Clement Escoffier 30 iunie 20176 august 2020

Reactiv, ce cuvânt supraîncărcat. Multe lucruri se dovedesc a deveni în mod magic Reactive în zilele noastre. În această postare, vom vorbi despre Programarea Reactivă, adică un model de dezvoltare structurat în jurul fluxurilor de date asincrone.

Știu că sunteți nerăbdători să scrieți prima aplicație reactivă, dar înainte de a o face, există câteva lucruri pe care trebuie să le știți. Utilizarea programării reactive schimbă modul în care vă proiectați și scrieți codul. Înainte de a vă urca în tren, este bine să știți încotro vă îndreptați.

În această postare, vom explica 5 lucruri despre programarea reactivă pentru a vedea ce schimbă pentru dumneavoastră.

Când folosiți programarea reactivă, fluxurile de date vor fi coloana vertebrală a aplicației dumneavoastră. Evenimentele, mesajele, apelurile și chiar și eșecurile vor fi transmise printr-un flux de date. Cu programarea reactivă, observați aceste fluxuri și reacționați atunci când este emisă o valoare.

Atunci, în codul dumneavoastră, veți crea fluxuri de date din orice și de la orice: evenimente de clic, solicitări HTTP, mesaje ingerate, notificări de disponibilitate, modificări pe o variabilă, evenimente cache, măsuri de la un senzor, literalmente orice se poate schimba sau întâmpla. Acest lucru are un efect secundar interesant asupra aplicației dumneavoastră: devine inerent asincronă.

Reactive eXtension (http://reactivex.io, a.ka. RX) este o implementare a principiilor de programare reactivă pentru a „compune programe asincrone și bazate pe evenimente prin utilizarea secvenței observabile”. Cu RX, codul dvs. creează și se abonează la fluxuri de date numite Observables. În timp ce programarea reactivă se referă la concepte, RX vă oferă o cutie de instrumente uimitoare. Prin combinarea modelelor observator și iterator și a idiomurilor funcționale, RX vă oferă superputeri. Aveți la dispoziție un arsenal de funcții pentru a combina, fuziona, filtra, transforma și crea fluxuri de date. Următoarea imagine ilustrează utilizarea RX în Java (folosind https://github.com/ReactiveX/RxJava).

Chiar dacă RX nu este singura implementare a principiilor de programare reactivă (de exemplu, putem cita BaconJS – http://baconjs.github.io), astăzi este cea mai frecvent utilizată. În restul acestei postări, vom folosi Rx Java.

2. Observabilele pot fi reci sau calde – și contează.

În acest moment, încercați să vedeți care sunt diferitele fluxuri (sau observabile) cu care veți avea de-a face în programul dumneavoastră. Dar există două clase de fluxuri: calde și reci. Înțelegerea diferenței este esențială pentru a utiliza cu succes programarea reactivă.

Observabilele reci sunt leneșe. Ele nu fac nimic până când cineva nu începe să le observe (subscribe în RX). Ele încep să funcționeze doar atunci când sunt consumate. Fluxurile reci sunt folosite pentru a reprezenta acțiuni asincrone, de exemplu, că nu va fi executată până când cineva este interesat de rezultat. Un alt exemplu ar fi descărcarea unui fișier. Nu va începe să extragă octeții dacă nimeni nu are de gând să facă ceva cu datele. Datele produse de un flux rece nu sunt partajate între abonați și atunci când vă abonați primiți toate elementele.

Fluxurile calde sunt active înainte de abonare, cum ar fi un ticker de acțiuni sau datele trimise de un senzor sau de un utilizator. Datele sunt independente de un abonat individual. Atunci când un observator se abonează la un observabil fierbinte, acesta va primi toate valorile din fluxul care sunt emise după ce se abonează. Valorile sunt partajate între toți abonații. De exemplu, chiar dacă nimeni nu s-a abonat la un termometru, acesta măsoară și publică temperatura curentă. Atunci când un abonat se înregistrează la flux, acesta primește automat următoarea măsurătoare.

De ce este atât de important să înțelegeți dacă fluxurile dvs. sunt calde sau reci? Pentru că acest lucru schimbă modul în care codul dvs. consumă elementele vehiculate. Dacă nu sunteți abonat la un observabil fierbinte, nu veți primi datele, iar aceste date sunt pierdute.

Dezvoltați folosind cele mai valoroase produse Red Hat

Abonamentul dvs. deblochează produsele Red Hat și instruirea tehnică privind dezvoltarea de aplicații cloud enterprise.

ADERĂ-TE LA RED HAT DEVELOPER

Asincronia folosită greșit mustește

Există un cuvânt important în definiția programării reactive: asincron. Sunteți notificat atunci când datele sunt emise în flux în mod asincron – adică independent de fluxul principal al programului. Prin structurarea programului dvs. în jurul fluxurilor de date, scrieți cod asincron: scrieți cod invocat atunci când fluxul emite un element nou. Thread-urile, codul blocant și efectele secundare sunt aspecte foarte importante în acest context. Să începem cu efectele secundare.

Funcțiile fără efecte secundare interacționează cu restul programului exclusiv prin argumentele și valorile lor de retur. Efectele secundare pot fi foarte utile și sunt inevitabile în multe cazuri. Dar ele au și capcane. Atunci când folosiți programarea reactivă, ar trebui să evitați efectele secundare inutile și să aveți o intenție clară atunci când le folosiți. Așadar, adoptați imutabilitatea și funcțiile fără efecte secundare. În timp ce unele cazuri sunt justificate, abuzul de efecte secundare duce la furtuni: siguranța firelor de execuție.

Acesta este al doilea punct important: firele de execuție. Este frumos să observi fluxurile și să fii notificat atunci când se întâmplă ceva interesant, dar nu trebuie să uiți niciodată cine te apelează sau, mai exact, pe ce fir sunt executate funcțiile tale. Este foarte recomandat să evitați să folosiți prea multe fire de execuție în programul dumneavoastră. Programele asincrone care se bazează pe mai multe fire de execuție devine un puzzle greu de sincronizare care se termină adesea ca o vânătoare de blocaje.

Acesta este al treilea punct: nu blocați niciodată. Deoarece nu dețineți firul care vă apelează, trebuie să vă asigurați că nu îl blocați niciodată. Dacă o faceți, puteți evita ca celelalte elemente să fie emise, ele vor fi stocate în buffer până când … bufferul este plin (în acest caz poate interveni back-pressure, dar nu acesta este subiectul acestei postări). Combinând RX și IO asincron, aveți tot ce vă trebuie pentru a scrie cod non-blocant, iar dacă doriți mai mult, uitați-vă la Eclipse Vert.x, un toolkit reactiv care promovează reactivitatea și asincronia. De exemplu, următorul cod arată clientul Web Vert.x și API-ul RX pentru a prelua un document JSON de pe server și a afișa numele intrării:

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

Rețineți metoda subscribe din acest ultim fragment. Acesta preia o a doua metodă apelată atunci când una dintre etapele de procesare aruncă o excepție. Prindeți întotdeauna excepțiile. Dacă nu o faceți, veți petrece ore întregi încercând să înțelegeți ce nu merge bine.

4. Păstrați lucrurile simple

După cum știți, „Cu o mare putere vine o mare responsabilitate”. RX oferă o mulțime de funcții foarte interesante și este ușor să înclini spre partea întunecată. Înlănțuirea flapmap, retry, debounce și zip vă face să vă simțiți ca un ninja… DAR, nu uitați niciodată că un cod bun trebuie să fie lizibil de către altcineva.

Să luăm puțin cod…

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

Dat un exemplu ca acesta este poate fi greu de înțeles nu? Se înlănțuie mai multe operații asincrone (flatmap), se alătură unui alt set de operații (zip). Codul de programare reactivă necesită în primul rând o schimbare de mentalitate. Sunteți notificat de evenimente asincrone. Apoi, API-ul poate fi greu de înțeles (uitați-vă doar la lista de operatori). Nu abuzați, scrieți comentarii, explicați sau desenați diagrame (sunt sigur că sunteți un artist asciiart). RX este puternic, dacă abuzați de el sau nu-l explicați îi veți face pe colegii dvs. morocănoși.

5. Programare reactivă != Sistem reactiv

Probabil partea cea mai confuză. Folosind programarea reactivă nu se construiește un sistem reactiv. Sistemele reactive, așa cum sunt definite în manifestul reactiv, sunt un stil arhitectural pentru a construi sisteme distribuite reactive. Sistemele reactive ar putea fi văzute ca sisteme distribuite făcute cum trebuie. Un sistem reactiv este caracterizat de patru proprietăți:

  • Receptiv: un sistem reactiv trebuie să trateze cererile într-un timp rezonabil (vă las pe dumneavoastră să definiți rezonabil).
  • Rezilient: un sistem reactiv trebuie să rămână receptiv în fața eșecurilor (crash, timeout, erori 500… ), deci trebuie să fie proiectat pentru eșecuri și să le trateze în mod corespunzător.
  • Elastic: un sistem reactiv trebuie să rămână receptiv sub diverse sarcini. În consecință, acesta trebuie să crească și să scadă și să fie capabil să gestioneze sarcina cu resurse minime.
  • Gestionat de mesaje: componentele unui sistem reactiv interacționează folosind trecerea asincronă a mesajelor.

În ciuda simplității acestor principii fundamentale ale sistemelor reactive, construirea unuia dintre ele este complicată. De obicei, fiecare nod trebuie să îmbrățișeze un model de dezvoltare asincronă neblocantă, un model de concurență bazat pe sarcini și utilizează I/O neblocante. Dacă nu vă gândiți mai întâi la aceste puncte, va fi rapid o farfurie de spaghete.

Reactive Programming and Reactive eXtension oferă un model de dezvoltare pentru a îmblânzi bestia asincronă. Utilizându-l cu înțelepciune, codul dvs. va rămâne lizibil și ușor de înțeles. Cu toate acestea, utilizarea programării reactive nu transformă sistemul dvs. într-un sistem reactiv. Sistemele reactive sunt nivelul următor.

Concluzie

Am ajuns în sfârșit la sfârșitul acestui post. Dacă vreți să mergeți mai departe și sunteți interesați de reactiv, vă recomand să aruncați o privire la Eclipse Vert.x – un set de instrumente pentru a construi sisteme reactive și distribuite (http://vertx.io) și la minilibrul Reactive Microservices in Java disponibil la https://developers.redhat.com/books/building-reactive-microservices-java. Combinând Vert.x și Reactive eXtension vă dezlănțuie superputerea reactivă. Puteți nu numai să folosiți programarea reactivă, ci și să construiți sisteme reactive și să aveți acces la un ecosistem palpitant și în creștere.

Codificare fericită!

Descărcați foaia de trucuri Eclipse Vert.x, această foaie de trucuri oferă detalii pas cu pas pentru a vă permite să vă creați aplicațiile așa cum doriți.

Lasă un răspuns

Adresa ta de email nu va fi publicată.