UX, ATM e vestizione di bug

Qualche tempo fa ho avuto la fortuna di poter assistere a un talk di @rainwiz che mi ha un po’ liberato di alcuni pregiudizi che avevo riguardo ai miei colleghi designer, i quali si occupano solitamente di migliorare la forma dei prodotti software lasciandone pressoché immutata la sostanza. Io da parte mia l’ho sempre pensata alla Don Camillo, ovvero “una cosa è bella quando è di buona qualità e serve bene al suo scopo”, e ho sempre messo font/colori/immagini in secondo piano rispetto alla “ciccia”. Ebbene in quella lunga e interessante serata di novembre ho scoperto che gente molto in gamba, spesso ferrata in psicologia (o nel caso dello speaker antropologia), si occupa quasi interamente di raccogliere informazioni attraverso interviste e questionari cercando di alterare il meno possibile i loro oggetti di osservazione (di solito i futuri utenti dei nostri software).
Esistono UX engineers (UX sta per User eXperience) che più di abbellire la UI si preoccupano di capire come ragionano gli utenti, di sfruttare scorciatoie psicologiche per facilitarne il lavoro, di evitare tranelli mentali che potrebbero causare spiacevoli inconvenienti.

ATM, goal e dimenticanze

Vi era un tempo, nemmeno troppo lontano, in cui andando a prelevare contante la gente dimenticava la propria carta/bancomat nell’ATM. In molti si saranno chiesti il perché, visto che il processo di prelievo era perfettamente simmetrico – carta => pin => soldi => carta – finché probabilmente si sarà richiesto il parere di qualche esperto psicologo (o studente in psicologia, tanto basta), e l’arcano è stato svelato.

Sopra la sequenza originaria, sotto quella attuale

Sopra la sequenza originaria, sotto quella attuale


Il problema non era tanto nella smemoratezza degli utenti, quanto in una delle funzioni esecutive della nostra mente, e nel caso specifico in quella del mantenimento del gol/meta/obiettivo in memoria.
Il concetto è semplice: si va all’ATM con un compito (task) chiaro, il prelievo di contante, e la nostra mente focalizza l’attenzione su questo obiettivo; una volta che lo si è raggiunto l’operazione è terminata, e tutto il resto rischia di cadere nell’oblio. Guardando questo flusso dalla giusta angolazione, il ricordarsi di prendere la carta prima di andarsene sembra più un’eccezione alla regola che non il contrario. Vero che se si ha tempo e si è concentrati nello svolgimento del compito generalmente ci si ricorda, ma è proprio quando si è sovrappensiero che la mente lavora in automatico, e in queste occasioni un processo modellato non tenendo conto di questi aspetti di psicologia basilare può creare grossi problemi agli utenti, anche economici.

Restando in materia di goal un esempio diverso ma non troppo è secondo me quello dell’aperitivo al bar. Si va al bar per stare in compagnia, fare due chiacchiere e bere qualcosa, e prima o poi si paga. Gli obiettivi sono chiaramente due – lo stare in compagnia e il bere qualcosa – il pagare è soltanto un mezzo, ma dal momento che in ogni bar le regole un po’ cambiano (in alcuni si paga prima e in altri dopo, nel “nostro” capita di “segnare” e spesso il barista sa già cosa vogliamo), nella nostra mente lo schema non è ben definito, quindi questa se costretta a lavorare in automatico pensa solo a fare goal. Il tempo passa, si fa tardi e salutiamo, ecco che ci siamo dimenticati di pagare. Io da parte mia raramente mi dimentico di qualcosa, e a dispetto del detto “a pagare e a morire c’è sempre tempo” cerco sempre di pagare il prima possibile, eppure mi è capitato di essermene andato senza aver pagato, e l’ho fatto anche in posti diversi dal bar.

Sempre UX e psicologia, ma applicate alle casse automatiche invece che ai bancomat

Ieri sono andato a fare la spesa e per una volta, avendo tempo, ho provato a usare la cassa automatica. Tutto molto bello, con la doppia bilancia per evitare che la gente si “dimentichi” di passare qualcosa sullo scanner, il lettore di codici a barre fisso e manuale, il controllo umano in caso di acquisti di alcolici… riguardo a questo soggetto è doveroso aprire una parentesi, quell’uomo sembrava ad un passo dal tagliarsi le vene, credo che uno dei pochi lavori più brutti di quello di cassiera sia quello di addetto alla cassa automatica, chiusa parentesi.
Finito di passare gli articoli c’è da pagare, si preme l’apposito pulsante mentre si prende il portafogli e, guidati dalla voce che chiede l’inserimento di contanti o carta si procede con il dare in pasto i soldi alla macchina. Da un verso non li prende, dall’altro neppure, il lettore chissà perché sembra non funzionare. Eppure la voce continua a richiedere l’inserimento dei soldi…

Cassa automatica al momento del pagamento

Cassa automatica al momento del pagamento


Dopo un minuto circa passato a girare e rigirare la banconota incitato dalla solita impassibile voce decido di guardare di nuovo il monitor, distante quasi mezzo metro dal mangia soldi, e vedo che c’è scritto di selezionare il metodo di pagamento.
Lasciamo stare per un momento la mia distrazione a causa della quale ho perso di vista il monitor e non ho letto cosa dovevo fare, ignoriamo anche la voce registrata che mi richiedeva una cosa mentre il monitor me ne chiedeva un’altra, e torniamo alle funzioni esecutive. L’utilizzo della cassa automatica era per me un’operazione nuova, e l’ho svolta quindi seguendo le istruzioni e comportandomi all’incirca come fossi stato d’avanti a una cassiera (allo stesso modo ho tirato fuori la carta fedeltà a metà spesa giusto perché mi sono ricordato, forse quella vocina avrebbe dovuto dirmelo all’inizio, o forse me lo avrebbe detto alla fine, chissà…). Arrivato il momento di pagare ho tirato fuori i soldi e per la mia testa questo doveva bastare, forse sarebbe stato il caso di abilitare direttamente i vari lettori aspettando uno qualunque degli input e richiedendo istruzioni soltanto in caso di ambiguità (ad esempio sul tipo di carta). La cassiera a volte me lo domanda se voglio pagare con la carta, ma di solito il tenere in mano i contanti per lei è un messaggio abbastanza chiaro, ma non lo è stato per il software il tentativo di inserirli prima di avergli detto che lo stavo per fare. La user experience pensata dai designer è ottimale? Forse si può fare di meglio?

