Estratto del documento

Indice

1 Definizione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Caratteristiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2.1 Propagazione del cambiamento . . . . . . . . . . . . . . . . 3

2.2 Strategie di propagazione . . . . . . . . . . . . . . . . . . . . 7

2.3 Modelli di valutazione . . . . . . . . . . . . . . . . . . . . . 9

2.4 Glitch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

Metodi di rimozione . . . . . . . . . . . . . . . . . 12

2.5 Flussi asincroni di dati ed eventi . . . . . . . . . . . . . . . . 15

2.6 Entità osservabili e osservatrici . . . . . . . . . . . . . . . . 17

Entità osservabile . . . . . . . . . . . . . . . . . . . 17

Entità osservatrice . . . . . . . . . . . . . . . . . . 18

3 Contesti d’utilizzo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

4 Vantaggi rispetto ad altri approcci . . . . . . . . . . . . . . . . . . 19

5 Programmazione reattiva distribuita . . . . . . . . . . . . . . . . . 21

6 Programmazione reattiva funzionale . . . . . . . . . . . . . . . . . . 22

Functional Programming . . . . . . . . . . . . . . . 22

Functional Reactive Programming . . . . . . . . . 23

6.1 Astrazioni di base . . . . . . . . . . . . . . . . . . . . . . . . 24

7 Tassonomia dei linguaggi reattivi . . . . . . . . . . . . . . . . . . . 25

8 Uso industriale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

9 Il manifesto reattivo . . . . . . . . . . . . . . . . . . . . . . . . . . 29

Bibliografia 32

1

Programmazione reattiva

Questi appunti si propongono di descrivere il panorama della programmazione

reattiva partendo dal principio, cioè dalle sue caratteristiche fondanti, per poi

procedere a piccoli passi verso argomenti più di dettaglio cercando sempre, prima

dell’introduzione di ognuno di essi (per quanto possibile), di fornire al lettore le

nozioni di base per poter affrontare la lettura senza difficoltà.

1 Definizione

Premettendo che non è tuttora esistente una definizione ufficialmente riconosciu-

ta di programmazione reattiva (RP, Reactive Programming), una di quelle che

condensa al meglio la filosofia di questo paradigma è probabilmente la seguente:

la programmazione reattiva è un paradigma di programmazione che si

avvale dei concetti del pattern Observer per gestire ed elaborare dati

ed eventi tramite flussi asincroni e osservabili dall’esterno, in accordo

con la nozione di propagazione del cambiamento.

2 Caratteristiche

Dalla definizione si può evincere come la programmazione reattiva sia un para-

digma fortemente correlato all’utilizzo di stream asincroni di dati/eventi e perciò

particolarmente utile nella programmazione event-driven, efficace per lo sviluppo

di applicazioni che necessitano di risposte reattive a stimoli provenienti in maniera

asincrona da molteplici fonti, situazione riscontrabile tipicamente su piattaforme

web e mobile. Questo approccio prevalentemente asincrono indebolisce i legami

2

INDICE 3

(loose coupling) tra i componenti dei programmi, producendo codice altamente

modulare e dunque più facilmente modificabile, manutenibile ed estensibile.

È importante precisare che si parla di flussi di informazioni osservabili, i cui

dati ed eventi emessi sono perciò catturabili dall’esterno e gestibili all’occorrenza

da tutti coloro che necessitino di continui aggiornamenti riguardo uno specifico

evento d’interesse. All’interno di questo contesto trova dunque facilmente posto il

1

Design Pattern Observer [11] della GoF , il quale definisce una o più dipendenze

fra oggetti, cosı̀ che quando uno di essi cambia stato, tutti i suoi sottoscrittori

vengono notificati automaticamente e possono reagire di conseguenza.

Per quanto riguarda invece il concetto di propagazione del cambiamento (Pro-

pagation of change), si tratta di una nozione presente in letteratura e su cui si

fonda il pensiero della programmazione reattiva; verrà esposto in maniera più

dettagliata nella prossima sottosezione.

2.1 Propagazione del cambiamento

Nel paradigma di programmazione reattiva tutto può essere trasmesso tramite

stream asincroni: dati, eventi, messaggi, chiamate, situazioni di successo e di er-

