5 ting at vide om reaktiv programmering

Af Clement Escoffier 30. juni 20176. august 2020

Reaktiv, sikke et overbelastet ord. Mange ting viser sig at blive magisk Reaktiv i disse dage. I dette indlæg vil vi tale om reaktiv programmering, dvs. en udviklingsmodel, der er struktureret omkring asynkrone datastrømme.

Jeg ved godt, at du er utålmodig efter at skrive din første reaktive applikation, men inden du gør det, er der et par ting, du skal vide. Ved at bruge reaktiv programmering ændres den måde, du designer og skriver din kode på. Før du hopper på toget, er det godt at vide, hvor du er på vej hen.

I dette indlæg vil vi forklare 5 ting om reaktiv programmering for at se, hvad det ændrer for dig.

Når du bruger reaktiv programmering, vil datastrømme være rygraden i din applikation. Begivenheder, meddelelser, opkald og endda fejl vil blive formidlet af en datastrøm. Med reaktiv programmering observerer du disse strømme og reagerer, når der udsendes en værdi.

Så i din kode vil du oprette datastrømme af hvad som helst og fra hvad som helst: klikhændelser, HTTP-forespørgsler, indhentede meddelelser, meddelelser om tilgængelighed, ændringer på en variabel, cache-hændelser, målinger fra en sensor, bogstaveligt talt alt, der kan ændre sig eller ske. Dette har en interessant sideeffekt på din applikation: den bliver i sagens natur asynkron.