Di sicuro c’è che questa concezione di supermercato ai giorni nostri non ha più alcuna ragione d’essere, in futuro secondo me ci saranno supermercati molto più piccoli affiancati a grossi magazzini, le persone selezioneranno la merce da un monitor e se la ritroveranno in delle buste già pronta per essere ritirata. Oppure si prenderà all’ingresso soltanto un lettore di codici a barre e ci si muoverà per dei negozi pieni di monitor scegliendo la merce a colpi di scanner, per ritrovarsela alla fine già pronta. Forse la merce ce la consegneranno direttamente a casa. O forse non esisteranno più nemmeno i supermercati e si acquisterà tutto sul web con la possibilità di pagare un po’ di più per merce con scadenze più lontane e di meno per quelle a scadenza prossima. In questo modo si pagheranno meno stipendi per lavori avvilenti e inutili, si ridurrà il rischio di taccheggi, e soprattutto molti meno alimenti saranno buttati perché scaduti. Vedremo.
Per il momento diciamo che il lavoro di cassiera al supermercato non può e non deve sopravvivere, è disumano.

Trasformare potenziali bug in features lavorando di esperienza e fantasia

UX non è solo fare in modo che l’utente esegua il proprio compito nel modo più semplice e appagante possibile, ma anche il cercare di fornirgli a basso costo funzionalità realmente utili e ridurre il rischio di errori.
Sono buoni tutti a investire tempo e denaro per sviluppare funzionalità di un software, ma non tutti sanno riconoscere l’opportunità di sfruttare potenziali bug per arricchiere il proprio programma. Nel libro I 36 stratagemmi il quattordicesimo stratagemma consiglia di “prendere a prestito un cadavere per rifondervi lo spirito”.

Stratagemma 14 della strategia cinese: "that's a feature!"

Stratagemma 14 della strategia cinese: “that’s a feature!”


Niente meglio di un buon aneddoto per fissare il concetto, raccontato da un esperto sviluppatore di mia conoscenza. Costui doveva aggiungere un sistema di messaggistica istantanea al proprio software e, trovatosi di fronte alla possibilità di inviare messaggi a se stessi, era prossimo a togliere questa possibilità perché poteva essere interpretata come un bug. Ebbene non lo fece, ma piuttosto mascherò questo “effetto collaterale non voluto” in modo da farlo sembrare una scelta, una possibilità di dialogare con se stessi come scrivendo su un blocco note. E ai clienti l’idea piacque. Per inciso questa cosa è possibile anche sull’applicazione Messenger di Facebook, ma non su Hangout di Google.

Buoni propositi pasquali

Non solo modellando processi da automatizzare al computer bisogna tenere conto di come funziona la mente, anche nella vita di tutti i giorni conoscere qualche fondamento di psicologia non guasta e può aiutare a evitare colossali figuri di me..a. Faccio quindi voto solenne, e questo articolo ne è testimone, che quanto prima cercherò di leggere almeno un libro sull’argomento e di riflettere un po’ di più sugli aspetti psicologici del mio lavoro ma anche del mio agire. Sperando di non dimenticarmene (il goal oggi è pur sempre lo scrivere quest’articolo).

TiShadow: un hack che (il più delle volte) può far risparmiare un sacco di tempo

Lo sviluppo mobile è una rogna, perché sul mercato ci sono un’infinità di dispositivi e svariate piattaforme e ogni singolo utente si aspetta di poter usare ciascuna applicazione di cui sente parlare.
Quando uno degli obiettivi è raggiungere più pubblico possibile la strada dello sviluppo multi-piattaforma offre varie alternative, ciascuna con i suoi punti di forza e le sue debolezze. Appcelerator Titanium è una di queste.

Compilazione e deploy a ogni modifica, ovvero come girarsi i pollici per la metà del tempo

Quasi in ogni contesto di sviluppo si deve affrontare l’enorme spreco di tempo dovuto a compilazione e deploy delle proprie applicazioni su dispositivi/simulatori, e Titanium non fa eccezione. O almeno non la faceva fino a un paio di anni fa.
Nel 2012 in Australia devono essersi stancati di aspettare il compilatore, e si sono inventati un hack: TiShadow. Il nome non rende molto bene l’idea, si tratta di un infrastruttura basata su un’applicazione mobile che funge da container (di applicazioni sviluppate con Titanium), un’applicazione server che ha il compito di iniettare il nostro codice all’interno del container, e una serie di comandi per console (CLI).

Un'immagine vale più di mille parole

Un’immagine vale più di mille parole


L’utilizzo in se non è complicato, e nemmeno capirne il funzionamento, ma è uno strumento ancora non così diffuso anche perché nei primi passi si può sbattere in alcuni spigoli e rimanere scoraggiati.

Distribuzione ed esecuzione paralleli su più dispositivi

Come è facile intuire stiamo parlando di strumenti sviluppati in Javascript per il Javascript, ecco quindi che spunta fuori npm e l’installazione consiste semplicemente nell’installazione di un modulo NodeJS, e ogni passaggio richiede l’utilizzo della linea di comando.

Installazione di TiShadow

npm install -g tishadow
(per un doveroso approfondimento sui moduli NodeJS leggete qui)
Una volta installato l’apposito modulo globale tutta una serie di comandi diventano disponibili da console.

Creazione dell’applicazione TiShadow