rore. Si possono osservare questi flussi e reagire quando da essi vengono emessi

valori. Questo ha un effetto interessante sulle applicazioni poiché tende a farle

diventare intrinsecamente asincrone ed event-driven, reattive nel gestire i cam-

biamenti in atto e le loro propagazioni spesso prive di sincronia. All’interno del

contesto delineatosi si afferma l’idea di propagazione del cambiamento, concetto

che sta alla base del paradigma in esame.

Si prenda come esempio esplicativo la seguente istruzione in pseudo-codice:

a := b + c

Se si utilizza un linguaggio imperativo, l’assegnamento di cui sopra applica alla

variabile il risultato dovuto alla somma tra le variabili e e questo avvie-

a b c,

ne nel preciso istante nel quale l’espressione viene valutata. Ciò significa che un

cambiamento successivo dei valori di e/o di non produce alcun effetto sulla

b c

variabile la quale mantiene sempre il valore originariamente calcolato (a meno,

a,

1 Gang of Four, cosı̀ vengono spesso chiamati Erich Gamma, Richard Helm, Ralph Johnson e

John Vlissides, autori del libro Design Patterns: Elements of Reusable Object-Oriented Software.

3

4 INDICE

ovviamente, di una nuova valutazione dell’espressione stessa). In programmazione

reattiva, invece, il concetto di propagazione del cambiamento rende il procedi-

mento differente: il valore di viene infatti sempre aggiornato automaticamente

a

ogniqualvolta i valori delle variabili e/o cambiano, senza prevedere la necessità

b c

da parte del programma di rieseguire l’istruzione di assegnamento di a.

La logica della propagazione del cambiamento può essere per esempio imple-

mentata per mezzo di un grafo i cui nodi rappresentano i valori da tenere aggiornati

e i cui archi rappresentano le relazioni di dipendenza che coinvolgono i nodi. Tra-

mite questo tipo di architettura si viene quindi a creare una rete di dipendenze

computazionali ed il cambiamento di un nodo (cioè di un valore) scatena una

reazione che implica l’attraversamento degli eventuali archi ad esso collegati e il

conseguente aggiornamento di tutti i nodi raggiunti.

Per rendere più chiari questi concetti, viene esposto di seguito un semplice

esempio in pseudo-codice. number1 := 4

number2 := 6

sum := number1 + number2

average := sum / 2

Il codice mostra l’assegnamento dei valori 4 e 6 a due variabili (number1 e number2),

con successivo calcolo e salvataggio della somma e della media aritmetica (ri-

spettivamente all’interno delle variabili ed In questo caso risulta

sum average).

estremamente semplice costruire il corrispondente grafo delle dipendenze per la

propagazione dei cambiamenti, in figura 1:

4

INDICE 5

Figura 1: Grafo delle dipendenze, somma e media di due numeri

Si può facilmente notare come il primo nodo genitore (average) abbia solo un

nodo figlio (sum), perciò dipenda solo da esso, mentre quest’ultimo dipenda invece

da due nodi figlio (rappresentati dalle variabili e questi ultimi

number1 number2);

sono attualmente anche nodi periferici del grafo orientato, perciò si possono consi-

derare ‘autonomi‘ perché non dipendono da nessun altro nodo figlio e nell’attuale

configurazione non possono quindi mai subire modifiche propagate.

Seguendo l’approccio imperativo, i valori delle variabili ed vengo-

sum average

no assegnati durante l’esecuzione del frammento di codice e non risultano aggior-

nati dopo una modifica dei valori delle variabili che rappresentano i due numeri.

Al contrario, seguendo l’approccio dettato dalla programmazione reattiva e in par-

ticolare dal concetto di propagazione del cambiamento su cui il paradigma si basa,

ogni modifica dei valori delle variabili e propaga il cambiamento

number1 number2

al nodo genitore il quale aggiorna la somma e propaga a sua volta l’informa-

sum,

zione di cambiamento al nodo genitore il quale infine aggiorna il valore

average,

della media aritmetica.

La situazione cambia leggermente nel prossimo esempio, sempre in pseudo-

codice. 5

6 INDICE

numbers := [1, 2, 3, 4, 5, 6]

sum := 0

