Prima Angular contro React, e Vue a fare da terzo incomodo. Poi React che diventa React Native. Infine Flutter come nuova alternativa allo stesso React Native. Il mondo dei framework per lo sviluppo di front end in ottica cross-platform non si ferma e ci costringe a tornare sul tema.

Allora dicevamo che la sfida fra Angular e React ci sembrava aperta ed evidenziavamo punti di forza e di debolezza dei due standard. Oggi il panorama appare molto diverso, caratterizzato da una certa crescita di Vue come terzo incomodo, ma soprattutto da una decisa spinta verso il paradigma semi-nativo in opposizione a quello ibrido. Ecco nascere il concetto di progressive web app (PWA) e l’attenzione per Ionic. Ecco, soprattutto, il grande interesse nei confronti di React Native, cui però risponde una tecnologia come Flutter.

Di seguito proviamo a fare un po’ di ordine, ben sapendo che lo scenario è in continua evoluzione e che, in ogni caso, nessuna soluzione può essere considerata migliore in assoluto. La scelta del framework o dell’SDK giusto dev’essere ponderata ogni volta in funzione dell’orizzonte progettuale, ossia del tipo di user experience che si intende produrre, delle funzionalità richieste e del profilo dell’utente atteso. Così come contano fattori di contesto quali budget economico, tempi pianificati per lo sviluppo, competenze disponibili e altro.

C’erano una volta i ‘vecchi’ framework

Tanto per cominciare ricordiamo, a favore dei meno esperti, che cos’è un framework per lo sviluppo di front end. In sostanza parliamo di librerie strutturate che contengono componenti predefiniti, ossia pezzi di software già scritti e pronti per l’uso. Generalmente il linguaggio utilizzato è JavaScript, oggi nella sua versione ES6, ma vedremo che ci sono autorevoli eccezioni. Tali librerie garantiscono la riusabilità del codice e quindi uno sviluppo più efficiente, nel rispetto di adeguati standard di sicurezza.

Si tratta di tecnologie cross-platform, nel senso che il loro output è costituito da un unico codice in grado di supportare un’esperienza di tipo browser based. La user experience è dunque indipendente dal sistema operativo sottostante. Allo stesso tempo tali tecnologie offrono un risultato tendenzialmente assimilabile a quello delle mobile app native, salvo i casi in cui siano necessarie interazioni spinte con l’hardware.

Tutti i framework sono distribuiti con licenza MIT in maniera gratuita e sono supportati da grandi organizzazioni. Alle spalle di Angular c’è Google, mentre React è nato in casa Facebook. Quanto a Vue, è stato a sua volta sviluppato da ex dipendenti di Google.

Volendo essere pignoli, dovremmo ammettere che libreria, framework e software development kit (SDK) non sono sinonimi. Vedremo più avanti che alcuni framework si caratterizzano per una maggiore semplicità e dunque possono essere definiti come vere e proprie librerie, mentre altri includono molte più cose. Il successo dello sviluppo semi-nativo, poi, ha portato con sé nuovi strumenti – come appunto React Native, Ionic o Flutter – che vanno ben al di là del concetto di framework.

Strategie client-side e server-side

Il rendering con JavaScript avviene di norma sul client (client-side). Tuttavia, i principali framework possono lavorare anche server-side. Diversi sono i modi in cui è possibile processare i JavaScript lato server. Uno dei più classici consiste nell’impiego del runtime Node.js, ma è possibile ricorrere anche ad altre tecnologie, come Java o PHP.

L’approccio client-side rende l’interfaccia utente – una volta caricata nel browser – piuttosto veloce e reattiva. A quel punto, infatti, il browser non ha bisogno di conferire con il server. Il client è autonomo, a meno che non siano necessari dati che non sono stati caricati in precedenza. Il problema è che tale livello di autonomia e di interattività con l’utente si ottiene solo dopo che il caricamento dei file JavaScript richiesti è terminato. Il che può richiedere un tempo significativo. Inoltre, dal punto di vista della sicurezza l’approccio client-side è di solito considerato relativamente fragile, dal momento che gli script sono per definizione più esposti.