Andiamo quindi a creare una directory per la nostra applicazione, spostiamoci al suo interno, e lanciamo il comando per la creazione dell’app:
tishadow app -d ./
Fatto questo nella directory corrente comparirà un’applicazione Titanium installabile su tutte le piattaforme e contenente i moduli più comunemente usati. Quest’applicazione deve contenere tutto il necessario per il funzionamento della nostra app, perché sarà lei che ospiterà il pacchetto della nostra applicazione, o meglio tutto il contenuto della directory /app. Come potete vedere osservando la struttura di un progetto Titanium i moduli, i plugin, e soprattutto i file tiapp.xml e il manifest sono esterni alla directory app, è importante quindi andare ad aggiungere eventuali moduli non già presenti nell’installazione di TiShadow, e andare a “completare” il tiapp.xml della nuova applicazione ombra inserendovi gli eventuali moduli aggiunti e correggendo appid, version e altre informazioni che potrebbero essere importanti per il buon funzionamento della nostra app.

Deploy dell’applicazione ombra sui dispositivi

L’applicazione “ombra” creata al passo precedente deve essere installata sui nostri dispositivi (o simulatori) in cui dobbiamo testare la nostra applicazione mobile.
Se ad esempio vogliamo provare la nostra applicazione su un simulatore di Motorola Moto X creato con Genymotion sarà sufficiente utilizzare il CLI di Titanium con il comando:
ti build -p android -T emulator --device-id "Motorola Moto X - 4.3 - API 18 - 720x1280"
Questo passo in linea di principio è sufficiente farlo una volta, o almeno solo quando facciamo modifiche “sostanziali” alla nostra applicazione (come aggiunta di moduli o upgrade dell’sdk), perché poi l’applicazione TiShadow rimarrà sul nostro dispositivo/simulatore.

L'applicazione "ombra" TiShadow sul simulatore Genymotion

L’applicazione “ombra” TiShadow sul simulatore Genymotion


L’applicazione TiShadow è disponibile per lo scaricamento anche sull’Android Market, ma se ne sconsiglia vivamente l’utilizzo in favore dell’installazione vista sopra, perché non è chiaro quale sia la sua versione e non avremo modo di mettere le mani al suo interno (ad esempio per modificare il tiapp.xml o per aggiungere moduli).
TiShadow sul market. Ora dimenticatela.

TiShadow sul market. Ora dimenticatela.

Lancio del server TiShadow e connessione dell’applicazione ombra

Una volta installata e lanciata l’applicazione “container”, ci ritroveremo di fronte a una richiesta di connessione a un server…

Quale server TiShadow ?

Quale server TiShadow ?


Facendo un rapido riavvolgimento fino all’inizio dell’articolo potete vedere che avevo nominato un’applicazione server. Questa è una delle parti fondamentali del modulo TiShadow, e per lanciarla è sufficiente digitare:
tishadow server
Si possono specificare vari parametri ma niente di fondamentale. L’applicazione server si mette in ascolto su una porta (la 3000 di default), e aspetta che delle applicazioni client TiShadow vi si connettano così da stabilire un collegamento attraverso il quale iniettare la nostra applicazione.
Inseriamo quindi l’IP della nostra macchina sulla maschera di login dell’app TiShadow e lasciamo che i due attori si connettano.
Ripetiamo questo passaggio per ogni altro dispositivo/simulatore in cui vogliamo testare la nostra applicazione.

Esecuzione della nostra applicazione

Arrivati a questo punto dobbiamo solo posizionarci nella directory della nostra applicazione e dire a TiShadow di eseguirla:
tishadow run
Per magia ci ritroveremo con la nostra applicazione distribuita su ogni dispositivo/simulatore collegato al server.
Anche questo comando dispone di vari parametri, ad esempio con tishadow @ run il deploy è automatico ad ogni salvataggio… una manciata di secondi per un deploy a caldo su dispositivi multipli.
È doveroso specificare che spesso le cose si “incastrano” e c’è da riavviare server e/o client e/o fare qualche aggiustamento, fatto sta che lo strumento è di una potenza devastante.

Unit-test con TiShadow

Ipotizziamo per un momento che chi sta leggendo sia abituato a lavorare soltanto su una piattaforma e abbia una macchina abbastanza veloce da non trarre troppo giovamento da deploy a caldo e distribuzione parallela su più dispositivi, può trarre comunque giovamento da TiShadow? Una domanda scritta in questo modo presuppone una risposta affermativa, specialmente dopo aver letto il titolo, e infatti la risposta è sì.
Ci sono un sacco di moduli e librerie per eseguire test automatici di unità in Javascript, ma farli funzionare con Titanium non è sempre così semplice. TiShadow ci aiuta perché integra al suo interno la libreria Jasmine, e una volta scritte le specifiche nella consueta forma describe-it e inserite nella directory app_main_directory/spec il gioco è fatto.

describe("Spec description", function(){
  it("Test description", function(){
    expect(true).toBe(true);
  });
});

Non serve installare moduli o includere librerie, perché è già tutto dentro TiShadow. Basta descrivere le nostre specifiche come nell’esempio sopra, inserirle in file terminanti con il suffisso “_spec.js” e includere questi file nella directory “spec”. L’esecuzione dei test consiste in due parole:
tishadow spec

Conclusioni

La lentezza delle procedure di deploy è un problema sentito, specialmente nell’ambito dello sviluppo mobile. Forse meno sentito ma non meno importante è l’argomento dei test automatici. Su Titanium entrambi i problemi sono più o meno risolti da TiShadow, un modulo ancora ignoto a molti forse anche a causa del nome enigmatico.
Speriamo che questo breve articolo serva a fare un po’ di luce sull’argomento e a dissipare le ombre che molti vedono aleggiare su Titanium.

Il passato che avanza: SVN su Eclipse

Articolo forse un po’ anacronistico, ma tutte le volte che devo collegarmi a un repository SVN con Eclipse o uno dei suoi tanti figli (come ad esempio Titanium Studio), non mi ricordo mai di preciso dove trovare l’apposito plugin.

Detto che nel 2015 è possibile e forse doveroso trasferire i propri sorgenti su un VCS distribuito in stile GIT, anziché continuare a tenerli su un sistema centralizzato, è anche vero che in alcuni casi questo passaggio non si può fare.
Di client SVN ce ne sono tanti, per Windows uno dei più diffusi è TortoiseSVN, ma parlando di plugin per Eclipse (che non ha un client SVN integrato) la strada è più o meno obbligata.

