5 saker att veta om reaktiv programmering

av Clement Escoffier 30 juni 20176 augusti 2020

Reaktiv, vilket överbelastat ord. Många saker visar sig bli magiskt Reactive nuförtiden. I det här inlägget ska vi prata om reaktiv programmering, det vill säga en utvecklingsmodell som är strukturerad kring asynkrona dataströmmar.

Jag vet att du är otålig för att skriva din första reaktiva applikation, men innan du gör det finns det ett par saker att veta. Att använda reaktiv programmering förändrar hur du utformar och skriver din kod. Innan du hoppar på tåget är det bra att veta vart du är på väg.

I det här inlägget kommer vi att förklara 5 saker om reaktiv programmering för att se vad det förändrar för dig.

När du använder reaktiv programmering kommer dataströmmar att vara ryggraden i din applikation. Händelser, meddelanden, anrop och till och med fel kommer att förmedlas av en dataström. Med reaktiv programmering observerar du dessa flöden och reagerar när ett värde sänds ut.

Så, i din kod kommer du att skapa dataflöden av vad som helst och från vad som helst: klickhändelser, HTTP-begäranden, intagna meddelanden, tillgänglighetsmeddelanden, ändringar av en variabel, cachehändelser, mätningar från en sensor, bokstavligen vad som helst som kan förändras eller hända. Detta har en intressant bieffekt på ditt program: det blir till sin natur asynkront.

