Progettare Web App Offline-first

Quando si tratta di creare delle app, spesso supponiamo che i nostri utenti siano molto simili a noi. Ce li immaginiamo con i device più recenti, con software sempre aggiornato e con le connessioni più rapide. Nonostante noi manteniamo un autentico zoo di vecchi dispositivi e vecchi browser per i test, passiamo la maggior parte del tempo a sviluppare dal comfort dei nostri device desktop moderni e sempre connessi.

L’articolo prosegue sotto

Per noi, una connessione che salta o un servizio lento è un problema temporaneo che scaturisce in niente di più di un semplice messaggio d’errore. Da questa prospettiva, c’è la tentazione di pensare alla connettività, al mobile o ad altro come a qualcosa che si risolverà da sé nel tempo, man mano che aumentiamo la copertura di rete e acquistiamo servizi più veloci. E questo funziona, fintanto che i nostri utenti rimangono sopra al livello del suolo in grandi città, ben sviluppate ma non troppo affollate.

Ma cosa succede una volta che scendono nella metropolitana, quando si imbarcano su un aereo, si spostano sulla terraferma o vanno in campagna? Oppure quando sono nell’angolo sbagliato della stanza o semplicemente si trovano in mezzo a una grande folla? Le app experience che creiamo così attentamente diventano fonte di frustrazione, perché facciamo completo affidamento su quel collegamento effimero verso i server.

Questa dipendenza ignora una verità fondamentale: essere offline succede. Se usate un dispositivo mobile, a un certo punto vi troverete offline. Comunque, va bene, ci sono dei modi per gestire questa situazione.

Facciamo il punto della situazione#section1

Una volta le web app erano completamente dipendenti dal server: faceva tutto il lavoro e il client mostrava semplicemente il risultato. Ogni interruzione della connessione era un problema enorme: una volta offline, non si poteva usare l’app.

Quel problema è parzialmente risolto con dei client più capaci, in cui la maggior parte della logica dell’applicazione gira nel browser, come ad esempio Google Docs. Ma, per un’appropriata esperienza offline-first, sarebbe il caso di memorizzare i dati nel front end e dovreste sincronizzarli con i dati memorizzati sul server. Fortunatamente, i database in-browser stanno maturando e c’è un numero crescente di soluzioni per gestirli, come derby.js, Lawnchair, Hoodie, Firebase, remotestorage.io, Sencha touch e altri, quindi risolvere gli aspetti tecnici sta diventando più semplici.

Ma abbiamo un problema più grosso e più strano da gestire: progettare app e relative interfacce per una connessione intermittente porta ad un’abbondanza di scenari e problemi.

Ovviamente, ci sono alcuni precedenti di UX offline-first e uno di questi è particolarmente diffuso: l’inbox e l’outbox dell’email. Le email finiscono nella outbox, anche quando si è offline. Una volta che si ritorna online, vengono spedite. È semplice, discreto e funziona.

Per le email in arrivo, l’esperienza è altrettanto delicata: una volta che vi ricollegate, le nuove email provenienti dal server appaiono in cima alla inbox. Nel frattempo, avete una copia locale più o meno completa di tutte le email fino a quel punto, così da non essere bloccati in un’app vuota. Tutti e tre gli scenari (non funziona il “client push”, il “client pull/server push” non funziona, non c’è disponibilità dei dati locali quando offline) sono ben gestiti.

Le email risultano essere semplici. Sono non editabili, facilmente elencabili, basate sul testo e “conflict-free”. La nozione di averne delle copie locali è già ben salda tra gli utilizzatori di email. Ma ci sono moltissime altre possibilità. Come gestiamo questi scenari, ad esempio, in una app di disegno collaborativo? Cosa succede se abbiamo da gestire oggetti che non sono immutabili come le email, ma marker delle mappe con degli attributi che cambiano, tracce midi, problemi, task o azioni? Il browser è il nuovo ambiente di runtime dell’applicazione e se prendiamo in considerazione la legge di Atwood (“Ogni applicazione che può essere scritta in JavaScript alla fine verrà scritta in JavaScript”), quali altre cose mai sentite prima faremo nel browser in un paio d’anni? Vogliamo ancora trattare l’offline come un caso limite e ricorrere alle feature che non funzionano, ai template così fastidiosamente vuoti e ai messaggi di errore da panico?