L’installazione di plugin su Eclipse

Senza andarsi a sporcare le mani con file e directory di Eclipse, ci sono due modi per installare dei plugin dall’interno di Eclipse: il menù “Install New Software” e il vicino “Eclipse Marketplace”.

Il menù help con le voci per l'installazione di plugin

Il menù help con le voci per l’installazione di plugin


Il Marketplace – presente sulle versioni standard di Eclipse – è il modo più semplice per trovare plugin sicuramente funzionanti e di buon livello, ma purtroppo non è sempre presente in Eclipse. Infatti in alcune versioni modificate (vedi Titanium Studio) questa voce di menù non c’è proprio. Se siamo in uno di questi casi o se il plugin che ci interessa non è disponibile sul Marketplace, si può ricorrere al più spartano “Install new software”.

Maschera di installazione di plugin su Titanium Studio, identica nell'Eclipse standard

Maschera di installazione di plugin su Titanium Studio, identica nell’Eclipse standard


Il funzionamento è abbastanza ovvio, su “Name” si inserisce un nome identificativo della risorsa, su “Location” l’url al quale si trova il plugin.
Una volta registrata la location, nella maschera sottostante rimane da mettere le spunte sui componenti (eventuali) che si desidera installare e confermare l’installazione.

Installazione di Polarion Subversive

Il client SVN installabile su Eclipse che la fa da padrona è il Subversive SVN. Scaricabile dal Marketplace, è però disponibile anche per l’installazione manuale.
Nella pagina qui sopra ci sono tutti i link necessari, ma per farvela più semplice le cose che dovete installare sono due:
http://download.eclipse.org/technology/subversive/2.0/update-site/ – [required] Subversive plug-in
http://community.polarion.com/projects/subversive/download/eclipse/4.0/update-site/ – [required] Subversive SVN Connectors

Le cose che dovreste avere installate a questo punto per far funzionare SVN

Le cose che dovreste avere installate a questo punto per far funzionare SVN


Il connettore da usare dipende dal server, nel dubbio installateli tutti. Si può scegliere quale utilizzare anche successivamente.
Selezione del connettore da utilizzare

Selezione del connettore da utilizzare

Primi passi con il plugin

Siamo nel 2015, GIT esiste da un pezzo, e creare nuovi repository SVN equivale a incastrarsi le palle nel cassetto. Quindi se siete arrivati in questo punto probabilmente vi interessa solo collegarvi a repository già esistenti.
Aggiungete quindi la view “SVN Repositories” da qualche parte sul vostro Eclipse (Window -> Show View -> Other -> SVN -> SVN Repositories), e registrate una “repository location”.

Maschera per la registrazione di un repository già esistente

Maschera per la registrazione di un repository già esistente


A questo punto selezionate all’interno del repository ciò che vi interessa (generalmente un progetto) e fatene il checkout.
Essendo il progetto pieno di cartelline nascoste .svn, Eclipse capisce che si tratta di un lavoro sotto SVN e nella voce di menù “Team” aggiunge tutti gli strumenti propri di SVN.
Subversive-team-menu

Per finire

Se non avete mai usato SVN e non avete ancora messo i vostri sorgenti sotto controllo di versione ignorate tutto quanto letto fin qui e studiatevi direttamente GIT.

Qualche chiarimento sui moduli NodeJS

Un tempo quando nel nostro codice c’era bisogno di qualche funzione “non innovativa” semplicemente si cercava qua e là, si copiava il file/la libreria/il pezzo di codice nel nostro programma e si andava avanti. Spesso – per mancanza di tempo o per semplice pigrizia – nemmeno si studiava bene nemmeno cosa facesse quel codice altrui: era il Cargo Cult Programming.
Con il passare degli anni in ogni settore dello sviluppo software si è cercato di standardizzare e modularizzare codice e librerie in modo da rendere la programmazione più un gioco di incastri che non un lavoro da sartoria, e ora i moduli CommonJS sono un po’ dappertutto… e il Cargo Cult Programming se possibile è anche diventato più forte.

Moduli NodeJS: installazione

Con la nascita di NodeJS e il conseguente lancio del package manager npm il mondo Javascript ha subito una brusca accelerazione dal punto di vista della riusabilità e ora è tutto un’installazione di moduli, ma c’è chi non ha capito bene come funziona. Lo so perché anch’io all’inizio installavo moduli e librerie un po’ a caso, e ancora spesso ho dei dubbi sulla correttezza di quello che sto facendo.

Installazione locale o globale?

Tanto per cominciare ci sono “due modi” di installare un modulo presente su npm: localmente o globalmente. Mentre per installare un modulo localmente (ovvero nella directory corrente da cui si esegue il comando) bisogna scrivere “npm install nome_modulo“, per installare un modulo globalmente bisogna aggiungere l’apposito parametro, facendo diventare il comando “npm install --g nome_modulo

A differenza dell’installazione locale, che come già detto installa il modulo localmente e più precisamente nella directory node_modules/nome_modulo, l’installazione globale scarica il modulo all’interno di una directory di sistema presente sul PATH delle variabili di sistema.
Se non avete cambiato le impostazioni di default di Node, su Windows la directory di installazione dei moduli globali è C:\Users\nome_utente\AppData\Roaming\npm.
Il motivo per cui i moduli globali vengono installati dove sono accessibili da console è abbastanza evidente… sono installati con questo scopo. Non solo i moduli installati globalmente sono richiamabili da console, sono richiamabili solo da console. Infatti devono essere installati globalmente i moduli che servono come “strumenti” (Bower, Grunt, Cordova, …), al contrario delle “librerie” che invece devono essere installate localmente (Underscore, Express, …).

C’è poi un terzo caso, in cui parlare di installazione è improprio: il modulo creato da noi e non presente su npm.

L’utilizzo/inclusione del modulo, ovvero la require

