Il 26 marzo 2015, durante la conferenza F8, Facebook ha pubblicato su GitHub la versione iOS di React Native con licenza BSD; la versione Android è annunciata come in arrivo. Il progetto era già stato mostrato in anteprima al React.js Conf di gennaio, ma il codice diventa pubblico solo adesso.
Contesto
Nel 2015 lo sviluppo mobile segue due strade separate. iOS chiede Objective-C, Xcode e le API di UIKit; Android chiede Java, l’SDK Android e la sua gerarchia di View. Le due piattaforme hanno cicli di rilascio, convenzioni e strumenti di debug diversi. Tenere due basi di codice per la stessa app significa lavoro doppio e divergenze funzionali difficili da evitare.
Fino a qui l’alternativa più diffusa è l’approccio ibrido: Apache Cordova e PhoneGap chiudono un’app scritta in HTML, CSS e JavaScript dentro una WebView, cioè un browser senza barra degli indirizzi. Il guadagno è la condivisione del codice; il costo è che l’interfaccia non usa i controlli del sistema operativo, e su dispositivi meno potenti la differenza nello scorrimento e nelle animazioni si vede.
Architettura
React Native porta il modello di React — quello già noto sul web — allo sviluppo mobile, con una differenza nell’ultimo passo. Un componente scritto in JavaScript non finisce in elementi del DOM, ma in oggetti nativi della piattaforma. Un <View> diventa una UIView su iOS; un <Text> un’etichetta di testo nativa; un <ScrollView> lo scorrimento gestito dal sistema operativo. Il codice resta dichiarativo e in un solo linguaggio, ma a schermo compaiono i widget di sistema, non una pagina dentro un browser.
Sotto ci sono tre thread che girano in parallelo. Il thread JavaScript esegue la logica dell’app dentro un motore — su iOS lo stesso JavaScriptCore di Safari. Un thread di layout calcola dimensioni e posizioni degli elementi con l’implementazione di Flexbox inclusa nel progetto. Il thread principale, quello dell’interfaccia, applica le modifiche agli oggetti nativi e gestisce gli eventi di input.
Questi mondi non condividono memoria. Parlano fra loro attraverso un componente che si chiama bridge. Quando la logica JavaScript decide che l’interfaccia deve cambiare, non tocca direttamente le UIView: produce una descrizione delle modifiche, il bridge la serializza e la passa al lato nativo, che la applica. Il percorso va in entrambi i sensi: un tocco sullo schermo viene intercettato dal lato nativo, serializzato e consegnato al thread JavaScript come evento.
Il punto critico
Le caratteristiche del bridge decidono il comportamento di tutto il sistema. Conviene guardarle da vicino: spiegano i pregi e i limiti dell’architettura.
La comunicazione è asincrona. Nessuno dei due lati aspetta una risposta dall’altro. Il thread di rendering quindi non può essere bloccato da un calcolo JavaScript lungo: nel caso peggiore l’interfaccia continua a rispondere agli input mentre la logica resta indietro, invece di congelarsi del tutto. Per la reattività percepita è un vantaggio, al prezzo di una regola: nessuna operazione può attraversare il confine e attendersi un risultato immediato.
I messaggi sono serializzati — oggi in JSON — e raccolti in lotti. Le singole operazioni non partono una alla volta: si accumulano e si spediscono in gruppo, così i passaggi attraverso il bridge sono meno numerosi. Ogni passaggio ha un costo: serializzare, trasmettere, deserializzare. Finché i dati che attraversano il confine restano pochi, il costo è trascurabile; quando crescono — per esempio scorrendo una lista lunghissima che genera molti eventi al secondo — diventa il fattore che frena le prestazioni.
La scelta è coerente: tenere separati i due mondi lascia scrivere la logica in JavaScript senza riscrivere il motore di rendering, e usare i controlli nativi senza chiuderli in un browser. Il prezzo è che il confine va trattato come una risorsa scarsa, non come una normale chiamata di funzione.
Implicazioni
Sul lato sviluppo cambia il ciclo di feedback. Una modifica al codice JavaScript si ricarica nell’app in esecuzione senza ricompilare il binario nativo e, spesso, senza perdere lo stato della schermata. Su un progetto iOS classico una modifica richiede una compilazione che sulle basi di codice grandi si misura in minuti; qui il riscontro è quasi immediato.
Sul lato del codice condiviso, la logica di business, la gestione dello stato e le chiamate di rete possono valere per entrambe le piattaforme, mentre le parti specifiche di ciascuna restano accessibili. Quando serve una funzione di sistema che React Native non espone, si scrive un modulo nativo in Objective-C — e, quando arriverà Android, in Java — e lo si rende richiamabile da JavaScript attraverso lo stesso bridge.
L’apertura del codice non arriva da sola. Negli stessi giorni di F8 Facebook ha pubblicato ComponentKit per l’interfaccia iOS, Fresco come libreria di immagini per Android, e le utility Year Class e Connection Class per la profilazione su Android. React Native è la parte più visibile di un rilascio più ampio di strumenti per il mobile.
Limiti
A oggi, 15 aprile 2015, il rilascio pubblico riguarda solo iOS. La versione Android è data per imminente ma non c’è, quindi la condivisione di codice fra le due piattaforme non si può ancora verificare sul campo. Il progetto è giovane: i componenti esposti sono pochi, e qualunque controllo nativo non ancora coperto va scritto a mano.
Il bridge resta la cosa da tenere d’occhio. Le interfacce con pochi dati in transito ne traggono il massimo; quelle che spingono grandi volumi di eventi attraverso il confine — animazioni guidate dallo scorrimento, liste lunghissime — vanno misurate caso per caso, perché il costo di serializzazione non si toglie per costruzione. Sarà l’uso su app reali, insieme all’arrivo di Android, a dire quanto questa architettura regge fuori dalle demo.
https://code.facebook.com/posts/1014532261909640/f8-big-technology-bets-and-open-source-announcements/ https://github.com/facebook/react-native https://facebook.github.io/react-native/ https://techcrunch.com/2015/03/26/facebook-open-sources-react-native/ https://www.noze.it/insights/react-native-open-source/
Immagine di copertina: Mark Zuckerberg, in maglietta scura, parla sul palco illuminato della conferenza Facebook F8 2015 davanti a un grande schermo — foto di Maurizio Pesce, CC BY 2.0 — https://commons.wikimedia.org/wiki/File:Mark_Zuckerberg_on_stage_at_Facebook’s_F8_Developers_Conference_2015_(16934644455).jpg