L’esperienza dell’utilizzo di un sito web o di un’app quando si è offline dovrebbe essere migliore, meno frustrante e che dia più possibilità. Abbiamo bisogno dell’equivalente UX del responsive web design: un robusto catalogo di guide e pattern per il mondo disconnesso del multi-device.

Il ciclo di vita della connettività#section2

La maggior parte delle web app ha due punti di fallimento correlati alla connettività: “client push” e “client pull/server push”. A seconda di quello che fa l’app, dovrete:

  • comunicare o nascondere esplicitamente lo stato della connessione e i suoi cambiamenti (ad esempio, un client per la chat informerà gli utenti che qualsiasi nuovo messaggio inserito non verrà mandato subito);
  • abilitare feature di creazione ed editing lato client anche quando si è offline e rassicurare gli utenti che i loro dati sono al sicuro e alla fine verranno inviati al server (pensate ad un’app di condivisione foto che vi permette di fare una foto e di pubblicarla in qualsiasi circostanza);
  • disabilitare, modificare o eventualmente anche nascondere delle feature che non possono funzionare offline, invece di lasciare che gli utenti provino ad utilizzare senza riuscirci (immaginativi un pulsante “invia” che sa quando cambiare in un pulsante “invia più tardi, quando sei online”).

Altre questioni si sollevano quando cambia lo stato della connessione durante l’uso. Ad esempio, il server vuole fare push di un cambio all’oggetto o alla vista che l’utente sta attualmente guardando, o addirittura modificando, questo richiederebbe che voi:

  • notificaste l’utente dei nuovi dati, potenzialmente in conflitto, che sono a disposizione, e
  • diate all’utente uno strumento di risoluzione del conflitto piacevole, se necessario.

Diamo un’occhiata a degli esempi presi dal mondo reale.

Scenari di connessione problematica#section3

Perdita di dati locali#section4

Lavorare offline con Google Docs in un browser diverso da Chrome può essere piuttosto frustrante: non si può modificare il proprio documento e, sebbene leggerlo sia ancora possibile, copiarne alcune parti non lo è. Non si può fare nulla con il proprio documento di testo o foglio di calcolo, nemmeno copiarlo in un altro programma per continuare a lavorarci da lì. E tuttavia, si tratta già di un miglioramento rispetto alle versioni passate, in cui un grande overlay vi avrebbe avvisato dello stato offline e vi avrebbe impedito perfino di vedere il vostro lavoro.

Questa è una circostanza comune sia nelle app native che in quelle web: i dati a cui avete appena avuto accesso diventano d’un tratto non disponibili quando si perde la connessione. Se possibile, le app dovrebbero mantenere il loro stato e rendere disponibili i propri dati, anche se non possono essere modificati. Questo richiede mantenere dei dati locali a cui ricorrere se il server non può essere raggiunto, così che gli utenti non vengano mai bloccati da una app vuota.

Trattare l’offline come un errore#section5

Smettetela di trattare l’assenza di connettività come un errore. La vostra app dovrebbe essere in grado di gestire le disconnessioni e di continuare con l’attività quanto più “elegantemente” possibile. Non mostrate schermate che non potete riempire con i dati e assicuratevi che i messaggi d’errore abbiano il giusto tono. Prendete Instagram: quando una persona non può postare una foto, Instragram lo chiama fallimento: invece di rassicurare l’utente che l’immagine non è persa, semplicemente la pubblicherà più tardi. Nessun problema. Potreste addirittura voler riformulare la vostra interfaccia a seconda dello stato di connessione dell’app, ad esempio potreste cambiare “salva” con “salva localmente”.

A volte potreste aver bisogno di bloccare completamente delle intere feature, ma molto più spesso non ne avrete bisogno. Per esempio:

  • Se non potete aggiornare un feed, mostrate il vecchio feed e un messaggio corrispondente. Non buttate via i vecchi dati, per poi cercare di caricare i nuovi dati, fallire ed avere una schermata vuota e inutile.
  • Se la vostra app permette agli utenti di creare dei dati localmente, lasciateglielo fare e informateli che saranno salvati e inviati in un secondo momento. Facoltativamente, avvisateli per avere una conferma prima di mandarli. Di nuovo, mi viene in mente Instagram: sa dove era stata fatta una foto, ma, quando è offline, non può chiedere a Foursquare come si chiama quel posto. Tuttavia, Instragram potrebbe chiedere agli utenti di ritornare ad una foto e di scegliere il posto su Foursquare una volta che ritornano online.

Gestire i conflitti#section6