La require non solo rende possibile utilizzare la libreria scelta all’interno del proprio script, ma ne effettua anche il caching in modo che – se all’interno dell’applicazione si richiede nuovamente la stessa libreria – Node non ha bisogno di andarla a leggere di nuovo su filesystem.
Includere un modulo all’interno del nostro script così da poterlo usare è semplice, ma non è così scontato capire dove Node va a cercare i file quando scriviamo require('nome_modulo').
Premessa: non serve specificare l’estensione del file (.js) perché Node cerca di default i file aggiungendovi quest’estensione.

Require con specifica del path

var customModule1 = require('./custom_module1');
var customModule2 = require('../../custom_module2');
var customModule3 = require('/home/custom_module3');

Forse il caso più semplice, Node importa il modulo specificato andandolo a cercare nel percorso assoluto specificato, o in quello relativo rispetto allo script in cui è stata chiamata la require.

Require con specifica del solo nome della libreria

var http = require("http");
var _ = require("underscore");

Qui la situazione si complica.
Per prima cosa Node cerca il modulo tra quelli “core”, cioè i moduli rilasciati di default con Node (es: http, fs, path, …). Se il modulo non è tra quelli preinstallati (es: underscore) Node inizia a ricercare il modulo all’interno della prima directory node_modules che riesce a trovare partendo dalla directory corrente (quella dello script) e risalendo la gerarchia fino ad arrivare alla directory root.
C’è da dire anche che il “modulo” può essere semplicemente un file javascript nome_modulo.js ma anche una directory nome_modulo contenente un index.js piuttosto che un nome_modulo.js e tante altre risorse, compresa un’eventuale directory node_modules in cui sono contenute tutte le dipendenze del modulo.
Lo so, è un po’ un casino e forse ho sintetizzato troppo, il punto è che capirete meglio andando a scartabellare la directory node_modules globale e provando a installare qualche modulo locale qua e là vedendo come e quando Node lancia l’errore “Cannot find module ‘nome_modulo'” se la require fallisce.

Scrittura di un semplice modulo: exports

Un piccolo esempio pokeristico, sperando che conosciate questi termini. Se non li conoscete va bene uguale ma mi dispiace per voi.

var fold = function(){
  console.log("fold");
};
module.exports = fold;

Il modulo “weak” è estremamente basilare, ed esporta una sola funzione.

var bet = function(){
  console.log("bet");
};

exports.bet = bet;
exports.raise = function(){
  console.log("raise");
};
exports.when = "When I'm strong and/or in position and/or I want to convince my opponents that I'm strong";

Il modulo “strong” utilizza l’exports un po’ di più, collegandovi non una ma due funzioni, e una stringa tanto per fare mucchio. La prima funzione – bet – viene dichiarata e definita in una variabile che poi viene esportata, a differenza della seconda – raise – che viene assegnata direttamente all’omonima proprietà dell’oggetto exports. Il risultato è esattamente lo stesso.

var weak = require('./weak');
var strong = require('./strong');

weak();
strong.bet();
strong.raise();

console.log(weak);
console.log(strong);

Qui possiamo vedere che il modulo “weak” nient’altro non è che la funzione esportata, che infatti può essere richiamata direttamente. Strong è invece un oggetto Javascript contenente tre proprietà: una stringa e due funzioni – bet e raise – che in quanto tali possono essere eseguite.

Dubbi amletici: exports o module.exports?

I più attenti avranno notato una differenza tra weak.js e strong.js… e non serve nemmeno essere troppo attenti considerato che c’è scritto sul titolo. Che differenza c’è tra la variabile “exports” e la “module.exports”?
In pratica nessuna, perché exports è semplicemente un riferimento a module.exports. Si tratta di zucchero sintattico che serve a velocizzare la scrittura del modulo e a evitare che per sbaglio rendiamo la nostra vita amara andando ad assegnare qualcosa a module.exports, rompendo così l’interfaccia tra il modulo e i suoi utilizzatori.

Conclusioni

Modulare è bello, modulare è “c’è un sacco di roba gratis e si trova tutta lì”, modulare è veloce. Però è importante capire bene quali sono le regole perché altrimenti i pezzi non si incastrano e bisogna fare come gli astronauti dell’Apollo 13 con i filtri per l’anidride carbonica.
Parlando di installazioni ho omesso che quando si installa un modulo bisognerebbe anche preoccuparsi di quale versione installare, perché la pappa pronta è buona ma qualcuno potrebbe aver fatto delle modifiche alla ricetta dall’ultima volta, e potremmo ritrovarci con un’intolleranza. E poi bisogna spiegare al cliente che siamo stati sfortunati.

Fondamenti di tipografia

Il mese scorso – approfittando di un abbonamento a prezzo di favore – mi sono fatto una scorpacciata di corsi sul veramente ben fatto CodeSchool, recente piattaforma di apprendimento online orientata alle tecnologie per lo sviluppo web. Quel Code sul nome del sito dovrebbe chiarire le finalità principali del sito, ma i fondatori non hanno mancato di offrire anche qualche nozione di design, perché è noto che la stragrande maggioranza di noi programmatori non è molto sensibile a queste tematiche (per usare un eufemismo).
Ecco quindi che – consapevole della mia carenza nella capacità di abbellimento del prodotto – ho completato anche il corso Fundamentals of design. Il primo livello, che può essere svolto anche senza abbonamento, parla di tipografia. Se avete un’oretta vi consiglio di registrarvi e completarlo, e poi magari date anche una guardata al resto dell’offerta perché è veramente di alta qualità.

Grazie o non grazie

Lasciando da parte i font di tipo Script, che simulano la scrittura in corsivo e dovrebbero essere usati con parsimonia (o meglio mai… odio il corsivo), il principale carattere distintivo di un font è la presenza o meno delle “grazie”.
La differenza tra caratteri serif e sans-serif è o dovrebbe essere nota a tutti: i serif (“grazie” in italiano) sono quegli abbellimenti stilistici che alcuni caratteri (quelli appartenenti alla famiglia dei font serif) hanno nelle parti terminali delle lettere, mentre i sans-serif ne sono sprovvisti.