Reactive eXtension (http://reactivex.io, a.ka. RX) är en implementering av de reaktiva programmeringsprinciperna för att ”komponera asynkrona och händelsebaserade program genom att använda observerbar sekvens”. Med RX skapar och prenumererar din kod på dataströmmar som heter Observables. Medan reaktiv programmering handlar om begreppen ger RX dig en fantastisk verktygslåda. Genom att kombinera observatörs- och iteratormönster och funktionella idiom ger RX dig superkrafter. Du har en arsenal av funktioner för att kombinera, sammanfoga, filtrera, omvandla och skapa dataströmmar. Nästa bild illustrerar användningen av RX i Java (med hjälp av https://github.com/ReactiveX/RxJava).

Och även om RX inte är det enda genomförandet av de reaktiva programmeringsprinciperna (vi kan t.ex. nämna BaconJS – http://baconjs.github.io), så är det den mest använda idag. I resten av det här inlägget kommer vi att använda Rx Java.

2. Observables kan vara kalla eller varma – och det spelar roll.

I det här läget försöker du se vilka olika strömmar (eller observables) du kommer att hantera i ditt program. Men det finns två klasser av strömmar: varma och kalla. Att förstå skillnaden är nyckeln till att framgångsrikt använda reaktiv programmering.

Kalla observabler är lata. De gör ingenting förrän någon börjar observera dem (subscribe i RX). De börjar bara köra när de konsumeras. Cold streams används för att representera asynkrona åtgärder, till exempel att det inte kommer att utföras förrän någon är intresserad av resultatet. Ett annat exempel skulle vara en filnedladdning. Den kommer inte att börja dra bytes om ingen kommer att göra något med uppgifterna. De data som produceras av en kall ström delas inte mellan prenumeranter och när du prenumererar får du alla objekt.

Hot streams är aktiva före prenumerationen som en aktieticker, eller data som skickas av en sensor eller en användare. Uppgifterna är oberoende av en enskild abonnent. När en observatör prenumererar på en varm observabel får den alla värden i strömmen som sänds ut efter prenumerationen. Värdena delas mellan alla prenumeranter. Även om ingen har prenumererat på en termometer mäter och publicerar den till exempel den aktuella temperaturen, även om ingen har prenumererat på den. När en prenumerant registrerar sig på strömmen får den automatiskt nästa mätning.

Varför är det så viktigt att förstå om dina strömmar är varma eller kalla? Därför att det ändrar hur din kod konsumerar de förmedlade objekten. Om du inte är prenumererad på en varm observabel kommer du inte att ta emot data, och dessa data går förlorade.

Utveckla med hjälp av Red Hats mest värdefulla produkter

Ditt medlemskap låser upp Red Hat-produkter och teknisk utbildning om utveckling av molntillämpningar för företag.

JOIN RED HAT DEVELOPER

Missbrukad asynkronitet biter

Det finns ett viktigt ord i definitionen av reaktiv programmering: asynkron. Du meddelas när data sänds ut i strömmen asynkront – det vill säga oberoende av programmets huvudflöde. Genom att strukturera ditt program kring dataströmmar skriver du asynkron kod: du skriver kod som anropas när strömmen avger ett nytt objekt. Trådar, blockerande kod och sidoeffekter är mycket viktiga frågor i detta sammanhang. Låt oss börja med sidoeffekter.

Funktioner utan sidoeffekter interagerar med resten av programmet uteslutande genom sina argument och returvärden. Sidoeffekter kan vara mycket användbara och är oundvikliga i många fall. Men de har också sina fallgropar. När man använder reaktiv programmering bör man undvika onödiga sidoeffekter och ha en tydlig avsikt när man använder dem. Så omfamna oföränderlighet och sidoeffektfria funktioner. Även om vissa fall är motiverade leder missbruk av sidoeffekter till åskväder: trådsäkerhet.

Det är den andra viktiga punkten: trådar. Det är trevligt att observera strömmar och bli underrättad när något intressant händer, men du får aldrig glömma vem som ringer dig, eller mer exakt på vilken tråd dina funktioner exekveras. Det rekommenderas starkt att undvika att använda för många trådar i ditt program. Asynkrona program som förlitar sig på flera trådar blir ett svårt synkroniseringspussel som ofta slutar som en dödlägesjakt.

Det är den tredje punkten: blockera aldrig. Eftersom du inte äger den tråd som kallar dig måste du se till att aldrig blockera den. Om du gör det kan du undvika de andra objekt som ska emitteras, de kommer att buffras tills … bufferten är full (back-pressure kan träda in i det här fallet, men det är inte ämnet för det här inlägget). Genom att kombinera RX och asynkron IO har du allt du behöver för att skriva icke-blockerande kod, och om du vill ha mer kan du titta på Eclipse Vert.x, en reaktiv verktygslåda som främjar reaktivitet och asynkronitet. Följande kod visar till exempel Vert.x Web Client och dess RX API för att hämta ett JSON-dokument från servern och visa namnposten:

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

Lägg märke till subscribe-metoden i det sista utdraget. Den tar en andra metod som anropas när ett av bearbetningsstegen kastar ett undantag. Fånga alltid upp undantagen. Om du inte gör det kommer du att tillbringa timmar med att försöka förstå vad som går fel.

4. Håll saker och ting enkla

Som du vet, ”Med stor makt följer stort ansvar”. RX tillhandahåller många mycket häftiga funktioner och det är lätt att luta sig mot den mörka sidan. Att kedja flapmap, retry, debounce och zip får dig att känna dig som en ninja… MEN glöm aldrig att bra kod måste kunna läsas av någon annan.

Låt oss ta lite kod…

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

Genom ett exempel som detta kan det vara svårt att förstå eller hur? Den kedjar flera asynkrona operationer (flatmap), ansluter sig till en annan uppsättning operationer (zip). Reaktiv programmeringskod kräver först en sinnesförändring. Du får meddelande om asynkrona händelser. Sedan kan API:et vara svårt att förstå (titta bara på listan över operatörer). Missbruka inte, skriv kommentarer, förklara eller rita diagram (jag är säker på att du är en asciiart artist). RX är kraftfullt, att missbruka det eller att inte förklara det kommer att göra dina arbetskamrater griniga.

5. Reaktiv programmering != Reaktivt system

Det är förmodligen den mest förvirrande delen. Att använda reaktiv programmering bygger inte ett reaktivt system. Reaktiva system, enligt definitionen i det reaktiva manifestet, är en arkitektonisk stil för att bygga responsiva distribuerade system. Reaktiva system kan ses som distribuerade system gjorda på rätt sätt. Ett reaktivt system kännetecknas av fyra egenskaper:

  • Responsivt: ett reaktivt system måste hantera förfrågningar inom rimlig tid (jag låter er definiera vad som är rimligt).
  • Resilient: ett reaktivt system måste förbli responsivt vid fel (krasch, timeout, 500 fel… ), så det måste utformas för fel och hantera dem på lämpligt sätt.
  • Elastiskt: ett reaktivt system måste förbli responsivt under olika belastningar. Följaktligen måste det skalas upp och ner och kunna hantera belastningen med minimala resurser.
  • Meddelandedrivet: Komponenter från ett reaktivt system interagerar med hjälp av asynkron meddelandeöverföring.

Trots enkelheten i dessa grundläggande principer för reaktiva system är det knepigt att bygga ett av dem. Typiskt sett måste varje nod omfatta en asynkron icke-blockerande utvecklingsmodell, en uppgiftsbaserad samtidighetsmodell och använda icke-blockerande I/O. Om du inte tänker på dessa punkter först blir det snabbt en spaghettiplatta.

Reactive Programming and Reactive eXtension tillhandahåller en utvecklingsmodell för att tämja det asynkrona odjuret. Genom att använda den klokt kommer din kod att förbli läsbar och begriplig. Att använda reaktiv programmering förvandlar dock inte ditt system till ett reaktivt system. Reaktiva system är nästa nivå.

Slutsats

Vi når äntligen slutet på det här inlägget. Om du vill gå vidare och är intresserad av reaktiv, rekommenderar jag att du tar en titt på Eclipse Vert.x – en verktygslåda för att bygga reaktiva och distribuerade system (http://vertx.io), och på miniboken Reactive Microservices in Java som finns tillgänglig från https://developers.redhat.com/books/building-reactive-microservices-java. Genom att kombinera Vert.x och Reactive eXtension frigör du dina reaktiva superkrafter. Du kan inte bara använda reaktiv programmering utan också bygga reaktiva system och få tillgång till ett spännande och växande ekosystem.

Happy coding!

Ladda ner Eclipse Vert.x cheat sheet, det här fuskbladet innehåller steg för steg detaljer så att du kan skapa dina appar på det sätt du vill.

Lämna ett svar

Din e-postadress kommer inte publiceras.