Se siete web designer o web developer, avete sicuramente familiarità con il prototyping. Dai grezzi wireframe alla creazione di interfacce in Photoshop, i progettisti fanno la mappatura di come funzioneranno i siti prima di crearli. Negli scorsi anni, il processo di prototipazione è cambiato in maniera significativa. Con i produttori di browser che in generale sono d’accordo sugli standard web e con l’avvento di tool quali Firebug e web inspector di WebKit, possiamo a volte evitare Photoshop in toto e andare direttamente nel browser. Inoltre, i framework JavaScript come jQuery ci permettono di giocare con gli eventi del browser con poche righe di codice. Ma cosa succede se abbiamo bisogno di fare qualcosa in più? Man mano che i siti web diventano applicazioni web, abbiamo bisogno di fare dei prototipi che implementino anche le funzionalità di back-end.
Questo articolo introduce Sinatra, un cosiddetto “micro” framework web che ci aiuta nella creazione di web app reali (sebbene semplici) in modo estremamente rapido, permettendoci di fare prototipi dei flussi e dei comportamenti che vorreste integrare nel prodotto finale. Sinatra è scritto in Ruby, ma per i nostri obiettivi lo useremo come il “collante” tra il nostro HTML/CSS e le funzioni del dominio specifico di Sinatra, così non dovrete imparare più di qualche semplice metodo per ottenere “Hello world.”. In questo articolo, il nostro esempio sarà una semplicissima app per Twitter, che prende due username e dice se uno segue l’altro.
Rendere indistinti “front end” e “back end” e la soglia dell’“appness”#section1
Sebbene si parli molto di “app” ultimamente, metterei dei paletti tra sito internet ed applicazione web nel punto in cui il contributo di un singolo utente determina il corso degli eventi sullo schermo. Sulle prime, le app potrebbero sembrare semplici da prototipare come successioni di schermate, ma quando si ha effettivamente un app funzionante, saltano sempre fuori delle situazioni impredicibili. Ci potrebbero ad esempio essere diverse homepage per gli utenti loggati e per i nuovi utenti. Un utente potrebbe dover saltare ad un sito di terze parti per l’autenticazione prima di ritornarvi. Come rendereste tale esperienza il più invisibile possibile? Una feature must-have potrebbe apparire mentre voi (in qualità di first user) siete frustrati cercando di fare qualcosa. Cominciare a giocare con queste azioni in Sinatra vi permette di esplorare questi problemi fin da subito, riducendo il gap tra il back end ed il front end. Se la vostra app attinge ad API di terze parti piuttosto che da un database, il “back end” diventa essenzialmente un blocco fisso e potete effettivamente usare dei dati reali nel vostro mockup invece che fare “hard coding” (in cui è sempre presente la tentazione di creare gli scenari migliori).
Le app di Sinatra creano delle ottime proof of concept e dei Minimum Viable Products, che a volte possono perfino sbocciare in applicazioni complete. Sono fantastiche anche per abbozzare qualcosa in maniera estremamente rapida durante il notiziario o nelle situazioni virali. Passo spesso alcuni giorni su una rapida app di Sinatra per vedere se una determinata cosa può essere fatta con una certa tecnologia o se un dato concetto è valido prima di buttarmici a tempo pieno. In due parole, Sinatra è il coltellino svizzero del web designer. Non ci vuole molto per imparare ad usarlo e risulta comodo per fare prototipi di grossi progetti. Inoltre, va bene quando si ha bisogno di avere una web app funzionante in maniera rapida, senza soffermarsi troppo sul back-end.
Primi passi#section2
Per questo tutorial è necessario avere installato Ruby. Se siete su un Mac, ecco un’ottima guida di Dan Benjamin su come configurare Ruby e RubyGems per Snow Leopard. Su Windows, provate RubyInstaller e su Ubuntu Linux lanciate sudo apt-get install ruby-full
. Dovrete anche installare RubyGems, il Ruby package manager. RubyGems distribuisce Sinatra e la Twitter gem (una libreria che ci permette di lavorare con le API di Twitter). Dovremo anche usare un po’ la linea di comando, ma solo per installare le librerie e poi per avviare ed arrestare la nostra app, quindi non preoccupatevi se non sapete usare il terminale (tuttavia, se volete un corso accelerato, vi raccomando caldamente lo screencast Meet the Command Line di PeepCode). Giusto per sapere dove si trova su Mac OS X: è Terminal.app nella cartelletta Utilities all’interno di Applications. Per gli scopi di questo articolo, denoterò il prompt della linea di comando con prompt>
. Scrivete semplicemente il comando dopo il prompt e premete invio. Qualunque cosa appaia sotto a prompt>
è l’output di quel comando nel terminale.
Una volta installati Ruby e RubyGems, dovrete aprire Terminal e far partire:
prompt> sudo gem install sinatra twitter
Ora abbiamo tutte le librerie che ci servono. Una volta fatto ciò, potete chiudere Terminal.
Organizzare una app Sinatra#section3
Adesso siamo pronti per scrivere la nostra app. Ma prima, qualche parola su come funziona Sinatra. Il framework si basa sul pattern MVC, in cui un controller si interpone tra un “model” ossia un rappresentazione dei dati con cui state lavorando, e la view, che è come i dati appaiono nel front-end. Un model è solitamente un database, ma può essere qualunque fonte di dati, come una API o un input dall’utente memorizzato in un cookie. La cosa importante, tuttavia, è che non è collegato alla sua rappresentazione sullo schermo (o, nel gergo MVC, la “view”). Un controller parla sia al mode sia alla view per determinare quali dati vengono inviati e dove.
Nel contesto del prototyping, fare un mockup in HTML/CSS standard costituirebbe la V in MVC, con i dati “hardcoded” per scopi dimostrativi. Cominciando a pensare a come il model ed il controller influenzino la view vuol dire arrivare al cuore di cosa rende la vostra nuova cosa una “app”. Il vostro controller può prendere dei segnali da entrambe i lati e determinare in che modo il dato è rappresentato nella view o aggiornato nel model.
Dal momento che Sinatra è un “micro-framework,” in realtà fornisce solo la “C” e “V” in MVC. E’ agnostico riguardo a come vi portate il vostro model. I web framework che hanno molte più funzioni come Ruby on Rails forniscono tutte e tre, perfino con un pesante database layer. Dal momento che prenderemo tutti i nostri dati dalla API di Twitter, il nostro model saranno i dati che ritornerà: avremo solo bisogno di qualche metodo per richiedere i dati che vogliamo e mandarli al nostro controller.
Come funziona un controller? In Sinatra, è semplicemente una lista di verbi HTTP con istruzioni su cosa fare in risposta a questi verbi. Quando il vostro browser inoltra un comando GET
ad una app Sinatra con un certo pattern URL, quest’ultima farà qualunque cosa c’è all’interno del blocco che corrisponde a quel pattern.
Ecco un esempio dell’app Sinatra più semplice del mondo.
In testa ad ogni file della app mettiamo le seguenti due righe per far sì che Ruby sappia che si tratta di una app Sinatra:
require 'rubygems'
require 'sinatra'
Quindi, la nostra semplice app:
get '/hello' do
"Hello"
end
Tutto quello che c’è tra il do
e l’end
è quello che Sinatra eseguirà quando il browser chiederà quello specifico URL. In questo caso, se un browser naviga fino a /hello, mostrerà il testo “Hello” nel browser. Ecco un esempio un po’ più interessante:
get '/hello' do
user = params[:user]
"Hello " + user + "!"
end
In questo esempio stiamo catturando i parametri della query GET per passarli alla nostra app. Se navigate su /hello?user=Al in questa app, la pagina mostrerà “Hello Al!”
In alternativa, per URL più carini, l’esempio può essere scritto così:
get '/hello/:user' do
user = params[:user]
"Hello " + user + "!"
end
Quindi, navigare su /hello/Al vi darà lo stesso risultato. Per far partire questa app, cambiate la sua directory nel Terminal (potete chiamare la app “myapp.rb” per ora) e poi farla partire:
prompt> ruby myapp.rb
== Sinatra/1.0 has taken the stage on 4567 for development with
backup from Thin
>> Thin web server (v1.2.7 codename No Hup)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
Ora che il server locale sta andando, provatela facendo puntare il vostro browser all’indirizzo http://localhost:4567/hello/Al. Per fermare il server, premete control-C (dovrete fermare e far partire il server se apportate cambiamenti al codice).
E la View?#section4
Questo è tutto riguardo all’aggiunta di un layer di funzionalità ad un mockup statico, quindi come interpoliamo queste cose nell’effettivo HTML? Usiamo le views. Sinatra rende questa operazione molto semplice cercando i file in una cartella views all’interno della root della vostra app. In ogni blocco del verbo, si punta ad una specifica view. Ecco lo stesso esempio con una view:
get '/hello' do
@user = params[:user]
erb :hello
end
Ora se la vostra app si trova in /myapp/myapp.rb nel vostro file system, dovrete mettere la view “hello” in /myapp/views/hello.erb. Ecco a cosa assomiglia tale file:
<h1>Hello <%= @user %>!</h1>
Ci sono molte cose qui. La prima cosa che potreste notare è che mettiamo un @
prima della nostra variabile utente. Questo la fa diventare una variabile istanza. Le variabili istanza sono importanti in Ruby ma per i nostri scopi, va bene sapere solo che soltanto le variabili istanza possono essere passate alle views. Se avete alcuni dati all’interno di un “verb block” che volete mostrare in una view, memorizzateli in una variabile istanza o non faranno quel salto.
Per richiamare la nostra view, usiamo il metodo erb
. ERB sta per “embedded ruby”: è il linguaggio di template che usiamo per interpolare Ruby nel nostro HTML. Mettendo erb :hello
come ultima riga nel nostro “verb block”, diciamo a Sinatra che vogliamo usare ERB per fare il rendering di un template chiamato “hello.erb” all’interno della cartella views della nostra app. Quando facciamo ciò, saprà che deve passare tutte le variabili istanza presenti nel nostro block a quella view.
Lavorare con dati reali: la API di Twitter#section5
Come vedete, Sinatra rende estremamente semplice creare una web app, se la soglia per la “appness” è quella che può manipolare gli input dell’utente. Per renderla una app reale, abbiamo bisogno di alcuni dati con cui lavorare. Per questo, tiriamo fuori la Twitter API tramite la Twitter gem. Dopo questa parte del tutorial, avremo un’ossatura di una app di Twitter che potrete usare per crearvi un bellissimo mockup HTML/CSS.
Creiamo una nuova cartella chiamata followapp ed un file al suo interno chiamato followapp.rb. In questo file, possiamo usare le stesse istruzioni “require” di prima, ma ne aggiungeremo un’altra per includere la libreria Twitter:
require 'rubygems'
require 'twitter'
require 'sinatra'
In questa app avremo due “azioni”: una pagina index che raccoglierà gli utenti di cui vorremo controllare lo stato “follow” e una pagina dei risultati che mostreranno se l’utente A segue l’utente B.
Ecco com’è la nostra azione della index:
get '/' do
erb :index
end
Dal momento che non stiamo facendo nulla nel back end, tutto quello che dobbiamo fare è dire a Sinatra di puntare ad una certa view. In quella view avremo una form che raccoglie i dati dell’utente e li manda alla nostra altra azione. Ecco com’è il file /views/index.erb:
<h1>Enter two users</h1>
<form method="get" action="/follows">
Does <input type="text" name="user1" /> follow
<input type="text" name="user2" />? <input type="submit" value="Go" />
</form>
Come potrete immaginare, questo li invia tramite GET, creando un URL che somiglia a questo: /follows?user1=username&user2=username. Per gestirlo, creiamo un’altra azione nel nostro controller che risponde a tali parametri:
get '/follows' do
@user1 = params[:user1]
@user2 = params[:user2]
#not implemented yet
@following = is_following?(@user1, @user2)
erb :follows
end
Questa azione gestisce la risposta. Prende i due parametri che gli diamo dalla pagina index e genera una variabile chiamata @following
che non abbiamo ancora implementato.
Ti seguo se mi segui#section6
Ecco come implementiamo il core engine della app: il metodo is_following?
, che scopre se l’utente uno segue l’utente due. Twitter non rende semplice controllare esattamente se un utente ne segue un altro, ma hanno un followers endpoint nella loro API che dà come risultato una list di user ID per tutti i follower di un certo account. C’è un problemino nell’usare questo ed è che abbiamo bisogno di ottenere uno user ID dallo screen name per controllarlo nella lista. Perciò, useremo solo lo users/show endpoint. E’ semplice con la Twitter gem. Nella nostra app, ecco il metodo che scriveremo:
def twitter_id(screen_name)
Twitter.user(screen_name).id
end
Questo prende uno username e restituisce lo user ID. Così, se dovessi lanciare twitter_id("a_l")
, otterrei 7865282. Ora, abbiamo bisogno solo di un altro metodo, is_following?
, per confrontare due ID. Ecco com’è:
def is_following?(a,b)
followers = Twitter.follower_ids(twitter_id(b)).ids
followers.include?(twitter_id(a))
end
Il metodo Twitter.follower_ids
restituisce un array di user ID con i follower dello user B. Poi usiamo include?
per controllare se lo user ID dell’utente A è presente nell’array. (Per ulteriori dettagli su come funzionano include?
e gli array, guardate la Array documentation di Ruby). Quindi, con solo poche righe di codice, abbiamo adesso il kernel della nostra app. (Notate che il metodo Twitter.follower_ids
restituisce solo i primi 5000 follower dell’utente. Ci sono modi per ottenerli tutti, ma complicherebbe la app.) Questo ci riporta alla riga nella nostra action:
@following = is_following?(@user1, @user2)
Questa variabile istanza risponderà quindi true
o false
a seconda che @user1
segua @user2
. Come sarà la nostra view? (Questa è contenuta in /followapp/views/follows.erb.)
<h2><%= @user1 %> <%= @following ? "follows" : "does not follow" %>
<%= @user2 %></h2>
Ecco fatto! Questa view mostrerà “Username follows Username” o “Username does not follow Username.”