Se la vostra app offre l’editing collaborativo o delle altre forme di uso simultaneo su device multipli, probabilmente ad un certo punto dovrete creare delle versioni in conflitto degli oggetti. Non possiamo impedirlo, ma possiamo fornire delle UI per la risoluzione dei conflitti facilmente utilizzabili dalle persone che non sanno nemmeno cosa sia un conflitto di sincronizzazione.

Prendete Evernote, il cui lavoro è basato principalmente sulla sincronizzazione delle note: i conflitti sono risolti semplicemente concatenando entrambe le versioni della nota. Su qualunque cosa sia più lunga di un paio di righe, questo richiede una quantità eccessiva di sforzo cognitivo e di editing successivo.

Draft, d’altro canto, è riuscita a rendere semplice e bella la risoluzione dei conflitti tra collaboratori: mostra entrambe le versioni con le loro differenze in tre colonne separate e ciascuna differenza ha un pulsante “accetta” e uno “ignora”. Una risoluzione dei conflitti intuitiva e visualmente bella, almeno per il testo, è sicuramente possibile.

Non sempre è necessaria una risoluzione cambiamento per cambiamento. In molti casi si ha solo bisogno di fornire una bella interfaccia per sottolineare le differenze e permettere all’utente di scegliere quale versione vince in uno specifico conflitto.

Comunque, ci sono altri tipi di conflitti che ci attendono e molti di questi non saranno basati sul testo: marcatori delle posizioni sulle mappe fuori posto, colori dei grafici a barre, linee in un disegno e un’infinità di altre cose a cui non abbiamo ancora nemmeno pensato.

Ma non tutti i problemi tecnici hanno bisogno di soluzioni tecniche. Prendiamo ad esempio due camerieri con dei dispositivi wireless per prendere gli ordini in un grande ristorante disposto su più piani. Uno è connesso al server del ristorante, l’altro è all’ultimo piano, dove la connessione manca temporaneamente. Entrambe stanno servendo dei tavoli che hanno ordinato la stessa bottiglia di un raro e costoso vino. Il dispositivo del cameriere offline non può sapere del conflitto. Quello che può fare, però, è essere cosciente del rischio di conflitto (poco magazzino, il suo stato offline) e suggerire al cameriere di dare una risposta appropriata al tavolo (“Ottima scelta. Verifico che ce ne sia ancora.”).

Anticipare i bisogni degli utenti#section7

In alcuni casi, le app possono fare delle azioni preventive a basso overhead per dare agli utenti una migliore esperienza in un secondo momento. Quando Google Maps capisce che sono su una rete wifi in un Paese diverso dal mio solito, potrebbe rapidamente mettere in cache quello che mi circonda, perché c’è una forte probabilità che più tardi sarò offline o starò usando il roaming.

In molti casi, comunque, il contenuto è troppo grande per essere messo in cache preventivamente: per esempio, un video da un sito di news. In questi casi, gli utenti devono prendere l’esplicita decisione di sincronizzare localmente, il che richiede il download del video sul loro device e la sua visione in un’applicazione diversa. Qualunque contesto avesse quel video online, come le informazioni collegate o un thread di commenti rilevanti, è ora perso, così come lo è l’opportunità per gli utenti stessi di commentare.

Refresh dei dati cronologici#section8

Tutti questi sono esempi di “client push”, ma c’è anche l’aspetto del “server push”: cosa possiamo fare quando il server aggiorna la vista attiva dell’utente e manda i dati che non possono essere opportunamente aggiunti in cima alla lista? I dati cronologici causano spesso questo problema.

Per esempio, se usate iMessage su vari device, i messaggi a volte vengono mostrati senza un ordine cronologico durante la sincronizzazione. iMessage potrebbe rimetterli nell’ordine corretto (hanno un timestamp, dopo tutto), ma invece li mostra nell’ordine in cui sono arrivati sul device. Questo li rende molto evidenti ma anche estremamente disordinati.

Immaginate il modo più intuitivo per fare questa cosa: i messaggi vengono sempre mostrati in ordine cronologico, indipendentemente da quando arrivano. Sulle prime sembra ragionevole, ma significa che potreste dover scorrere indietro nel tempo per leggere un messaggio che è appena arrivato perché era stato mandato in risposta ad uno molto più vecchio. Peggio ancora, potreste non notarlo nemmeno perché si è palesato in un posto in cui probabilmente non state guardando.