for each number in numbers

sum := sum + number

end

average := sum / count(numbers)

In questo caso non sono presenti solo due numeri di cui far la somma e la media,

bensı̀ un array di numeri grande a piacere, perciò è necessario iterare l’intero

vettore per calcolare la somma totale dei suoi elementi e ricavarne la lunghezza

(count(numbers)) per quantificare il valore al denominatore nella formula per

la media aritmetica. In figura 2 viene mostrato il grafo delle dipendenze per la

propagazione dei cambiamenti relativo a questo esempio:

Figura 2: Grafo delle dipendenze, somma e media di un array di numeri

Si può osservare come il nodo genitore contrariamente all’esempio prece-

average,

dente, si ritrovi ora ad avere due nodi figlio da cui dipende, e e come

sum numbers,

quest’ultimo abbia due nodi genitore (average e Questo accade per il sem-

sum).

plice motivo che la variabile contenente la media viene assegnata tramite un’espres-

sione che coinvolge entrambe le variabili (average := sum / count(numbers));

si trova a dipendere quindi non più solo dal valore della somma ma anche

average

dalla lunghezza dell’array di numeri. Se subisce una mutazione, la notifi-

numbers

ca del cambiamento viene propagata attraverso il grafo delle dipendenze a ed

sum

6

INDICE 7

2

ma solo il primo può essere aggiornato poiché il secondo non possiede

average,

ancora tutte la nuove informazioni per poter calcolare la media; una volta che an-

che il nodo notifica il cambiamento del valore della somma al nodo genitore,

sum

allora questo viene aggiornato.

2.2 Strategie di propagazione

Le principali strategie adottabili per la propagazione del cambiamento nella pro-

grammazione reattiva sono le seguenti:

• Complete propagation

Ogni nodo, durante la propagazione, invia il suo attuale stato completo ai

nodi dipendenti; in questo caso, tutto lo stato precedente del nodo viene

perso durante l’aggiornamento al nuovo stato. Questa strategia presenta

un alto carico computazionale, in quanto ogni nodo mutato propaga il suo

completo stato, perciò non è adatto nei casi in cui il grafo delle dipenden-

ze computazionali sia particolarmente complesso o nel caso in cui gli stati

necessitino di grandi quantità di dati per essere descritti.

• Delta propagation

Nel momento della propagazione i nodi interessati inviano solo una porzione

(un delta) del loro stato ai nodi dipendenti, cioè solo le frazioni di infor-

mazione che sono state effettivamente coinvolte da modifiche. Le porzioni

di stato precedenti non soggette ad alterazioni permangono all’interno dei

nodi, non vengono perse. Questo tipo di approccio tende a minimizzare la

quantità di dati da trasportare lungo la catena di dipendenze durante la pro-

pagazione dei cambiamenti, dunque risulta efficiente anche nei casi in cui si

presenti un grafo delle dipendenze complesso o una gran quantità di dati per

la rappresentazione degli stati, situazioni nelle quali la complete propagation

mostra invece limitazioni.

2 Nel caso in cui calcolasse comunque la media senza possedere tutte le informazioni

average

aggiornate si potrebbe verificare un malfunzionamento dovuto ad inconsistenza dei dati chiamato

glitch, argomento della sottosezione 1.2.4. 7

8 INDICE

• Batch propagation

La batch propagation è un approccio che prevede la non immediata pro-

pagazione dei cambiamenti, cioè la propagazione ritardata nel tempo. È

un metodo di ottimizzazione: se due o più cambiamenti vicini nel tempo

si annullano a vicenda (fanno cioè sı̀ che si ritorni allo stato di partenza,

precedente ai cambiamenti stessi), oppure un aggiornamento non modifica

alcuno stato, la propagazione non avviene, in quanto non è in atto nessun

cambiamento complessivo nel concreto. Al contrario, nel caso due o più

cambiamenti vicini nel tempo generino un’effettiva mutazione di stato nel

grafo, viene propagato solo l’ultimo cambiamento, infatti i precedenti risul-

tano ormai obsoleti. Questa strategia minimizza il numero di propagazioni e

quindi di percorrenza delle dipendenze nel grafo e di carico computazionale