Il risultato dell’esecuzione della nuova app Twitter.
Ecco l’intera “app”:
require 'rubygems'
require 'twitter'
require 'sinatra'
def twitter_id(screen_name)
Twitter.user(screen_name).id
end
def is_following?(a,b)
followers = Twitter.follower_ids(twitter_id(b)).ids
followers.include?(twitter_id(a))
end
get '/' do
erb :index
end
get '/follows' do
@user1 = params[:user1]
@user2 = params[:user2]
@following = is_following?(@user1, @user2)
erb :follows
end
Nota: l’intero codice di questa app è disponibile su Github.
In circa 20 righe di codice abbiamo un web app funzionante che può fungere da prototipo per un progetto a cui stiamo lavorando. Dal momento che Sinatra rende così semplice costruire queste micro app, possiamo ora prototipare la funzionalità nel modo in cui eravamo abituati a prototipare le decisioni di interfaccia. Vedere le funzionalità in azione rende inoltre molto più semplice decidere se vale la pena continuare un progetto oppure no. Tutto sembra bellissimo nei comp Photoshop o perfino in HTML perfetto, ma quando si usa una app, si può veramente capire se questa è la strada giusta su cui proseguire. Con Sinatra queste decisioni possono essere prese prima piuttosto che più avanti nel corso del progetto, evitando dei dolorosi cambi di direzione.
Mostrate e raccontate#section7
Una volta che la vostra app è “up and running”, vorrete probabilmente condividerla. Ricordatevi come Sinatra parte di default a http://localhost:4567? Condividere la vostra app all’interno di una rete locale è facile come sostituire localhost con il vostro indirizzo IP interno. Solitamente, questo inizia con 10.0 o 192.168 e lo si trova nelle preferenze di rete. Quindi, per far girare la vostra app all’interno del vostro ufficio o della vostra VPN, usate http://localip:4567.
Condividere la vostra app con il mondo su Internet è un po’ più complesso, ma non molto. Il modo in assoluto più semplice per lanciare (“deploy”) la vostra app è con un servizio come Heroku o Engine Yard, che sono host web progettati specificamente per far girare le app Ruby (Rails e Sinatra) e vi metteranno la vostra app “up and running” molto rapidamente e con pochissimo sforzo. Heroku è gratis per le piccole app, rendendolo l’ideale per condividere prototipi e ha un’interfaccia molto più semplice. Engine Yard ha più opzioni, ma è abbastanza complesso e non ha piani gratuiti. Sfortunatamente, la maggior parte degli shared hosting al di fuori di questi servizi speciali non sono configurati per ospitare app Ruby, ma è possibile che abbiate esperienze diverse.
Sia che si tratti di un prototipo, di un single serving site o di qualcosa di più complesso, è sempre elettrizzante vedere anche la app più semplice in internet. Aggiungere quella “appness” porta in vita quello che prima erano solo pagine su un server.
Passi successivi#section8
C’è molto di più in Sinatra di quello che ho trattato qui. Per saperne di più, guardate queste risorse:
- La documentazione ufficiale, il Sinatra Book
- Uno screencast di Peepcode, Meet Sinatra
- Uno screencast di Pragmatic Programmers su Sinatra
Illustrazioni: {carlok}
Nessun commento
Altro da ALA
Webwaste
Uno strumento essenziale per catturare i vostri progressi lavorativi
Andiamo al cuore dell’accessibilità digitale
JavaScript Responsabile, Parte II
JavaScript Responsabile: parte prima