Font “serif”, le grazie sono evidenziate in rosso


Font “sans-serif”

Classificazioni

Qui il discorso si fa più complicato, ma conviene comunque fare un po’ di chiarezza perché per avere “armonia tipografica” è importante scegliere e combinare i font in base alle loro caratteristiche.
CodeSchool, Wikipedia e I Love Typography raggruppano i font con criteri simili ma non proprio uguali, quindi cercherò di fare una breve sintesi, di spiegare un po’ la terminologia, e poi sarà compito di ciascuno approfondire.
La fonte più interessante e completa che ho trovato in rete è questa serie di articoli:
History of typography: Humanist
History of typography: Old Style
History of typography: Transitional
A brief history of type: Modern/Didone
A brief history of type: Slab Serif/Egyptian

I love typography segue un percorso “storico” della tipografia e suggerisce una classificazione basata sul tempo: l’antico e illeggibile Blackletter, i più leggeri Humanist, e da qui il passaggio ai più recenti e “squadrati” Modern e Slab Serif passando per gli Old Style e Transitional. Tutte queste classificazioni ricadono però nella tipologia dei Serif, e a lettere il primo articolo della serie sembrerebbe che i Sans-Serif vengano dopo e facciano classificazione a parte. In realtà ciascuna di queste classificazioni è definita da particolari caratteristiche, caratteristiche che possono essere traslate anche nella “macro-classificazione” dei Sans-Serif. Ecco quindi che forse è più corretto classificare i font in modo un po’ più gerarchico:

  • Serif
    • Humanist
    • Old Style
    • Transitional
    • Modern
    • Slab Serif
  • Sans-Serif

    • Humanist
    • Transitional
    • Geometric
  • Script

Humanist e Old Style

I font Humanist sono caratterizzati dalla lettere “o” ed “e” minuscole molto inclinate, dal corpo dei caratteri minuscoli piuttosto basso, dalla poca differenza tra i tratti più sottili e quelli più spessi (caratteristica ben visibile sulle “A” maiuscole), da serif piuttosto inclinati.

Eleganza un po' retrò

Eleganza un po’ retrò


Gli Humanist di tipo serif sono i più “classici” tra i font, e sembrerebbero maggiormente indicati nei settori accademici e legali. Quelli Sans-Serif sono consigliati invece in ambiti educativi e governativi.

Transitional

Con i Transitional si fa un bel balzo in avanti rispetto agli Humanist, e in questa famiglia si possono facilmente notare il generale “raddrizzamento” dei caratteri e delle linee (vedi la “o” minuscola), il grande contrasto tra linee sottili e spesse (vedi la “M” maiuscola) e un “livellamento” dei serif.

Tratti distintivi dei font Transitional

Tratti distintivi dei font Transitional


I Transitional rappresentano un mondo moderno, e sono consigliati nel giornalismo (Serif) e nel mondo della tecnologia (Sans-Serif).

Geometric

I Geometric hanno senso soltanto nel mondo dei Sans-Serif, perché estremamente “severi” e minimali. Come si può vedere ogni qualvolta la lettera (minuscola o maiuscola) può essere approssimata a una forma geometrica (cerchio, triangolo, quadrato) questa caratteristica viene enfatizzata.

La "geometricità" dei font geometrici

La “geometricità” dei font geometrici


Consigliati nel mondo delle scienze.

Modern

Naturali successori dei (serif)font Transitional sono i Modern, caratteri in cui le linee orizzontali e verticali sono portate all’estremo, sia nelle lettere che nelle grazie, e i caratteri tendono ad essere “stirati” in verticale.

Ortogonalità portata all'estremo

Ortogonalità portata all’estremo


Sono considerati i più eleganti tra i font, e di solito utilizzati nel mondo dell’arte e della moda.

Slab Serif

Figli della rivoluzione industriale questa è la classe di font più “grassa”: i tratti eleganti e sottili dei Modern e dei Transitional lasciano il posto a linee spesse sempre e comunque, con grazie non più così “aggraziate”.

Il font dell'abbondanza

Il font dell’abbondanza


Sono considerati adatti al mondo del marketing, forse per la loro opulenza.

Come sceglierli

A dispetto del detto “Non è bello ciò che è bello ma è bello ciò che piace” da sempre gli esperti del bello ci dicono cosa va con cosa, e nel mondo della tipografia non si fa eccezione.

Bello o non bello

Bello o non bello


Gli esperti forniscono quindi delle linee guida che è meglio seguire per evitare che le diverse sezioni del nostro sito o della nostra applicazione si lascino dopo qualche mese e per scongiurare spiacevoli risatine alle spalle:

  • se non si è designer esperti meglio evitare di mescolare diverse classi di font, perché un solo font usato bene è più che sufficiente per ottenere un bel risultato in ogni prodotto
  • per diversificare lo stile dei font, se ne possono usare diversi per diversi scopi (testata, corpo, menù, …) evitare miscugli all’interno della stessa sezione
  • mai usare due font con lo stesso stile (ad esempio due diversi Humanist Serif)
  • evitare di accostare due font della stessa classe (due font Serif per esempio), meglio dei contrasti più netti
  • utilizzare due font con stile simile ma diversa classe può dare un bell’effetto (ad esempio un Humanist Serif e un Humanist Sans-Serif)

Regola aurea: armonia totale o forte contrasto, meglio evitare spiacevoli casi intermedi.

Windows, git e bash

So che il titolo può sembrare strano, ma chi come me ha un pc con Windows a casa e un Mac al lavoro a volte sente la necessità di avere una shell “un po’ più Unix-like” anche sul pc, se non altro per evitare di tradurre script .sh in .bat, operazione che ha volte può risultare ardua.
Ci sono vari progetti che permettono di portare la shell dei sistemi Linux/Mac su Windows, MinGW e Cygwin su tutti, ma tutti noi abbiamo (o dovremmo avere) già installato git, quindi perché preocuparsi di installare dell’altro.