complessivo, ma tende a rendere il sistema meno reattivo ai cambiamenti,

poiché essi vengono ritardati nel tempo. É dunque cruciale adottare un tem-

po di ritardo corretto, al fine di ritardare il cambiamento riducendo il carico

di elaborazione ma al tempo stesso non diminuire eccessivamente la reatti-

vità del sistema; si delinea quindi una strategia efficace nel caso in cui le

computazioni e il trasferimento di dati tra i nodi si rivelino particolarmente

onerosi e sia tollerabile un leggero ritardo di reattività ai cambiamenti.

• Invalidity notification propagation

Non si delinea propriamente come una strategia implementativa, quanto più

come una ”sotto-strategia”, cioè un approccio utilizzabile potenzialmente ac-

canto ad ognuna delle tre strategie precedentemente descritte. É utilizzabile

inoltre soltanto nei casi in cui il sistema di interesse possieda un grafo del-

le dipendenze con direzionalità di propagazione di tipo pull oppure hybrid

(verranno descritti nella prossima sottosezione). La invalidity notification

propagation consiste nella richiesta di aggiornamento (pull update) da parte

di un nodo che riscontra di possedere uno stato non valido, oppure che riceve

un messaggio di propagazione non valido. In questo caso il nodo interessato

scarta l’anomalia e richiede ai nodi da cui dipende un nuovo aggiornamento

in merito. Dopo la ricezione del nuovo aggiornamento, e solo nel caso questo

risulti valido, il nodo si aggiorna e lo propaga come di consueto attraverso

le dipendenze ad esso collegate.

Si ricorda che è possibile anche progettare architetture reattive che contemplino

la contemporanea presenza di più strategie, fra loro non in contrasto, al fine di

8

INDICE 9

ricavare vantaggi da tutte in base alle differenti situazioni. Un’ottima idea può

essere per esempio quella di impiegare la delta propagation insieme alla batch

propagation.

2.3 Modelli di valutazione

Per modello di valutazione (evaluation model ) nella Reactive Programming si in-

tende la dinamica direzionale adottata per la propagazione dei cambiamenti nel

grafo delle dipendenze computazionali del sistema reattivo. Il modello viene appli-

cato a livello di linguaggio e rimane trasparente al programmatore, che non deve

quindi preoccuparsi di propagare i dati manualmente.

Come già specificato precedentemente, un nodo trasmette il cambiamento ad

altri nodi suoi dipendenti seguendo la rete di relazioni rappresentata dal grafo; il

nodo che invia può essere quindi visto come un produttore di dati (informazioni

di cambiamento) e i nodi che ricevono come dei consumatori di dati, in accordo

con la logica produttore-consumatore evidenziata in figura 3.

A questo punto, però, bisogna prendere un’importante decisione di progetta-

zione: è necessario infatti scegliere quale modello di valutazione adottare, ognuno

di essi offre vantaggi in alcune situazioni e svantaggi in altre. La letteratura pre-

senta due principali modelli [1][9] a cui si aggiunge un terzo ibrido fra i primi

due:

• Push-based

Nel modello push-based la reazione ha inizio quando un nodo produttore

(origine) cambia stato aggiornandosi, in questo caso ”spinge” (push) l’infor-

mazione di cambiamento attraverso il grafo verso i nodi consumatori suoi

dipendenti (destin

Anteprima
Vedrai una selezione di 8 pagine su 35
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 1 Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 2
Anteprima di 8 pagg. su 35.
Scarica il documento per vederlo tutto.
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 6
Anteprima di 8 pagg. su 35.
Scarica il documento per vederlo tutto.
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 11
Anteprima di 8 pagg. su 35.
Scarica il documento per vederlo tutto.
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 16
Anteprima di 8 pagg. su 35.
Scarica il documento per vederlo tutto.
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 21
Anteprima di 8 pagg. su 35.
Scarica il documento per vederlo tutto.
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 26
Anteprima di 8 pagg. su 35.
Scarica il documento per vederlo tutto.
Programmazione Reattiva - Appunti dettagliati di teoria (35 pagine) Pag. 31
1 su 35
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher Nikwanted di informazioni apprese con la frequenza delle lezioni di Programmazione e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Bologna o del prof Ricci Alessandro.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community