Reactive eXtension (http://reactivex.io, a.ka. RX) er en implementering af de reaktive programmeringsprincipper til at “sammensætte asynkrone og begivenhedsbaserede programmer ved hjælp af observerbar sekvens”. Med RX opretter og abonnerer din kode på datastrømme ved navn Observables. Mens Reactive Programming handler om koncepterne, giver RX dig en fantastisk værktøjskasse. Ved at kombinere observatør- og iteratormønstre og funktionelle idiomer giver RX dig superkræfter. Du har et arsenal af funktioner til at kombinere, sammensmelte, filtrere, transformere og skabe datastrømme. Det næste billede illustrerer brugen af RX i Java (ved hjælp af https://github.com/ReactiveX/RxJava).

Selv om RX ikke er den eneste implementering af principperne for reaktiv programmering (vi kan f.eks. nævne BaconJS – http://baconjs.github.io), er det den mest anvendte i dag. I resten af dette indlæg vil vi bruge Rx Java.

2. Observables kan være kolde eller varme – og det betyder noget.

På dette tidspunkt forsøger du at se, hvad der er de forskellige streams (eller observables), som du skal håndtere i dit program. Men der er to klasser af streams: varme og kolde. Forståelse af forskellen er nøglen til succesfuld brug af reaktiv programmering.

Cold observables er dovne. De gør ikke noget, før nogen begynder at observere dem (subscribe i RX). De begynder først at køre, når de bliver forbrugt. Cold streams bruges til at repræsentere asynkrone handlinger, f.eks. at det ikke vil blive udført, før nogen er interesseret i resultatet. Et andet eksempel kunne være en fildownload. Den vil ikke begynde at trække bytes, hvis der ikke er nogen, der vil gøre noget med dataene. De data, der produceres af en kold strøm, deles ikke blandt abonnenterne, og når du abonnerer, får du alle emnerne.

Hot streams er aktive før abonnementet som f.eks. en aktietæller eller data sendt af en sensor eller en bruger. Dataene er uafhængige af en individuel abonnent. Når en observatør abonnerer på en hot observable, får den alle værdier i strømmen, der udsendes, efter at den har abonneret. Værdierne deles mellem alle abonnenterne. Selv om ingen har abonneret på et termometer, måler og offentliggør det f.eks. den aktuelle temperatur, selv om ingen har abonneret på det. Når en abonnent tilmelder sig strømmen, modtager den automatisk den næste måling.

Hvorfor er det så vigtigt at forstå, om dine strømme er varme eller kolde? Fordi det ændrer, hvordan din kode forbruger de formidlede elementer. Hvis du ikke er tilmeldt en hot observable, modtager du ikke dataene, og disse data går tabt.

Udvikl med Red Hats mest værdifulde produkter

Dit medlemskab låser op for Red Hat-produkter og teknisk træning i udvikling af cloud-applikationer til virksomheder.

JOIN RED HAT DEVELOPER

Misbrugte asynkrone bidder

Der er et vigtigt ord i definitionen af reaktiv programmering: asynkron. Du får besked, når der udsendes data i strømmen asynkront – dvs. uafhængigt af hovedprogramforløbet. Ved at strukturere dit program omkring datastrømme skriver du asynkron kode: du skriver kode, der påkaldes, når strømmen udsender et nyt element. Tråde, blokerende kode og sideeffekter er meget vigtige ting i denne sammenhæng. Lad os begynde med sideeffekter.

Funktioner uden sideeffekter interagerer med resten af programmet udelukkende gennem deres argumenter og returværdier. Sideeffekter kan være meget nyttige og er i mange tilfælde uundgåelige. Men de har også faldgruber. Når man bruger reaktiv programmering, bør man undgå unødvendige sideeffekter og have en klar hensigt, når man bruger dem. Så omfavn uforanderlighed og sideeffektfrie funktioner. Selv om nogle tilfælde er berettigede, fører misbrug af sideeffekter til tordenvejr: trådsikkerhed.

Det er det andet vigtige punkt: tråde. Det er rart at observere streams og få besked, når der sker noget interessant, men du må aldrig glemme, hvem der kalder dig, eller mere præcist, på hvilken tråd dine funktioner udføres. Det anbefales kraftigt at undgå at bruge for mange tråde i dit program. Asynkrone programmer, der er afhængige af flere tråde, bliver et svært synkroniseringspuslespil, der ofte ender som en dødløshedsjagt.

Det er det tredje punkt: aldrig blokere. Fordi du ikke ejer den tråd, der kalder dig, skal du være sikker på aldrig at blokere den. Hvis du gør det, kan du undgå de andre elementer, der skal udsendes, de vil blive buffered indtil … bufferen er fuld (back-pressure kan træde ind i dette tilfælde, men det er ikke emnet for dette indlæg). Ved at kombinere RX og asynkron IO har du alt hvad du behøver for at skrive ikke-blocking kode, og hvis du vil have mere, kan du kigge på Eclipse Vert.x, et reaktivt værktøjssæt der fremmer reaktivitet og asynkronitet. Følgende kode viser f.eks. Vert.x Web Client og dens RX API til at hente et JSON-dokument fra serveren og vise navnet på posten:

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

Bemærk subscribe-metoden i dette sidste uddrag. Den tager en anden metode, der kaldes, når et af behandlingsstadierne kaster en undtagelse. Fang altid undtagelserne. Hvis du ikke gør det, vil du bruge timer på at forsøge at forstå, hvad der går galt.

4. Hold tingene enkle

Som du ved, “Med stor magt følger stort ansvar”. RX giver masser af meget fede funktioner, og det er let at læne sig mod den mørke side. Chaining flapmap, retry, debounce og zip får dig til at føle dig som en ninja… MEN glem aldrig, at god kode skal kunne læses af andre.

Lad os tage noget kode…

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

Givet et eksempel som dette er kan være svært at forstå ikke? Den kæder flere asynkrone operationer (flatmap), slutter sig til et andet sæt operationer (zip). Reaktiv programmeringskode kræver først et mind-shift. Du får besked om asynkrone begivenheder. Derefter kan API’et være svært at forstå (se bare på listen over operatører). Lad være med at misbruge, skriv kommentarer, forklar eller tegn diagrammer (jeg er sikker på, at du er en asciiart-kunstner). RX er kraftfuldt, at misbruge det eller ikke forklare det vil gøre dine kolleger gnavne.

5. Reaktiv programmering != Reaktivt system

Men det er nok den mest forvirrende del. Ved at bruge reaktiv programmering opbygger man ikke et reaktivt system. Reaktive systemer, som defineret i det reaktive manifest, er en arkitektonisk stil til at opbygge responsive distribuerede systemer. Reaktive systemer kan ses som distribuerede systemer gjort rigtigt. Et reaktivt system er kendetegnet ved fire egenskaber:

  • Responsivt: Et reaktivt system skal håndtere anmodninger inden for en rimelig tid (jeg lader dig definere rimelig).
  • Resilient: Et reaktivt system skal forblive responsivt i tilfælde af fejl (nedbrud, timeout, 500 fejl … ), så det skal være designet til fejl og håndtere dem på passende vis.
  • Elastisk: Et reaktivt system skal forblive responsivt under forskellige belastninger. Derfor skal det skaleres op og ned og være i stand til at håndtere belastningen med minimale ressourcer.
  • Meddelelsesdrevet: Komponenter fra et reaktivt system interagerer ved hjælp af asynkron beskedoverførsel.

Trods enkelheden i disse grundlæggende principper for reaktive systemer er det vanskeligt at opbygge et af dem. Typisk skal hver knudepunkt omfavne en asynkron ikke-blokkerende udviklingsmodel, en opgavebaseret konkurrencemodel og anvender ikke-blokkerende I/O. Hvis du ikke tænker over disse punkter først, bliver det hurtigt en spaghettiplade.

Reactive Programming and Reactive eXtension giver en udviklingsmodel til at tæmme det asynkrone bæst. Ved at bruge den klogt, vil din kode forblive læsbar, og forståelig. Men ved at bruge reaktiv programmering forvandler du ikke dit system til et reaktivt system. Reaktive systemer er det næste niveau.

Konklusion

Vi når endelig til slutningen af dette indlæg. Hvis du vil gå videre og er interesseret i reaktiv, vil jeg anbefale dig at tage et kig på Eclipse Vert.x – et værktøjssæt til at bygge reaktive og distribuerede systemer (http://vertx.io) og på minibogen Reactive Microservices in Java, der kan fås hos https://developers.redhat.com/books/building-reactive-microservices-java. Ved at kombinere Vert.x og Reactive eXtension slipper du dine reaktive superkræfter løs. Du kan ikke kun bruge reaktiv programmering, men også bygge reaktive systemer og få adgang til et spændende og voksende økosystem.

Happy coding!

Download Eclipse Vert.x cheat sheet, dette snydeark indeholder trinvise detaljer, så du kan oprette dine apps på den måde, du ønsker det.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.