Mondi su mondi, sistemi di sistemi.

Git per il controllo di qualità

Wednesday, June 8th, 2011

Dopo aver par­lato dell’uso dei fil­tri con Git, penso sia una buona idea descri­vere gli usi degli hook in pre com­mit, ad esem­pio, per fare dei con­trolli pre­ven­tivi di qualità.

JavaScript non è cat­tivo, sono i bro­w­ser che lo dipin­gono così

Chiunque abbia un po’ di dime­sti­chezza con JavaScript se che ci sono delle dif­fe­renze fra le varie imple­men­ta­zioni dei bro­w­ser che pos­sono dare pro­blemi, anche molto gravi1 , a par­tire da un codice appa­ren­te­mente senza difetti.

Un caso clas­sico è l’uso della vir­gola dopo l’ultimo ele­mento di una col­le­zione: lo stan­dard lo proi­bi­sce ma quasi tutti i bro­w­ser lo inter­pre­tano senza pro­blemi. La frase “quasi tutti i bro­w­ser” di solito signi­fica “tutti tranne Explorer” ed è così anche in que­sto caso ma a parti inver­tite. Qui è Explorer che applica alla let­tera le spe­ci­fi­che inter­rom­pendo il par­sing e lasciando gli utenti a piedi2.

Un altro caso clas­sico, que­sta volta appli­ca­bile a tutti i bro­w­ser, è l’uso di varia­bili non dichia­rate. In que­sto caso la cosa è più sub­dola per­ché non si tratta di un errore dalle con­se­guenze vistose, ma spe­ci­fico per qual­che bro­w­ser, bensì di una cosa per­fet­ta­mente legale che può cau­sare pro­blemi solo in certe con­di­zioni. Neanche que­sta è una bella prospettiva!

Insomma, è neces­sa­rio un qual­che stru­mento che ci per­metta di con­trol­lare la qua­lità del codice che scri­viamo prima che venga man­dato nella repo.

JSLint e JSHint

Per con­trol­lare la qua­lità di JavaScript cono­sco due stru­menti: JSLint e JSHint.

Il primo è quello più famoso, è in cir­co­la­zione da molto e fa un lavoro egre­gio nel segna­lare una serie ster­mi­nata di pos­si­bili problemi.

Il secondo è una deri­va­zione di JSLint, creata con l’intenzione di dare uno stru­mento un po’ più adat­ta­bile alle con­ven­zioni usate in un certo progetto.

Ho scelto JSHint pro­prio per que­sta ragione per­ché negli ultimi tempi mi sono abi­tuato a scri­vere le vir­gole prima dell’argomento suc­ces­sivo3:

var items = [
    'a'
    , 'b'
    , 'c'
];


Il pro­blema è che JSLint non ne vuol sapere di con­si­de­rarlo valido.

Come invo­care i controlli

Il pro­blema con entrambi que­sti stru­menti è che sono scritti essi stessi in JavaScript e quindi, visto che dob­biamo invo­care i con­trolli da Git, ci serve un inter­prete al di fuori del browser.

Per fare que­sto, l’avrete già capito, pos­siamo usare Node.js, che pos­siamo instal­lare con MacPorts o Homebrew o a mano; poi ci serve npm per instal­lare i moduli di Node.js, in par­ti­co­lare node-jshint, che con­sente di usare JSHint con Node.js.

Node.js ed npm sono molto sem­plici da instal­lare. Per quanto riguarda JSHint biso­gna solo avere l’accortezza di instal­larlo nella direc­tory dei moduli con­di­visa, defi­nita da npm come instal­la­zione glo­bale.

Una volta instal­lato il tutto ci serve un script di shell che invo­che­remo dall’hook di pre-commit di git. Questo script ha il solo com­pito di leg­gere l’output di JSHint ed emet­tere l’eventuale segnale d’errore, visto che la uti­lità di suo non lo fa anche se ci sono pro­blemi. Limitandoci al minimo indi­spen­sa­bile:

#!/bin/sh
#
# Verifica la conformità dei file js alle linee guida stabilite.