Se mostrate i dati in ordine cronologico e la sequenza dei dati stessi ha senso, come in una chat (a differenza dell’email che può essere a thread), le capacità offline pongono un problema: i dati trasmessi più di recente non sono necessariamente i più nuovi e potrebbero pertanto apparire in posti in cui gli utenti non se li aspettano. Potreste mantenere il contesto e la sequenza, ma la vostra interfaccia ha anche bisogno di far sapere agli utenti la collocazione temporale del nuovo contenuto.

Preparare diversi tipi di dati#section9

Molti di questi esempi sono basati sul testo e anche se non lo sono (come i segnaposto su una mappa), alcuni di questi potrebbero plausibilmente avere un aiuto basato sul testo (come una lista di segnaposto della mappa vicini alla mappa), che possono semplificare gli aggiornamenti e le notifiche collegate alla sincronizzazione.

Tuttavia, sappiamo che la quantità, la varietà e la complessità delle applicazioni web continuerà ad aumentare così come i tipi di dati che saranno gestiti dai loro utenti. Alcune saranno collaborative, la maggior parte sarà utilizzabile su più device e molte introdurranno nuove ed emozionanti questioni legate alla sincronizzazione. Ha quindi senso studiare queste problematiche e sviluppare un vocabolario comune per gli scenari offline e le loro soluzioni.

Offliners Anonymous#section10

Quando abbiamo cominciato a chiedere di questi problemi agli sviluppatori di tutto il mondo, siamo rimasti sorpresi dal quante persone si sono improvvisamente aperte, raccontando le loro storie di sofferenza offline, realizzando che avevano avuto problemi simili in passato ma non ne avevano mai parlato gli uni con gli altri. La maggior parte ha combattuto in solitaria, hanno rinunciato o hanno rimandato ma tutti avevano segretamente desiderato che ci fosse un qualche luogo in cui chiedere consigli per le app offline.

Non dobbiamo rimanere anonimi, però. Possiamo leggere l’appello di John Allsopp di 13 anni fa all’adozione del web come medium fluido pieno di incognite e di “accettare gli alti e i bassi delle cose”. Oggi, sappiamo che ciò si estende oltre le dimensioni dei monitor e l’aspect ratio, il supporto delle feature e tutte le implementazioni dei rendering engines e rimane vero anche per le connessioni del nostro lavoro allo stesso web.

In questa realtà ancora più fluida e in qualche modo scoraggiante, abbiamo bisogno di aiuto a vicenda. Dovremmo assicurarci che noi, e quelli che verranno dopo di noi, saremo ben equipaggiati con degli strumenti e dei pattern affidabili per le incertezze di un mondo mobile in espansione, sia per il bene dei nostri utenti sia per il nostro. Il web development è già abbastanza complicato senza perdere ulteriore tempo a reinventare la ruota.

Per aiutarci gli uni con gli altri e per aiutare le future generazioni di designer, developer e user interface expert, vi invitiamo ad unirvi alla discussione su offlinefirst.org. Il nostro obiettivo finale è quello di creare un manuale offline che includa dei pattern UX e degli anti-patter, delle opzioni tecnologiche e la ricerca sui modelli mentali dell’utente, creando un repository di conoscenza a cui attingere e a cui contribuire, così che i nostri sforzi e le nostre esperienze collettive non vadano perse.

Per ora, abbiamo bisogno di sentire la vostra voce: quali sono le vostre esperienze in questo campo, la vostra conoscenza dei tool, i vostri “tips and tricks” ma anche le vostre sfide. Risolverli non sarà facile, ma migliorerà l’esperienza dei nostri utenti, ovunque e in qualsiasi momento abbiano bisogno dei nostri servizi. Non è questo il motivo per cui siamo qui?

Illustrazioni: {carlok}

Sull’autore

Alex Feyerke

Alex Feyerke lavora come freelance web developer e consulente a Berlino. Pensa che creare il web sia ancora troppo difficile, per cui fa parte di un team che sta lavorando a Hoodie, una libreria open source che permetta alle persone di creare delle offline-first web app complete in maniera più semplice, senza doversi preoccupare del backend. Alex aiuta anche ad organizzare up.front, il front-end usergroup di Berlino. Quando non lavora, esce a fare rock climbing, va in bicicletta o suona la chitarra. Lo potete contattare su Twitter.

Nessun commento

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Altro da ALA

Webwaste

In questo estratto da World Wide Waste, Gerry McGovern esamina l'impatto ambientale di siti web pieni zeppi di asset inutili. Digital is physical. Sembra economico e gratis ma non lo è: ci costa la Terra.
Industry