MinGW è infatti già incluso nell’installazione di git, e sebbene quando si apre il menù contestuale su una directory quel “Git bash” vicino a “Git init” e “Git gui” possa far pensare che per cliccarlo dobbiamo avere l’intenzione di usare Git, in realtà non è così.

Tasto destro del mouse e il gioco è fatto

Tasto destro del mouse e il gioco è fatto


Git bash apre semplicemente la shell bash sulla directory scelta e da lì possiamo dimenticarci dei comandi dos e utilizzare quelli che (dovremmo) conoscere bene.
La shell bash simulata su Windows grazie a MinGW

La shell bash simulata su Windows grazie a MinGW

Non sempre gli script .sh che ci portiamo dietro dal Mac girano al primo colpo, ma di solito qualche piccolo ritocco è sufficiente:

Script .sh per utilizzare ImageMagick su Windows

Script .sh per utilizzare ImageMagick su Windows


In questo esempio il comando convert di ImageMagick (popolare utility di manipolazione immagini) dava qualche problema a causa di un’omonimia con un altro comando già presente tra le variabili di sistema. È stato sufficiente esplicitare il percorso dell’eseguibile per far funzionare tutto a dovere.

Niente di trascendentale ma è comunque un piacere evitare inutili installazioni.

A mali estremi estremi rimedi: Xcode e la visualizzazione del log sui dispositivi iOS

I neofiti dello sviluppo mobile a volte rimangono sorpresi dalla varietà e dall’alto numero di errori che si manifestano quando si va a rilasciare la propria app. Generalmente su iOS grazie all’uniformità dei dispositivi non si hanno grossi problemi, ma in certe occasioni capita comunque di imprecare a lungo.

Qualche giorno fa improvvisamente la mia applicazione ha smesso di avviarsi sul dispositivo. Sul simulatore andava tutto liscio, e i certificati sembravano tutti a posto, ma dall’oggi al domani non c’era più verso di farla avviare sull’iPad. Dopo qualche ora di maledizioni alla Apple e alla sua politica nazifascista di gestione dei certificati, ho avuto la “brillante” idea di guardare i log del dispositivo, operazione tutt’altro che difficile ma che non capita di dover fare spesso.
Ebbene leggendo il log trovai l’errore immediatamente, avevo solamente scritto male la require di un modulo CommonJS, inserendo una lettera minuscola dove andava maiuscola. Nessun problema sul simulatore ma sul dispositivo questa piccola svista mandava in crash l’interprete Javascript.
Tutto bene quel che finisce bene… e velocemente.

Per chi di voi non sapesse di cosa sto parlando, vi basti sapere che Xcode nel menù Window ha una voce Devices che permette di mettere le mani su tutti i dispositivi connessi al vostro Mac, compresi i simulatori.

I dispositivi sul menù di Xcode

I dispositivi sul menù di Xcode

Dalla finestra dei dispositivi non sono solo i log di questi ultimi ad essere accessibili, ma anche le cartelle di proprietà delle varie app (container).

Log dei dispositivi e container delle applicazioni

Log dei dispositivi e container delle applicazioni

Dulcis in fundo, se vi piace mettere le mani all’interno dei file delle applicazioni usando il Finder ma navigando nelle directory dei simulatori vi capita di perdervi tra quella ventina di identificatori alfanumerici indistinguibili, ricordate che dalla schermata dei dispositivi è anche possibile ottenere l’identificatore associato a ogni simulatore, così da andare a colpo sicuro in quel marasma di caratteri e numeri. I dispositivi virtuali si trovano tutti all’interno di /Users/username/Library/Developer/CoreSimulator/Devices, da lì in avanti ci vuole la bussola.

Concatenare stringhe in Javascript con la funzione join

La concatenazione di stringhe per molti potrà sembrare un argomento di poco conto… e infatti lo è anche per me. Ciononostante vorrei affrontare l’argomento perché c’è una tecnica che aiuta a mantenere il codice pulito ed è anche efficiente.
In Java per ottimizzare l’utilizzo delle memoria quando si lavora con molte stringhe c’è la classe StringBuilder, qui non abbiamo classi particolari ma la funzione join dell’array produce un risultato molto simile allo StringBuilder.

Vediamo prima un classico esempio di concatenazione di stringhe con carattere separatore tra una e l’altra.

var arr, i, sum, beginTime;
 
arr = new Array(100000);
for (i=arr.length-1;i>0;i--){ arr[i] = ""+i; }
 
// first
sum = "";
beginTime = +new Date();
for (i in arr){
  if (sum){ sum += ","; }
  sum += "" + arr[i];
}
console.log(new Date() - beginTime);

// second
sum = "";
beginTime = +new Date();
for (i in arr){ sum += "" + arr[i]; }
sum = sum.slice(0, sum.length - 1);
console.log(new Date() - beginTime);

// third
sum = "";
beginTime = +new Date();
sum = arr.join(",");
console.log(new Date() - beginTime);

I primi due snippet utilizzano la concatenazione classica con +, ma mentre nel primo caso il carattere separatore viene inserito con un’istruzione condizionale, nel secondo viene inserito sempre rimuovendo il carattere eccedente aggiunto in fondo. Ebbene la tecnica dello slice è sempre più prestante, e il codice più bello.
Il terzo esempio utilizza invece la funzione join degli Array, come promesso nel titolo. In questo caso il codice è estremamente più pulito, perché si prende l’array così com’è e si specifica (l’eventuale) carattere separatore. Il bello è che non si guadagna soltanto in leggibilità e manutenibilità, ma anche la velocità è notevolmente più alta, specialmente su SpiderMonkey.

In altri casi capita di dover comporre delle stringhe avendone dei pezzi, caso tipico una query sql. Lasciamo stare per il momento le sql injection supponendo che i parametri siano opportunamente parsati e la query utilizzi dei placeholder.

var sum =
  " SELECT ... " +
  " FROM ... " +
  " JOIN ... " +
  " JOIN ... " +
  " WHERE ... " +
  " ORDER BY ...";

sum = [
  " SELECT ... ",
  " FROM ... ",
  " JOIN ... ",
  " JOIN ... ",
  " WHERE ... ",
  " ORDER BY ..."
].join();