RESULT=$(node-hint public/scripts/*.js)

if [ "$RESULT" != 'Lint Free!' ] ; then
    echo "$RESULT"
    exit 1
fi

Lo script appena mostrato va messo in .git/hooks/pre-commit.

Altre pos­si­bi­lità

In que­sto caso spe­ci­fico, ovvero, quello del con­trollo dei file JavaScript ci sono altre pos­si­bi­lità. Per TextMate ci sono un paio di bund­les: js-tools e javascript-tools che fanno que­sto e molto altro; per Emacs la situa­zione è meno strut­tu­rata e, come sem­pre, biso­gna arra­bat­tarsi per adat­tare le varie info che si tro­vano in rete alla pro­pria situa­zione; per ora ne fac­cio tran­quil­la­mente a meno.

  1. Quanto gravi? Il caso descritto più avanti, ovvero, la pre­senza di una vir­gola in coda ad un oggetto let­te­rale, ha cau­sato un’interruzione di quasi un giorno del sito di Lifehacker, all’inizio di Febbraio.

    In que­sto caso va notato che il pro­blema è stato esa­cer­bato dall’eccessiva dipen­denza da JavaScript per costruire la pagina, un anti-pattern che è cir­co­lato molto negli ultimi mesi. L’abuso dello scrip­ting per com­porre il con­te­nuto in pagina ha tante forme ma quella più cono­sciuta, usata appunto anche da Lifehacker, è il cosid­detto hash­bang pat­tern.

    Mi sem­bra un caso da manuale di inver­sione dei fini: Google intro­duce l’hashbang per poter indi­ciz­zare anche le pagine con con­te­nuti dina­mici, met­tendo una toppa ai siti costruiti senza tenere in con­si­de­ra­zione il pro­gres­sive enhan­ce­ment; gli svi­lup­pa­tori pren­dono que­sto rime­dio e lo usano come base di par­tenza su cui costruire l’architettura dei link di un sito, com­pro­met­ten­done la robu­stezza.

  2. Sto sem­pli­fi­cando sel­vag­gia­mente per­ché il punto del post non riguarda le spe­ci­fi­che di JavaScript e le sue imple­men­ta­zioni. In par­ti­co­lare non tengo conto né delle ver­sioni dei bro­w­ser né di quelle dello stan­dard.
  3. Quando ho visto que­sta con­ven­zione per la prima volta l’ho tro­vata biz­zarra, tut­ta­via mi sem­bra che renda il codice più facil­mente mani­po­la­bile per­ché la vir­gola serve a sepa­rare l’elemento suc­ces­sivo e quindi ha senso che viag­gino insieme.

Usare CloudKit con SproutCore

Wednesday, April 28th, 2010

Dopo aver intro­dotto CloudKit, vediamo come usarlo con SproutCore, con­fi­gu­ran­dolo come bac­kend per il tuto­rial al posto dei più clas­sici PHP, Rails, Django e com­pa­gnia bella.

Il tuto­rial con­si­ste nel creare una todo list, i cui record stanno sotto <app>/tasks. Dato che SproutCore e CloudKit seguono a grandi linee gli stessi prin­cipi REST, i punti su cui inter­ve­nire non sono molti: più che altro si tratta di fare in modo che ven­gano usati cor­ret­ta­mente gli etag.

Fetch dei record

Se chie­diamo /tasks CloudKit non resti­tui­sce i dati dei record ma solo i loro link e alcuni dati descrit­tivi come il numero dei record e l’offset1. In que­sto tuto­rial, però, faremo in modo che resti­tui­sca tutti i dati in un colpo solo. Quindi, al posto di girare sem­pli­ce­mente la richie­sta, faremo un GET verso /tasks/_resolved (in gras­setto le parti modi­fi­cate rispetto al tutorial):


fetch: function(store, query) {

  if (query === Todos.TASKS_QUERY) {
    SC.Request.getUrl('/tasks/_resolved').json()
      .notify(this, 'didFetchTasks', store, query)
      .send();
    return YES;
  }

  return NO;
},

otte­nendo una rispo­sta simile a questa:


{
    "documents": [{
        "document": "{
             \"campo\": \"valore\",
             ...
        }",
        "etag": "3b990fe0-2913-012d-e490-0019e33a5348",
        "uri": "/tasks/3",
        "last_modified": "Tue, 13 Apr 2010 10:14:13 GMT",
    },
    ...],
   "offset": 0,
   "total": 3
}

La nostra data source sarà sem­pli­ce­mente quello di spac­chet­tare documents che, ragioni ignote, tratta ogni docu­mento come una stringa e non un oggetto JSON, aggiun­gendo con­tem­po­ra­nea­mente l’etag che verrà usato nelle ope­ra­zioni di modifica:


didFetchTasks: function(response, store, query) {
    var records = [];
    response.get('body').documents.forEach(function(item, index, documents) {
    var record = SC.json.decode(item.document);
    records[index] = {
        "guid": item.uri,
    	"description": record.description,
    	"isDone": record.isDone,
	"etag": item.etag
    }
}, this);
if (SC.ok(response)) {
    store.loadRecords(Todos.Task, records);
    store.dataSourceDidFetchQuery(query);
  } else store.dataSourceDidErrorQuery(query, response);
},

Inserimento dei record

Nella crea­zione dei record SproutCore ese­gue subito il POST con i dati, lasciando a un dele­gato il com­pito di aggior­nare il dato store. Anche in que­sto caso dovremo aggiun­gere l’etag:

…
var record = store.readDataHash(storeKey);
record.etag = response.get('body').etag;
store.dataSourceDidComplete(storeKey, record, url);
…

Aggiornamento dei record

Adesso pos­siamo sfrut­tare gli etag sal­vati prima per impo­stare il valore dell’header If-Match:

updateRecord: function(store, storeKey) {
  if (SC.kindOf(store.recordTypeFor(storeKey), Todos.Task)) {
    var record = store.readDataHash(storeKey);
    SC.Request.putUrl(store.idFor(storeKey)).json()
      .header('If-Match', record.etag)
      .notify(this, this.didUpdateTask, store, storeKey)
      .send(record);
    return YES;

  } else return NO ;
},

Lo stesso vale per la can­cel­la­zione:

destroyRecord: function(store, storeKey) {
  if (SC.kindOf(store.recordTypeFor(storeKey), Todos.Task)) {
    SC.Request.deleteUrl(store.idFor(storeKey)).json()
      .header('If-Match', store.readDataHash(storeKey).etag)
      .notify(this, this.didDestroyTask, store, storeKey)
      .send();
    return YES;

  } else return NO;
},

Tutto qui?

Beh, sì! Abbiamo solo dato un’occhiata al tuto­rial e sicu­ra­mente per cose più rea­li­sti­che CloudKit è insuf­fi­ciente ma, come ricor­davo l’altra volta, vedo il suo uti­lizzo nell’ambito della pro­to­ti­pa­zione dove, da un lato, per la GUI, abbiamo SproutCore; dall’altro, per il bac­kend, abbiamo CloudKit.

Rispetto al tuto­rial siamo dovuti inter­ve­nire sulla defi­ni­zione della data source, men­tre nell’originale la stessa imple­men­ta­zione va bene con tutti i bac­kend ma non ci vuole molto per sosti­tuirla in base alle esi­genze2.

  1. CloudKit non sup­porta delle query arbi­tra­rie, quindi l’unico modo per fil­trare i record è quello di usare l’offset
  2. A mio parere, fra l’altro, gli etag dovreb­bero essere gestiti diret­ta­mente da SproutCore

Layout fluidi: vantaggi, rischi e rimedi

Thursday, November 5th, 2009

Questo arti­colo su Smashing Magazine fa il punto sui lay­out fluidi e sugli accor­gi­menti aggiun­tivi per evi­tare sorprese.

In due parole…

Ho letto per la prima di que­sto approc­cio su A List Apart. In sostanza, a par­tire dalla con­sta­ta­zione che i valori in em sono una misura rela­tiva, espressa come target/context, pos­siamo esten­dere que­sto approc­cio per i lay­out, espri­mendo le dimen­sioni delle sezioni in ter­mini di rapporti.

In altre parole, al posto di spe­ci­fi­care che un div dev’essere grande 700px, pos­siamo dire che sarà pari, ad es., al 70,85% della sezione che lo con­tiene, che è pari a 988px.

Inconvenienti e rimedi

I van­taggi pos­sono essere con­si­de­re­voli, soprat­tutto in con­si­de­ra­zione del fatto che le dimen­sioni dei moni­tor ten­dono a diver­si­fi­carsi. D’altra parte ci pos­sono essere pro­blemi, come ad es. il trat­ta­mento di ele­menti come le imma­gini o gli arro­ton­da­menti. I vari rimedi sono elen­cati su Smashing Magazine, con alcune chic­che come Masonry, che sistema i pro­blemi con gli ele­menti flot­tati; Smart Columns, che riar­ran­gia il con­te­nuto in base alle dimen­sioni della fine­stra; e l’aggancio delle dimen­sioni del testo sem­pre in base alle dimen­sioni della finestra.

Test della GUI: un esempio con l’autocomplete di YUI

Wednesday, July 29th, 2009

Qual è il problema?

Una delle cose abba­stanza inca­si­nate da testare sono gli ele­menti dell’elementi AJAX, come l’AutoComplete. Non sono mai riu­scito a testare l’evento che cor­ri­sponde diret­ta­mente allo use case, ovvero, l’utente sele­ziona un’elemento della lista e nel campo asso­ciato viene inse­rito un valore, per­lo­meno con YUI. Ho pro­vato anche con Selenium ma senza suc­cesso. Forse impe­gnan­dosi di più si potrebbe otte­nere qual­cosa di meglio ma, visti i risul­tati (vedi discus­sione in fondo), non so se sia necessario.

Riduciamo i danni

In man­canza dell’ideale pos­siamo comun­que ridurre di molto la por­zione di codice non testata. In primo luogo pos­siamo testare in modo esten­sivo la data source asso­ciata all’AutoComplete. In secondo luogo pos­siamo usare i custom events per iso­lare e testare il codice che si occupa delle con­se­guenze della selezione.

Lo sce­na­rio da testare

Facciamo un esem­pio clas­sico: un AutoComplete che, alla sele­zione del nome del cliente, impo­sta anche il valore della pri­mary key di quel record in un campo nascosto.

Usiamo i custom events

Se non tenes­simo conto delle esi­genze dei test, la solu­zione sarebbe sem­plice:

clienteAC.itemSelectEvent.subscribe(
    function(sType, args) {
        clienteAC.getInputEl().value = args[2].nome;
        document.form-cliente.id_cliente.value = args[2].id;
    }
);

Invece, con gli eventi custom pos­siamo scri­vere que­sto:

clienteAC.itemSelectEvent.subscribe(
    function(sType, args) {
        customItemSelectEvent.fire({
            selectedItem: args[2]
        });
    }
);

Ovvero, alla sele­zione dell’utente, lan­ciamo un evento che con­tiene la sele­zione stessa.

Dall’altra parte, il liste­ner rac­co­glie l’evento, ese­gue le ope­ra­zioni neces­sa­rie e al ter­mine lan­cia un secondo evento, comu­ni­cando la fine dell’operazione:

// aggiorniamo il campo associato all’auto complete
clienteAC.getInputEl().value = args[2].nome;
// impostamo il valore della primary key
document.form-cliente.id_cliente.value = args[2].id;
// “avvisiamo” che abbiamo finito
customLoadCompleteEvent.fire("Finished");

Testiamo!

Questo secondo evento è essen­ziale per i test, infatti, a que­sto punto pos­siamo sem­pli­ce­mente inviare un customItemSelectEvent e aspet­tare l’altro evento in rispo­sta:

//…
name: "Test auto complete cliente",
testSelectEvent: function() {
    var resume = function (ev, type) {
        this.resume(function() {
            customLoadComplete.unsubscribe(resume);
            YAHOO.util.Assert.areEqual(
                 "Mario Rossi",
                 document.form-cliente.nome.value,
                 "Il nome del cliente dovrebbe essere 'Mario Rossi'"
             );
        });
    };
    customLoadComplete.subscribe(resume, this, true);
    customItemSelect.fire({
        selectedItem:{
            id: 1,
	    nome: "Mario Rossi"
	}
    });
    this.wait();
},

Un bilan­cio

Un dub­bio legit­timo che può venire è se valga la pena di com­pli­care così il codice solo per poterlo testare. È un dub­bio che ho spesso!

In gene­rale, l’effetto delle modi­fi­che in fun­zione della “testa­bi­lità” è posi­tivo. L’importante è non spin­gersi al punto di creare metodi o varia­bili che ven­gono usate solo nei test: a mio parere è un errore.

In que­sto caso credo che il codice risul­tante sia più pulito e meglio sepa­rato. Adesso pos­siamo sfrut­tare l’evento finale customLoadComplete in coda alla sele­zione dell’utente per aggior­nare altri ele­menti della pagina, senza che ci sia una dipen­denza diretta con l’AutoComplete.

All’inizio accen­navo al fatto che, nono­stante tutto, sia forse pos­si­bile testare diret­ta­mente l’AutoComplete. Tuttavia ho l’impressione che avrei otte­nuto una qua­lità infe­riore, con più rigi­dità. A que­sto punto lo pren­de­rei in con­si­de­ra­zione solo come test com­ple­men­tare, utile ma non indispensabile.

Tecniche, plugin e trucchi per AJAX

Monday, March 16th, 2009

Smashing Magazine, come sem­pre abbon­dante, segnala un lungo elenco di tec­ni­che AJAX.

Segnalo quelli che mi sono pia­ciuti di più:

Faccio notare che buona parte delle tec­ni­che segna­late pos­sono essere rifatte piut­to­sto facil­mente anche con YUI.

Costruttori in JavaScript

Sunday, February 24th, 2008

Forse c’è ancora qual­cuno JavaScript un lin­guag­gio gio­cat­tolo, al con­fronto di quelli più seri come Java, C# e com­pa­gnia bella; per­lo­meno, è quello che pen­savo io, ma mi sono dovuto ricredere.

In ogni caso, lasciando per­dere le noio­sis­sime dia­tribe sul lin­guag­gio migliore dell’universo è certo che, per uno come che ha pro­gram­mato in Java per un bel po’, alcune carat­te­ri­sti­che di JavaScript sem­brano piut­to­sto bizzarre.

Prediamo ad esem­pio i costrut­tori: anch se la sin­tassi è molto fami­liare, il loro com­por­ta­mento e le loro carat­te­ri­sti­che sono com­ple­ta­mente diverse da quelle che ci si aspet­te­rebbe usando come modello un lin­guag­gio come Java.

Dato che non voglio spac­ciarmi per un guru di JavaScript, lascio a que­sto arti­colo il com­pito di illu­mi­narvi sulla que­stione dei costrut­tori in JavaScript.

Qual’è stata la vostra espe­rienza con JavaScript? Come ci siete arrivati?

Semplificare i form con i widgets

Sunday, February 24th, 2008

In que­sto arti­colo viene pre­sen­tato un sistema per sem­pli­fi­care, o forse sarebbe meglio dire com­pat­tare, un form complesso.

L’idea di fondo è quella di ridurre le diverse sezioni del form in wid­get espan­di­bili e con­trai­bili a pia­cere per ridurre al minimo lo spa­zio occupato.

A mio parere si sor­vola troppo sui difetti di una solu­zione del genere che sono due: le opzioni dispo­ni­bili non sono tutte imme­dia­ta­mente visi­bili e il numero di click neces­sari per sele­zio­nare un’opzione. So benis­simo che è pro­prio lo scopo dell’articolo quello di mostrare un modo per ridurre l’affollamento dello schermo ma non dob­biamo dimen­ti­care che ogni solu­zione ha i suoi pro e contro.

Nel com­plesso rimane comun­que un approc­cio piut­to­sto effi­cace, cal­co­lando il fatto che le eti­chette rias­sun­tive pre­sen­tate quando l’elemento è con­tratto pos­sono for­nire infor­ma­zioni sulla sele­zione attiva in quel momento.

Che ne pen­sate? Avete usato solu­zioni del genere? In par­ti­co­lare per appli­ca­zioni web che pre­ve­dono inse­ri­menti dati massicci?

Attacco XSS su una banca italiana

Wednesday, January 9th, 2008

Spesso mi cullo nell’illusione che, essendo l’Italia rela­ti­va­mente attar­data nelle nuove tec­no­lo­gie, i pro­blemi di sicu­rezza siano un pro­blema poco dif­fuso; e forse la cosa è vera in ter­mini sta­ti­stici. Ma que­sto arti­colo su Netcraft ci ricorda che non è asso­lu­te­mente così.

Si tratta di un attacco di “Cross–site scrip­ting” che inietta un form per dirot­tar i dati inse­riti su un ser­ver a Taiwan, per poi ridi­re­zio­nare l’utente sul sito corretto.

Da leg­gere con attenzione.

YUI 2.4

Thursday, December 6th, 2007

Yahoo! ha rila­sciato YUI 2.4, in cui la novità più inte­res­sante è l’implementazione dei selec­tor CSS 3 via JavaScript.

Prima o poi rifarò que­sto sito usando quello libre­rie… Nel frat­tempo credo che pro­verò ad usare il rich text edi­tor in un nuovo pro­getto che (spero) par­tirà il pros­simo anno. Sono curioso…

PNG trasparenti con IE6: un’alternativa a “filter”

Saturday, December 1st, 2007

Questo arti­colo su 24 ways descrive una solu­zione che mitiga que­sti pro­blemi, tra­mite uno script chia­mata SuperSleight.
Per quanto sia ten­tato di rubri­care il sup­porto a IE6 come supe­rato, visto il rila­scio di IE7 da un anno, la verità è che non è ancora arri­vato il momento. Di con­se­guenza arti­coli come quello che vado a segna­larvi hanno ancora un loro perché.

Tradizionalmente, per poter usare PNG tra­spa­renti con IE6, si faceva ricorso alla pro­prietà filter che, inu­tile dirlo, era pro­prie­ta­ria di Microsoft. Inoltre que­sta solu­zione ha diversi difetti:

  • le imma­gini in back­ground non pos­sono essere posi­zio­nate o ripetute;
  • pro­blemi con i link e con i form che si tro­vano sopra l’immagine;
  • l’implementazione è comun­que laboriosa.

« Voci Precedenti