Reactive programming principles

32
PRINCIPI DI REACTIVE PROGRAMMING INGEGNERIA DEL SOFTWARE Università degli Studi di Padova Dipartimento di Matematica Corso di Laurea in Informatica, A.A. 2013 – 2014 [email protected]

description

A very introductive presentation about reactive programming principles. Starting from synchronous standard programming, I try to present the needs that driven to reactive programming. Callbacks, Future, Promises, Observables and Actor model are the main issues. I also make an introduction to the Reactive Manifesto. The presentation is took from the Software Engineering course I run in the bachelor-level informatics curriculum at the University of Padova.

Transcript of Reactive programming principles

Page 1: Reactive programming principles

PRINCIPI DI REACTIVE PROGRAMMINGINGEGNERIA DEL SOFTWAREUniversità degli Studi di Padova

Dipartimento di Matematica

Corso di Laurea in Informatica, A.A. 2013 – 2014

[email protected]

Page 2: Reactive programming principles

2

Ingegneria del software mod. B

GO REACTIVE!

Applicazione anni 2000 Decine di server Tempi di risposta nell’ordine dei secondi Ore di downtime per manutenzione Dati nell’ordine dei Gigabyte Accedute da dispositivi desktop

Applicazione moderne (≥ 2010) Cluster di migliaia di processi multicore Tempi di risposta nell’ordine dei millisec 100% uptime Dati nell’ordine dei Petabyte Accedute da qualsiasi tipo di dispositivo

Riccardo Cardin

Page 3: Reactive programming principles

3

Ingegneria del software mod. B

GO REACTIVE!

Nuovi requisiti richiedono nuove tecnologie Reactive Application

Orientate agli eventi Scalabili Resilienti Responsive

Riccardo Cardin

"Readily responsive to a stimulus"Merriam-Webster

react to eventsLa natura event-driven abilita

alle altre qualità

react to loadLa scalabilità non deve dipendere

da risorse condivise

react to failureSistemi resilienti permettonodi recuperare errori a tutti

i livelli

react to usersI tempi di risposta non devonodipendere dal carico di lavoro

Page 4: Reactive programming principles

4

Ingegneria del software mod. B

REACTIVE MANIFESTO

Riccardo Cardin

responsive

scalable resilient

event-driven

• Loosely coupled design• Communication

orientation• Uso efficiente delle risorse

• Nessun redesing per ottenere la scalabilità

• Scalabilità on-demand

• Risk-management

• Downtime è perdita di denaro

• Parte del design

• Real-time, engaging, reach, collaborative

• Nessuna latenza nelle risposte

Page 5: Reactive programming principles

5

Ingegneria del software mod. B

MODELLO SINCRONO

Il mondo sincrono è senza futuro...

Frequenti operazioni di I/O Scarso utilizzo delle feature offerte dai processori

moderni Larga diffusione delle architetture multiprocessore

Cicli non ottimizzati Scarso parallelismo o gestione difficoltosa Tipico dei linguaggi imperativi e ad oggetti

C, C++, Java, ...

Riccardo Cardin

// Synchronous world (w/o Future)val session = socialNetwork.createSessionFor("user", credentials)// blocked on method, waiting for results (latency)...session.getFriends()// There are a lot of operation to do!!! :(

Page 6: Reactive programming principles

6

Ingegneria del software mod. B

MODELLO SINCRONO

Il mondo sincrono è senza futuro... Esempio: recuperare il nome del file più pesante

Riccardo Cardin