Nello scenario server-side la pagina si visualizza più rapidamente, in quanto la risposta dei server al client include la UI della pagina da renderizzare. Tuttavia, la pagina ha un comportamento statico. Sul server, infatti, le routine di JavaScript (event handlers) non possono lavorare. Se stiamo realizzando un’applicazione che è per lo più statica, l’approccio di rendering lato server è di solito più facile da usare. Inoltre, Il rendering server-side può aiutare a evitare problemi di compatibilità del browser.

Da notare, inoltre, che nell’approccio server-side l’esecuzione degli script non è necessaria perché il documento sia indicizzato dai motori di ricerca. Il che comporta un ulteriore vantaggio lato SEO.

Nei due disegni qui sotto, sono rappresentati lo scenario client-side e quello server-side (fonte: Alex Grigoryan, The Benefits of Server Side Rendering Over Client Side Rendering, in Walmart Labs, 17 aprile 2017).

Rendering ‘client-side’ (fonte: Alex Grigoryan)

Rendering ‘server-side’ (fonte: Alex Grigoryan)

I virtual DOM di React e il re-rendering

Uno dei vantaggi di alcuni framework – come React, Vue e Ember – è che, grazie ai virtual DOM, essi consentono di perseguire una terza strategia, detta di re-rendering. Il codice è eseguito una prima volta lato server, senza perdite di tempo. Il browser riceve in tal modo la UI già confezionata e intanto inizia il caricamento degli script. Quando tutti gli script sono a bordo del client, questo procede al re-rendering del virtual DOM e attiva gli event handlers necessari a governare il comportamento dinamico della pagina. Ovviamente è essenziale che server e client rendano il medesimo virtual DOM.

Ricordiamo che, se in JavaScript il DOM è una rappresentazione della pagina (DOM sta per Document Object Model), il virtual DOM è una rappresentazione virtuale della struttura della pagina. Tale rappresentazione, disponibile in memoria, può essere vista come una astrazione del DOM originale, al quale è del tutto simile. Fino alla versione 0.14, rilasciata nel 2015, ReactDOM era parte di React. Dopo l’avvento di React Native, ReactDOM è diventata una libreria autonoma, contenente funzionalità usate solo per le web app.

Qui si gioca una delle differenze più significative fra React e Angular. Il virtual DOM è sempre stato uno dei punti di forza di React, in grado di rendere molto veloce il rendering delle pagine. Angular ha adottato recentemente un nuovo approccio alla compilazione, introducendo Ivy in sostituzione di View Engine. Ricordiamo inoltre che nel 2016 Angular 2+ ha rimpiazzato il “vecchio” AngularJS. A questo cambiamento è corrisposto anche il passaggio da JavaScript a TypeScript.

Incremental DOM di Angular

Ebbene, Angular Ivy utilizza Incremental DOM, una libreria specifica nata nel 2015 proprio per la creazione e l’aggiornamento di alberi DOM. Il modello si discosta in modo significativo da quello del DOM virtuale introdotto a suo tempo da React. Incremental DOM non prevede la creazione di alberi intermedi, ma l’intervento su quelli esistenti.

Questo approccio riduce in misura significativa l’allocazione della memoria. Quanto il DOM non cambia, infatti, Incremental DOM non ha bisogno di memoria per eseguire una nuova visualizzazione. È necessario allocare memoria solo quando sono aggiunti o rimossi dei nodi DOM. E la dimensione dell’allocazione è proporzionale alla dimensione della modifica del DOM.

Vue, il terzo incomodo

