Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
Ad ogni nodo viene perciò assegnata un’altezza (si tratta di un numero che può
essere calcolato come l’altezza del nodo all’interno del grafo ordinato topologica-
mente) che è superiore a quella di qualsiasi nodo da cui dipende. I nodi vengono
14
INDICE 15
successivamente processati tramite una coda con priorità utilizzando proprio le
altezze come fattore di priorità. Questa tecnica di rimozione dei glitch è comune
a vari linguaggi di programmazione reattivi tra cui Scala.React e Flapjax [1].
Al nodo viene quindi applicata un’altezza a un’altezza e a
var1 0, var2 1
un’altezza e vengono tutti posti in una coda seguendo la priorità data dal
var3 2
loro valore di altezza. Quando il nodo cambia stato la coda con priorità
var1
segna priorità pari a e perciò permette al nodo di aggiornarsi ed inviare i dati
0
ad entrambi i nodi genitore e A questo punto la coda incrementa la
var2 var3.
priorità ad consentendo quindi soltanto a di aggiornare il proprio stato
1, var2
e propagare il cambiamento al suo unico nodo dipendente Infine la coda
var3.
incrementa la priorità a permettendo a di aggiornarsi avendo ricevuto
2 var3
tutte le nuove informazioni e quindi eliminando la possibilità di generare glitch e
inconsistenze di dati. La coda con priorità e l’ordine topologico imposto ai nodi
del grafo si rivelano perciò cruciali, in quanto bloccano l’aggiornamento dei nodi
che possiedono una priorità maggiore di quella attualmente servita dalla coda
evitando che possano aggiornare prematuramente il proprio stato, prevedendo
che essi possano avere in quel momento un quadro solamente parziale (e quindi
sorgente di errori) degli aggiornamenti dei nodi dai quali dipendono.
2.5 Flussi asincroni di dati ed eventi
Il trasporto e l’elaborazione dei dati e degli eventi per mezzo di flussi asincroni
osservabili dall’esterno è una caratteristica cosı̀ importante da permeare l’inte-
ro paradigma di Reactive Programming. Nella programmazione reattiva, infatti,
tutto può essere visto come una sorgente (un flusso) di dati: le variabili (che
possono mutare stato emettendo un nuovo valore ad ogni cambiamento), le posi-
zioni del puntatore del mouse, i tocchi dell’utente sul display dello smartphone,
le coordinate del GPS, i messaggi provenienti dai social e molto altro. Qualsiasi
struttura capace di incapsulare o inviare una qualsiasi tipologia di informazione
può potenzialmente essere vista come uno stream di dati/eventi.
Per descrivere i flussi nel panorama della programmazione reattiva ci si av-
4
vale molto spesso dei cosiddetti marble diagram , diagrammi che semplificano la
comprensione dell’andamento dei flussi di dati ed eventi nel tempo, del loro com-
4 Per maggiori informazioni visitare: http://rxmarbles.com/
15
16 INDICE
portamento e delle operazioni applicate ad essi. Gli elementi costitutivi di base di
un marble diagram sono i seguenti:
• una freccia/linea mono-direzionata che rappresenta lo scorrere del tempo
(solitamente da sinistra a destra);
• delle piccole figure geometriche (spesso cerchi) giacenti sulla linea temporale,
le quali rappresentano eventi oppure dati emessi dal flusso in un preciso
istante di tempo e quindi ordinati temporalmente;
• una x posta sulla linea temporale che rappresenta l’invio di un messaggio di
errore;
• un breve segmento ortogonale alla linea temporale e posto su di essa, il
quale indica che lo stream ha terminato gli elementi da inviare e ha dunque
concluso il suo compito.
Per fare un esempio, in figura 7 è rappresentato un flusso di eventi di click di un
bottone attraverso il formalismo dei marble diagram.
Figura 7: Esempio di marble diagram che rappresenta un flusso di
eventi di click di un bottone
Dall’esempio si possono facilmente intuire le tre differenti tipologie di segnale
(messaggio) che un flusso di dati è in grado di emettere:
16
INDICE 17
• emissione di un elemento (dato oppure evento);
• emissione di un messaggio di errore;
• emissione di un messaggio di completamento.
Già ora, e in maggior misura nella prossima sotto-sezione, risulta chiaro come
l’approccio utilizzato dalla programmazione reattiva non si basi esclusivamente su
quello tipico del pattern Observer ma lo estenda includendo funzionalità nuove
quali, un esempio, la capacità di notificare gli osservatori circa le condizioni di
errore o completamento del flusso di dati.
2.6 Entità osservabili e osservatrici
I flussi (stream) di dati/eventi (per semplicità, d’ora in poi, il termine dati/even-
ti potrà essere sostituito talvolta con il termine elementi ) nella programmazione
reattiva vengono chiamati entità osservabili, mentre coloro che li osservano sono
chiamati entità osservatrici. Un’entità osservabile rappresenta una sorgente di ele-
menti mentre un’entità osservatrice è colei che rimane in ascolto di un’entità osser-
vabile. É comprensibile che esistano queste due entità poiché, come già specificato,
la Reactive Programming recupera i principi del pattern Observer.
Di seguito vengono descritte le due entità più nel dettaglio, mantenendo sem-
pre il grado di astrazione tipico della letteratura sulla programmazione reattiva,
dunque senza calare il discorso su un linguaggio o un’architettura specifici.
Entità osservabile
Un’entità osservabile rappresenta un flusso che emette dati/eventi all’esterno, ad
intervalli regolari di tempo oppure in maniera totalmente asincrona; lo stream
può avere un numero qualunque di elementi da emettere, inclusi zero o infiniti.
Un’entità osservabile, però, non si limita solo ad emettere dati/eventi ma può
anche terminare con successo inviando un messaggio di avvenuto completamen-
to, oppure terminare con insuccesso inviando un messaggio di errore. Un’entità
osservabile infinita (cioè con un numero potenzialmente infinito di elementi da
emettere, come per esempio gli eventi di click dell’utente all’interno di un’appli-
cazione Android) non potrà mai terminare con un messaggio di completamento,
poiché questo deve essere inviato solo all’esaurimento degli elementi disponibili (in
17
18 INDICE
questo caso potenzialmente infiniti), potrà però terminare in ogni momento con
un messaggio di errore nel caso in cui si manifesti un malfunzionamento durante
l’esecuzione dell’entità osservabile stessa; in quest’ultima ipotesi l’entità infinita
terminerà prematuramente e non emetterà più alcun elemento.
Entità osservatrice
Un’entità osservatrice si può legare (sottoscrivere) ad un’entità osservabile al fi-
ne di catturare i dati/eventi emessi da quest’ultima e gestirli secondo specifiche
politiche. È bene ricordare che gli elementi vengono emessi sempre in sequenza,
uno dopo l’altro, e l’entità osservatrice che li cattura ne gestisce solitamente uno
solo dopo aver gestito il precedente. In generale quindi non si generano mai corse
5
critiche ; se molti dati/eventi vengono emessi da un’entità osservabile in un breve
intervallo temporale e l’entità osservatrice non riesce a stare al passo con la lo-
ro elaborazione, questi devono essere mantenuti in una coda degli eventi oppure
scartati. Infine, un’entità osservabile può avere zero, una o più entità osservatrici
sottoscritte.
3 Contesti d’utilizzo
I principali contesti nei quali risulta vantaggioso ed efficiente l’utilizzo della Reac-
tive Programming sono i seguenti (e riassunti in figura 8):
• applicazioni interattive, dove è necessaria l’elaborazione di molteplici input
provenienti dall’interfaccia grafica e azionati dall’utente in maniera asincrona
(click del mouse o di un bottone, tocco sullo schermo dello smartphone,
ecc..);
• applicazioni che interagiscono con sensori e perciò ricevono continui dati
aggiornati in tempo reale (GPS, accelerometro, sensori di prossimità, ecc..);
• applicazioni che instaurano connessioni multiple verso server e dunque ne-
cessitano di richiedere e inviare informazioni ad essi ininterrottamente;
5 In realtà nulla impedisce al programmatore di sovrascrivere il normale comportamento di
un’entità osservatrice, seppur possa essere fonte di problemi.
18
INDICE 19
• social network, che devono reagire prontamente alla rete e agli utenti, ag-
giornando in tempo reale i server e le applicazioni in base alle azioni degli
utenti (like, post, upload di foto, chatting, ecc..) in maniera da riflettere
immediatamente i cambiamenti su ogni dispositivo collegato;
• videogiochi, con multiple sorgenti di dati ed eventi da captare e gestire con
elevate precisione e velocità;
• applicazioni per lo streaming video, che devono continuamente comunicare
con i server e aggiornare lo stato ad ogni ricezione audio-video;
• applicazioni che recepiscono informazioni dalla rete e le visualizzano, per
esempio applicazioni per il meteo, le news, RSS, ecc..;
• in generale tutte le applicazioni che ricevono informazioni da più sorgenti,
specialmente se inviate in maniera asincrona, e che devono reagire pronta-
mente ad ogni possibile evento di interesse.
Figura 8: Principali contesti d’utilizzo della programmazione reattiva
4 Vantaggi rispetto ad altri approcci
Il paradigma di programmazione reattiva mostra i suoi grandi vantaggi special-
mente se posto a confronto con quello di programmazione imperativa, in quanto
essi risultano impiegare approcci diametralmente opposti in molteplici situazioni.
19
20 INDICE
Nella programmazione imperativa è il programmatore a dover specificare, at-
traverso l’utilizzo di istruzioni, come il programma debba arrivare passo a passo
al raggiungimento degli obiettivi prefissati; invece, utilizzando la programmazione
reattiva, ed in maniera ancora più evidente una sua estensione chiamata program-
6
mazione reattiva funzionale , l’approccio tende a farsi dichiarativo: in questo caso
al programmatore viene richiesto di specificare principalmente cosa il programma
deve fare, lasciando i dettagli del come farlo al linguaggio sottostante. La pro-
grammazione reattiva rende il codice più conciso e aumenta il livello di astrazione
in modo che ci si possa concentrare sulla logica d’interdipendenza fra gli eventi,
piuttosto che sul trattamento di grandi quantità di dettagli implementativi.
I vantaggi si rivelano ancora più evidenti se si osservano le moderne app web
e mobile, altamente interattive e con una moltitudine di potenziali eventi prove-
nienti dall’interfaccia grafica [7]. Una dozzina di anni fa, infatti, l’interazione con
le pagine web consisteva essenzialmente nell’invio di lunghe form a backend e nel-
7
l’esecuzione di semplici rendering a fronte