public String getBiggestFile(final File folder) { long maxLength = 0L; String fileName = null; for (final File fileEntry : folder.listFiles()) { if (maxLength < fileEntry.length()) { // Not so efficient fileName = fileEntry.getName(); maxLength = fileEntry.length(); } } return fileName ;}

...

if (maxLength… // computationfileEntry.length() // I/O

CPU poco utilizzata, I/O

sovrabbondante

Java

Tempo totale di attesa

Page 7: Reactive programming principles

7

Ingegneria del software mod. B

MODELLO ASINCRONO

Callbacks Funzioni da invocare al termine di una

elaborazione Gestione migliore della CPU Ridotti tempi di attesa

Più processi gestiscono più richieste Asynchronous JavaScript and XML (AJAX)

Riccardo Cardin

var callback = function(){ alert('I was called back asynchronously');};

$.ajax({ type: 'GET', url: 'http://example.com', done: callback, // positive case fail: anotherCallback // negative case}); jQuery

In attesa della risposta, è possibile continuare

l’elaborazione (rendering UI)

Page 8: Reactive programming principles

8

Ingegneria del software mod. B

MODELLO ASINCRONO

Callbacks

Linguaggi o framework che gestiscano l’elaborazione asincrona e concorrente Node.js, jQuery, ...

Ma...c’è sempre un ma...

Riccardo Cardin

CPU1

CPU2

CPU3

CPU4

Tempo totale di attesa

I/O è ancora presente, ma viene distribuito

sull’elaborazione di più CPU

Page 9: Reactive programming principles

9

Ingegneria del software mod. B

MODELLO ASINCRONO

Callbacks...HELL!!!

Riccardo Cardin

Page 10: Reactive programming principles

10

Ingegneria del software mod. B Riccardo Cardin

module.exports = function (dir, cb) {  fs.readdir(dir, function (er, files) {     if (er) return cb(er)    var counter = files.length    var errored = false    var stats = []     files.forEach(function (file, index) {      fs.stat(path.join(dir,file), function (er, stat) {         if (errored) return        if (er) {          errored = true          return cb(er)        }        stats[index] = stat          if (--counter == 0) {           var largest = stats            .filter(function (stat) { return stat.isFile() })             .reduce(function (prev, next) { // [6]              if (prev.size > next.size) return prev              return next            })          cb(null, files[stats.indexOf(largest)])         }      }) // [1]    }) // [2]  }) // [3]}

node.js

Innesto callback per gestire i flussi degli eventi

Difficile da verificare e manutenere

Difficile gestire le eccezioni con blocchi

try/catch

Page 11: Reactive programming principles

11

Ingegneria del software mod. B

FUTURES E PROMISES

Futures Tecnica per eseguire molte operazioni in

parallelo, in modo efficiente e non-blocking Stile dichiarativo Immutabile

Rappresenta un segnaposto per un risultato futuro Componibili Implementano meccanismi per la gestione delle

eccezioni

Riccardo Cardin

// With Futures (asynchronous world)val session = socialNetwork.createSessionFor("user", credentials)// Create placeholder for computationval f: Future[List[Friend]] = future { session.getFriends() }// Statements here can be executed, while waiting for results :)

scala

Page 12: Reactive programming principles

12

Ingegneria del software mod. B

FUTURES E PROMISES

Monad Rappresenta un contesto di esecuzione

(framework) Amplificatore di tipi, computation builder Può racchiudere un tipo

È componibile con altre monadi Composizione (a.k.a. concatenazione) sul tipo

racchiuso

Spesso permette di estrarre il valore del tipo contenuto Caratteristica dei linguaggi funzionali

Riccardo Cardin

public class Monad<T> { public Monad(T t) { /* ... */ }}

public class Monad<T> { public abstract <V> Monad<V> bind(Function<T, Monad<V>> f);}

Page 13: Reactive programming principles

13

Ingegneria del software mod. B

FUTURES E PROMISES

Monad È simile ad una bolla!

Riccardo Cardin

Può racciudere qualcosa

È qualcosa di non concreto

Può ricevere istruzioni su cosa fare del

contenuto

Può evaporare, lasciando libero il

contenuto

Page 14: Reactive programming principles

14

Ingegneria del software mod. B

FUTURES E PROMISES

Future[T] è una monad Racchiudono l’elaborazione da eseguire in modo

asincrono (callback) Successfully completed / Failed with an exception Eventual execution: nessun vincolo temporale

Riccardo Cardin

import scala.util.{Success, Failure}// Asynchronous execution inside future contextval f: Future[List[String]] = future { session.getRecentPosts}// Do something else...f onComplete { // onSuccess case Success(posts) => for (post <- posts) println(post) // onFailure case Failure(t) => println("An error has occured: " + t.getMessage)}

posts è il risulato dell’elaborazione

t è un’eccezione scala

Page 15: Reactive programming principles

15

Ingegneria del software mod. B

FUTURES E PROMISES

Future[T] è una monad Composizione funzionale di più elaborazioni

Non più callback hell!!! Si riporta il modello asincrono al modello sincrono Se un future nella catena fallisce, fallisce l’intera

catena

Riccardo Cardin

// First future executionval rateQuote = future { connection.getCurrentValue(USD)}// Bind second execution to firstval purchase = rateQuote map { quote => if (isProfitable(quote)) connection.buy(amount, quote) else throw new Exception("not profitable")}// Get final resultpurchase onSuccess { case _ => println("Purchased " + amount + " USD")} scala

Page 16: Reactive programming principles

16

Ingegneria del software mod. B

FUTURES E PROMISES

Promise[T] Single-assigment container (monad) / proxy

Un Future legge il risultato di un’elaborazione asincrona

Una Promise scrive (completa) un Future

Riccardo Cardin

val p = promise[T]// Future that is completed by the promiseval f = p.futureval consumer = future { startDoingSomething() f onSuccess { case r => doSomethingWithResult() }}val producer = future { val r = produceSomething() p success r // Promise completes the Future // It should be ‘p failure exception’ also continueDoingSomethingUnrelated()}

produceSomething

startDoingSomething

doSomethingWithResult

r

scala

Valore che rappresenta

l’elaborazione

Page 17: Reactive programming principles

17

Ingegneria del software mod. B

FUTURES E PROMISES

Javascript promises (Q library) Promise e future sono fusi nelle medesime

strutture

Promise stile Scala Q Deferreds

Riccardo Cardin

promiseMeSomething()// value is the return value of promiseMeSomething.then(function (value) { // Do something as soon as promiseMeSomething finishes}, // Something went wrong, reason is an exception function (reason) {});

then ritona una promise, quindi è

concatenabile

var deferred = Q.defer();FS.readFile("foo.txt", "utf-8", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise; Deferred permette di

completare una promise. concatenabile

Page 18: Reactive programming principles

18

Ingegneria del software mod. B

FUTURES E PROMISES

Java 8 promises: CompletableFuture<T>

Creazione (usando le lambda extension)

Composizione (future stile Scala)

Riccardo Cardin

A Future that may be explicitly completed (setting its value and status), and may include dependent functions and actions that trigger upon its completion.

Javadoc

final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { //...long running... return "42"; }, executor);

Effettua l’override del metodo

CompletableFuture.get()

// f1 is a promise that will completed with an Integer valueCompletableFuture<Double> f3 = f1.thenApply(Integer::parseInt).thenApply(r -> r * r * Math.PI). exceptionally(ex -> "We have a problem: " + ex.getMessage());

thenApply è simile a map di Scala

Page 19: Reactive programming principles

19

Ingegneria del software mod. B

REACTIVE EXTENSIONS (RX)

Gestione sequenze di valori in modo asincrono Observable sequences

Estensione del design pattern Observer Utilizzo di operatori di composizione (monads!)

Riccardo Cardin

Single items Multiple items

Synchronous T getData() Iterable<T> getData()

Asynchronous Future<T> getData() Observable<T> getData

public static void hello(String... names) { Observable.from(names).subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println("Hello " + s + "!"); } });} // hello("Ben", "George"); Hello Ben! Hello George!

Page 20: Reactive programming principles

20

Ingegneria del software mod. B

REACTIVE EXTENSIONS (RX)

Observables (RxJava)

Riccardo Cardin

Event Iterable (pull) Observable (push)

Retrieve data T next() onNext(T)

Discover error throws Exception

onError(Exception)

Complete returns onCompleted()

Aggiunta al pattern

GoF

getVideos().subscribe(new Observer<Video>() { def void onNext(Video video) { // Invoked on next element println(“Video: ” + video.videoId) } def void onError(Exception e) { // Invoked on error e.printStackTrace() } def void onCompleted() { // Invoked when stream finishes to emit println(“Completed”) }}

Page 21: Reactive programming principles

21

Ingegneria del software mod. B

REACTIVE EXTENSIONS (RX)

Observables (RxJava) Monads Componibili

Mantengono la proprietà di asincronia originaria

Riccardo Cardin

Page 22: Reactive programming principles

22

Ingegneria del software mod. B

REACTIVE EXTENSIONS (RX)

Composizione Observables

Riccardo Cardin

Page 23: Reactive programming principles

23

Ingegneria del software mod. B

ACTOR MODEL

Reactive Elaborazioni solo in risposta a stimoli esterni

Dormiente / attivo Non c’è un concetto esplicito di thread

Tre azioni fondamentali Invio di un messaggio async a se stesso o altro

attore Creazione nuovi attori Modifica del proprio comportamento

Nessuno stato interno (...in teoria...) ImmutabiliRiccardo Cardin

Each actor is a form of reactive object, executing some computation in response to a message and sending out a reply when the computation is done

John C. Mitchell

Page 24: Reactive programming principles

24

Ingegneria del software mod. B

ACTOR MODEL

Messaggi (task) Interfaccia di comunicazione dell’attore

Variare nel tempo (comportamento) Elaborazione dei messaggi uno per volta

Coda di messaggi (mail box) Nessuna garanzia sull’ordine di arrivo

Mail system Ogni attore ha associato un mail address

Composti di tre parti

Riccardo Cardin

tag target data

email address del receiver

operazione

Page 25: Reactive programming principles

25

Ingegneria del software mod. B

ACTOR MODEL

Esempio Ad ogni cambio di stato viene creato un nuovo

attore State change: no race conditions Behavioural change

Riccardo Cardin

A1:[1, 4, 7]

A1:[1, 2, 4, 7]

A1:[2, 4, 7]

Insert|2

Get_min

Min|1

Page 26: Reactive programming principles

26

Ingegneria del software mod. B

ACTOR MODEL

Akka Toolkit e runtime che implementano attori su JVM

Riccardo Cardin

(c) http://akka.io

Page 27: Reactive programming principles

27

Ingegneria del software mod. B

AKKA

Riccardo Cardin

type Receive = PartialFunction[Any, Unit]trait Actor { def receive: Receive // Actor actual behaviour implicit val self: ActorRef // Reference to itself def sender: ActorRef // Reference to the sender of last message implicit val context: ActorContext // Execution context}abstract class ActorRef { // Send primitives def !(msg: Any)(implicit sender: ActorRef = Actor.noSender): Unit def tell(msg: Any, sender: ActorRef) = this.!(msg)(sender) // ...}trait ActorContext { // Change behaviour of an Actor def become(behavior: Receive, discardOld: Boolean = true): Unit def unbecome(): Unit // Create a new Actor def actorOf(p: Props, name: String): ActorRef def stop(a: ActorRef): Unit // Stop an Actor // ...}

scala

Page 28: Reactive programming principles

28

Ingegneria del software mod. B

AKKA

Esempio Implementazione di un contatore con gli attori

Riccardo Cardin

class Counter extends Actor { // State == explicit behaviour def counter(n: Int): Receive = { // Receive two types of messages: ‘incr’ and ‘get’ // ‘incr’ change actor’s behaviour case ”incr” => context.become(counter(n + 1)) // ‘get’ returns current counter value to sender case ”get” => sender ! n } def receive = counter(0) // Default behaviour} scala

a:[0]

a!incr

a:[1]

a!incr

a:[2]

a!get sender!2

È possibile modellare

anche stati

interni

Page 29: Reactive programming principles

29

Ingegneria del software mod. B

AKKA

Resilienza Contenimento e riposte automatiche agli errori

Gli attori in errore vengono terminati o riavviati La decisione è presa da un attore supervisore Gli attori con supervisione formano una struttura ad

albero Il supervisore crea i suoi subordinati

Riccardo Cardin

class Manager extends Actor { // OneForOneStrategy restarts only actor which died override val supervisorStrategy = OneForOneStrategy() { case _: DBException => Restart // reconnect to DB case _: ActorKilledException => Stop case _: ServiceDownException => Escalate } // ... context.actorOf(Props[DBActor], ”db”) // ...}

sup

sub1

sub2

sub1.1Error flow

Page 30: Reactive programming principles

30

Ingegneria del software mod. B

AKKA

Actor lifecycle

Riccardo Cardin

Start

Restart

Stop

new ActorpreStart

fail

preStartnew Actor

stop

postStop

Supervisor

An actor

ActorRef rimane valido tra un

riavvio e l’altro

Le fasi di riavvio possono essere

molteplici

Page 31: Reactive programming principles

31

Ingegneria del software mod. B

BIBLIOGRAFIA The Reactive Manifesto

http://www.reactivemanifesto.org/ Promises in Node.js with Q – An Alternative to Callbacks

http://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/

The Reactive Extensions (Rx) http://msdn.microsoft.com/en-us/data/gg577609.aspx

Futures and Promises http://docs.scala-lang.org/overviews/core/futures.html

Java concurrency (multi-threading) http://www.vogella.com/tutorials/JavaConcurrency/article.html#futures

Java 8: Definitive guide to CompletableFuture http://nurkiewicz.blogspot.it/2013/05/java-8-definitive-guide-to.html

Taming asynchronous programming http://eamodeorubio.github.io/tamingasync/#/

Riccardo Cardin

Page 32: Reactive programming principles

32

Ingegneria del software mod. B

BIBLIOGRAFIA Monadic futures in Java 8

http://zeroturnaround.com/rebellabs/monadic-futures-in-java8/

Monads http://ericlippert.com/category/monads/ Callback Hell http://callbackhell.com/ CompletableFuture http://

www.slideshare.net/kojilin/completable-future RxJava Wiki https://github.com/Netflix/RxJava/wiki Functional Reactive Programming with RxJava https://

speakerdeck.com/benjchristensen/functional-reactive-programming-with-rxjava-javaone-2013

Principle of Reactive Programming https://class.coursera.org/reactive-001

Actors http://doc.akka.io/docs/akka/snapshot/scala/actors.html

Riccardo Cardin