A contrastare Angular e React, i due contendenti nell’ambito delle tecnologie di front end di tipo cross-platform, c’è Vue. Nato nel 2013 e giunto alla versione 2.6, questo terzo framework si caratterizza per la sua semplicità e per le notevoli performance. Come React e a differenza di Angular – il quale, come detto, è passato a TypeScript nel 2016 – Vue fa uso di ES6. Tuttavia, il prodotto finale non è solo codice JavaScript. Vue lavora infatti con il concetto di single-file component: script, template e stile sono contenuti in tre sezioni separate di un unico file, con la possibilità di usare preprocessori come Jade e l’estensione di sintassi SCSS.

In definitiva, è difficile stabilire se React sia meglio di Angular, o viceversa. O se la soluzione migliore sia la terza, quella di Vue. React e Vue sono vere e proprie collezioni di librerie, mentre Angular è molto di più. React e Vue sembrano tecnologie più adatte alla realizzazione di microservizi, proprio per la loro maggiore semplicità. Angular, viceversa, si sposa bene con il concetto di single page app.

Dalle app ibride alle progressive web app

Nel frattempo – e siamo intorno al 2015 – il concetto di app ibrida comincia a essere messo in discussione. Le app ibride, embedded o remote, sono straordinarie. Esse simulano l’esperienza utente offerta dalle app native, riducendo la necessità di manutenzione dei componenti nativi. Si eseguono nel browser del terminale mobile, non hanno un identificatore univoco (URL) e garantiscono accesso alle funzioni del sistema operativo. Inoltre, grazie alle nuove versioni del CSS3 e ai framework JavaScript, consentono l’uso di nuovi modelli di design. I framework hanno inoltre consentito, negli ultimi anni, di superare quasi tutti i problemi di prestazione.

Tuttavia, le app ibride non si comportano ancora come applicazioni di prima classe. In questo senso, le progressive web app rappresentano un passo in avanti. Proprio come le applicazioni ibride, le PWA sono sviluppate e caricate come normali pagine web, ma si comportano su un dispositivo mobile in modo molto più simile alle applicazioni native. In più, sfruttano le nuove funzionalità offerte dai moderni browser, inclusi service workers e il web app manifest.

I service workers si interpongono tra la connessione di rete e il terminale che eroga il contenuto. Utilizzano i meccanismi di cache in maniera efficiente e regolano il comportamento della app quando questa è offline, evitando la generazione di errori.

E poi c’è React Native

Un ulteriore approccio è rappresentato dalle app semi-native. Si tratta di applicazioni scritte usando un unico linguaggio di programmazione, ma che sono poi personalizzate in base al codice di ogni piattaforma – Android e iOS, nello specifico – prima di essere rilasciate.

I primi framework pensati per lo sviluppo di app semi-native sono stati Appcelerator Titanium e Xamarin Monotouch. Uno produce codice in JavaScript, l’altro in .NET. Una soluzione che invece sembra appartenere al passato è quella rappresentata dalla coppia CordovaPhoneGap, su cui la stessa Spindox ha fatto diverse esperienze un po’ di anni fa.

Una filosofia non troppo diversa è alla base di React Native, di cui tanto si parla da almeno un paio d’anni. Che cos’è React Native, in sostanza? Si tratta di uno strumento che permette il rendering in codice nativo – Android e iOS – di mobile app scritte usando la libreria JavaScript di React. Le primitive di React Native creano versioni di componenti specifiche per ciascuna piattaforma. In questo modo può essere usato un unico codice di base. In altri termini, React Native è un mobile framework che compila i componenti delle applicazioni native per le diverse piattaforme partendo da JavaScript. Quindi permette di utilizzare la libreria di React – con cui non va confuso – per costruire i componenti di una mobile app.