I volumi in gioco sono così insignificanti che c’è da vergognarsi a confrontarne le prestazioni, e in questo caso specifico la scelta della concatenazione tradizionale o di quella con join è più un fatto di gusti. Resta il fatto che a me la seconda forma piace di più, anche perché si ha sempre il vantaggio di poter specificare un carattere separatore da usare sempre tra un pezzo e l’altro.

Conclusioni

Inutile dilungarcisi troppo: cercate di usare sempre il join quando dovete concatenare delle stringhe contenute in un array, e se non è questo il vostro caso forse è il caso di farcelo diventare comunque, perché tutti quei + in giro per il codice non sono il massimo e ricondurre “gruppi” di stringhe ad array può essere comunque una buona idea.

Cicli in Javascript, ovvero non badate alle performance che è tempo sprecato

Qualche tempo fa avevo seguito un corso online di Javascript, recente e ben fatto, tanto per verificare che le mie conoscenze dello strumento che uso tutti i giorni fossero corrette e aggiornate. Una delle puntate riguardava le performance, e poneva particolare enfasi sull’importanza di scrivere bene i cicli per far evitare all’interprete letture inutili e ottimizzarne così le prestazioni, e con mia grande gioia ho appurato di essere allineato al “professore”. Poi però mi sono ricordato di come un mio amico molto esperto mi disse che secondo lui tutte queste considerazioni sono più dannose che inutili grazie all’efficienza degli ultimi interpreti Javascript, V8 e SpiderMonkey su tutti.

Forse qualcuno potrebbe considerare anacronistico porsi questi problemi nel 2015, specialmente parlando di un linguaggio usato generalmente ad alto livello, ma per me quando si scrive codice bisogna sempre cercare di farlo nel modo migliore, quindi ecco un semplice test.

var arr, i, sum, beginTime, iLimit;

arr = new Array(100000);
for (i=arr.length-1;i>0;i--){ arr[i] = i; }

// first
sum = 0;
beginTime = +new Date();
for (i in arr){ sum += arr[i]; }
console.log(new Date() - beginTime);

// second
sum = 0;
beginTime = +new Date();
for (i=0;i<arr.length;i++){ sum += arr[i]; }
console.log(new Date() - beginTime);

// third
sum = 0;
beginTime = +new Date();
for (i=0, iLimit=arr.length;i<iLimit;i++){ sum += arr[i]; }
console.log(new Date() - beginTime);

// fourth
sum = 0;
beginTime = +new Date();
for (i=arr.length-1;i>0;i--){ sum += arr[i]; }
console.log(new Date() - beginTime);

Sarei tentato di lasciarvi senza responso per farvi copiare e incollare questo codice sulle console di Chrome e Firefox, ma lungi da me essere crudele vi anticipo il verdetto (che potete immaginare leggendo il titolo dell’articolo): scriveteli come vi rimane più comodo.
Le due forme centrali, cioè il ciclo for normale “dall’inizio alla fine” e quello “dall’inizio alla fine con memorizzazione della dimensione”, sono su entrambe le console i più lenti. Ma mentre per il secondo esempio ce lo si poteva aspettare così non è per il terzo, che a detta del “professore” dovrebbe essere quanto meno più veloce del secondo, eppure così non è.

Forse non è corretto includere in questo test il for-in del primo esempio, perché ha una semantica e un utilizzo diversi rispetto agli altri, ma nonostante la sua maggior versatilità per V8 è proprio questo il vincitore, mentre per SpiderMonkey è il “ciclo for a rovescio” a vincere.

Conclusioni

In sostanza se non sapete dove sarà eseguito il vostro codice non avete elementi per stabilire quale forma è migliore, e anche se lo sapeste tutto sarebbe vanificato dal progresso dagli avanzatissimi algoritmi di calcolo messi in campo da Google e Mozilla. Quindi lasciate perdere e scrivete i vostri cicli come vi rimane più comodo, possibilmente a rovescio se il vostro algoritmo ve lo consente, ma evitando inutili complicanze come quella di salvarsi la dimensione dell’array… che io faccio sempre.

Modulo distinta per società di calcio dilettantistiche

Tra i miei vari passatempi c’è anche quella di dirigente tuttofare della società di calcio dilettantistica del mio paesino, che gestisco insieme ai miei amici/compaesani per i miei amici/compaesani. Al momento militiamo in terza categoria e le perdiamo quasi tutte, ma anche a questi livelli purtroppo c’è burocrazia, e in quanto “tecnico-tecnologico” del nostro gruppo di amici l’onere di migliorare questo genere di operazioni spetta a me.

Ora, ci saranno centomila modi diversi di compilare e stampare un modulo di questo tipo, ma apparentemente in rete non si riesce a trovare niente di decente. Dal momento che nel nostro mestiere la prima regola è massimizzare il lavoro non svolto, per il momento ho preso la cosa che più si somigliava a quello che ci serve e l’ho modificato un po’.

Il risultato è questo qui:

Distinta calcio a 11

In estrema sintesi è un foglio Excel contenente il modulo della distinta utilizzato comunemente nel calcio dilettantistico in cui i dati dei giocatori e dei dirigenti possono essere specificati in forma tabellare.

Prendete e fatene buon uso.

UPDATE
Bella cosa la teoria. Temevo che la mancanza di una stampante in sede avrebbe reso inutile stampare ore prima dei fogli parzialmente compilati, con il rischio di defezioni dell’ultimo minuto e la rottura di dover completare/correggere ben quattro copie (servono 4 copie della distinta, e da qui l’uso classico dei fogli autocopiativi). Ho provato quindi a fare delle versioni alternative.

La prima dovrebbe servire per chi vuole inserire tutti i giocatori in distinta e compilare poi solo le caselle dei numeri:
Versione B

La seconda comprende i 18 giocatori classici più un paio di posti non numerati per eventuali correzioni dell’ultimo minuto, ma soprattutto per ogni riga sono specificati entrambi i documenti, così da non doversi preoccupare di quale documento porterà il giocatore:
Versione C