Peraltro, non si deve pensare che lo sviluppo semi-nativo per la costruzione di applicazioni cross-platform sia possibile solo con React Native. Già dal 2013, per esempio, Ionic si proponeva come un SDK completo per lo sviluppo di applicazioni mobili ibride. All’inizio Ionic lavorava solo con Angular, mentre le nuove versioni permettono di scegliere qualsiasi framework per lo sviluppo di front end in ottica cross-platform. Non solo Angular, dunque, ma anche React o Vue. È inoltre possibile utilizzare componenti di Ionic senza alcun framework.

Flutter, la risposta di Google

Abbiamo già menzionato il concetto di PWA (progressive web app), che punta a integrare il mondo web con quello delle app native. Lanciate in occasione di Google I/O 2016, le PWA hanno incontrato un successo crescente. Ma la vera risposta di Google a React Native è Flutter. Si tratta, anche in questo caso, di un framework per lo sviluppo mobile in ottica cross-platform, basato sul linguaggio Dart. Il lancio di Flutter risale al 2017, quindi parliamo di una soluzione molto più giovane di React Native.

Il principale elemento costitutivo di un’applicazione Flutter è il widget. I widget corrispondono ai componenti di React Native. Flutter dispone con un gran numero di widget pronti all’uso, la maggior parte dei quali implementa concetti di Material Design, un insieme di regole di progettazione per le interfacce utente delle applicazioni web lanciato da Google nel 2014. Ci sono due tipi di widget: stateless e stateful. E qui ritorna l’analogia con la classe e i componenti funzionali in React. La numerosità dei widget potrebbe costituire un punto di forza di Flutter.

React Native e Flutter: proviamo un confronto

La ricchezza di widget, in effetti, pone Flutter in condizione di garantire ottimi risultati in termini di look & feel della UI. Tuttavia, React Native sembra vincente quanto a capacità di replicare un’esperienza nativa. Flutter è meno raccomandabile quando l’applicazione deve avere un design con caratteristiche specifiche con riferimento alla piattaforma, oppure quando richiede interazioni multiple con il sistema operativo, o ancora librerie native poco conosciute. React Native è la soluzione migliore anche nei casi in cui è previsto un uso significativo dell’hardware del telefono da parte dell’applicazione (ad esempio, per riprodurre musica o scattare fotografie).

C’è poi la questione delle performance. Per valutare le prestazioni dei due contendenti, occorre tenere presente l’approccio di Flutter è molto diverso da quello di React Native. Flutter è compilato usando la libreria C/C++ per avvicinarsi il più possibile al linguaggio macchina e quindi offrire migliori prestazioni native. Inoltre, la compilazione non si limita ai componenti dell’interfaccia utente, ma a tutta l’applicazione.

L’approccio di React Native è diverso da quello di Flutter. L’applicazione non è interamente compilata in C/C++ o in un linguaggio nativo. I componenti dell’interfaccia utente sono compilati con i loro equivalenti nativi, mentre il JavaScript funziona in un thread separato e comunica con i moduli nativi per qualsiasi azione necessaria attraverso un bridge. Questo permette a React Native di essere molto più veloce delle alternative ibride come Ionic o Cordova, ma non rispetto a Flutter che è un passo più vicino alle applicazioni native.

Flutter è un framework molto ben documentato. Certo, nel momento in cui scriviamo queste righe, l’ecosistema di Flutter è senz’altro più modesto rispetto a quello di React Native. Tuttavia, la velocità con cui vengono rilasciati nuovi pacchetti è impressionante, per cui il gap attuale potrebbe essere ben presto colmato.

Insomma, tutto lascia pensare che prima o poi dovremo provvedere a un nuovo aggiornamento di questo post. Come si dice in questi casi, stay tuned.

2 COMMENTS

  1. […] [Aggiornamento: a due anni di distanza dalla pubblicazione di questo post, lo scenario dei cross-platform framework è profondamente murato. Alle librerie JavaScript si sono affiancate tecnologie che permettono lo sviluppo di app semi-native. Per un quadro più aggiornato, vedete il nostro post React Native e Flutter: così evolve il mondo dei cross-platform framework] […]

Comments are closed.