Mondi su mondi, sistemi di sistemi.

Jenkins: non solo Java

Monday, June 27th, 2011

Stavo scri­vendo un post dopo aver letto l’annuncio di que­sto stru­mento per il con­trollo dei CSS quando mi è venuto in mente che forse sarebbe più inte­res­sante discu­tere dell’evoluzione gene­rale del (mio) modo di creare appli­ca­zioni1 per il web. Quindi ho but­tato nel cestino il post sui CSS.

Oltre il “plain text”

Una delle ragioni del suc­cesso del web è il fatto di essere basato su for­mati testuali: se voglio vedere com’è fatta una pagina, un foglio di stile, uno script, basta che lo apra con un qual­siasi edi­tor di testo. Anche su tutti i pro­cessi che stanno a con­torno del lavoro crea­tivo vero e pro­prio bene­fi­ciano di que­sta sem­pli­cità. Una volta creato un file, que­sto è pronto per svol­gere la sua fun­zione senza pas­saggi inter­medi, basta cari­carlo sul sito.

Tutto que­sto, però, è sem­pre meno vero per­ché la pres­sione per otte­nere pre­sta­zioni sem­pre migliori sta por­tando sem­pre di più verso un con­te­nuto che, se ancora si può tec­ni­ca­mente defi­nire “plain text”, risulta illeg­gi­bile in modo diretto. 2.

Poi ci sono l’ottimizzazione delle imma­gini o, come abbiamo visto, i con­trolli di qua­lità ecc. Insomma, si può dire che i pro­cessi usati nel creare delle appli­ca­zioni “tra­di­zio­nali”, con lin­guaggi com­pi­lati e anche il sem­plice sito sta­tico, si asso­mi­gliano sem­pre di più.

I pros­simi passi

Sono per­ciò arri­vato alla con­clu­sione che è sen­sato usare gli stessi stru­menti in tutti casi.

Quindi, anche se devo ancora pro­gram­mare la que­stione nel det­ta­glio, sicu­ra­mente comin­cerò a spo­stare i pro­getti sotto Jenkins; da lì vedrò poi di deci­dere caso per caso le ope­ra­zioni da fare. In alcuni casi gli stadi del pro­cesso saranno delle sem­plici otti­miz­za­zioni, in altri ci saranno anche tutte le varie bat­te­rie di test ma l’infrastruttura di base sarà la stessa.

  1. C’è sicu­ra­mente una bella dif­fe­renza fra un sito “sta­tico” e un’applicazione, ma credo che sia con­ve­niente comun­que con­si­de­rarli come estremi di uno stesso spet­tro. Anche per le ragioni espo­ste in que­sto post.
  2. Gli esempi ovvi sono la minia­tu­riz­za­zione dei fogli di stile e degli script. Anzi, per JavaScript siamo ormai arri­vati alla com­pi­la­zione vera e pro­pria. Poi ci sono altre forze di cam­bia­mento come la sem­pre mag­giore dina­mi­cità delle pagine, il cui con­te­nuto finale, una volta che il bro­w­ser ha com­ple­tato il pro­ces­sa­mento, non asso­mi­glia nem­meno lon­ta­na­mente a quello par­tenza.

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.

Tool del giorno: livereload

Wednesday, August 11th, 2010

Se c’è una cosa che ha inse­gnato l’xp è che il tempo per rice­vere il feed­back è cri­tico: più è breve, meglio è. D’altra parte se c’è una cosa che diventa dolo­ro­sa­mente chiara dopo la prima mezz’ora pas­sata a svi­lup­pare una pagina html è che siamo schiavi della com­bi­na­zione ⌘-r: fatta una modi­fi­china? Ricarica. Errore? Ricarica. Forse c’è qual­cosa in cache? Ricarica.

Così qual­che per­sona d’ingegno ha pen­sato bene di ren­derci la vita un po’ più sem­plice con live­re­load: una com­bi­na­zione di una gem di Ruby e di un’estensione per WebKit che fa rica­ri­care auto­ma­ti­ca­mente la pagina al bro­w­ser ad ogni modi­fica all’interno di una cartella.

Dopo cin­que minuti di uti­lizzo non saprete più con­ce­pire il mondo senza que­sta cosa. Installate!

Una sola rac­co­man­da­zione. Se per caso avete instal­lato ruby tra­mite MacPorts, non usa­telo. La gem fun­ziona solo con quello di sistema.

Utility del giorno: Fake

Monday, July 12th, 2010

Una delle cose più noiose è il dover ripe­tere manual­mente una serie di ope­ra­zioni con il bro­w­ser: per veri­fi­care che tutto sia a posto; come test per la gui; nell’accesso a ser­vizi che richie­dono la ripe­ti­zione di una serie sem­pre uguali di passi.

Ci sono già stru­menti di auto­ma­zione e replay come Selenium, ma sono pen­sati esclu­si­va­mente per il testing.

Fake è un’applicazione basata su Safari che copre sia gli sce­nari più stan­dard di Selenium sia i casi in cui vogliamo auto­ma­tiz­zare l’accesso noto­ria­mente imper­vio a siti come quelli di home ban­king e simili. In più, Fake per­mette alcune ope­ra­zioni molto più potenti e che non hanno nulla a che vedere con il testing ma che pos­sono essere uti­lis­sime come l’esecuzione di script di shell o AppleScript.

L’interfaccia è un incro­cio fra Automator e Safari ed è di una faci­lità estrema: basta tra­sci­nare le azioni nella time­line e impo­stare i para­me­tri. Una volta messa a punto la sequenza che vogliamo, pos­siamo sal­varla per il futuro.

Coda & Subversion

Thursday, March 25th, 2010

Uso Coda ormai da qual­che tempo. È un buon pro­gramma per lo svi­luppo dei siti, pia­ce­vole da usare e affi­da­bile, non ho avuto biso­gno di molto altro per diverso tempo.

I limiti più evi­denti di Coda

Dopo qual­che tempo, però, ho comin­ciato a sen­tire la man­canza di Emacs e così ho con­fi­gu­rato Coda in modo da usarlo come edi­tor esterno. A quel punto ho sco­perto con fasti­dio che la lista dei file da cari­care sul sito non veniva sem­pre aggior­nata con le modi­fi­che da Emacs, nono­stante fos­sero cor­ret­ta­mente indi­vi­duati come file modi­fi­cati rispetto alla repo­si­tory nel VCS (Version Control Software; attual­mente è Subversion), costrin­gen­domi ogni volta a mar­carli a mano. No fun.

Inoltre non sem­pre abbiamo a che fare con un deploy­ment diretto. Spesso dob­biamo prima cari­care il sito su un ser­ver di sta­ging e poi, veri­fi­cato che tutto vada bene, pas­sarlo in pro­du­zione. Teoricamente potremmo “ripun­tare” Coda fra i due ser­ver ma, in pra­tica, sarebbe un delirio.

Sfruttiamo Subversion!

Il modo ovvio di risol­vere que­sti pro­blemi è usare i punti di aggan­cio che Subversion mette a dispo­si­zione, ovvero, la pos­si­bi­lità di ese­guire delle ope­ra­zioni arbi­tra­rie in con­co­mi­tanza di alcuni eventi:

  • post-commit
  • post-lock
  • post-revprop-change
  • post-unlock
  • pre-commit
  • pre-lock
  • pre-revprop-change
  • pre-unlock
  • start-commit

In que­sto caso, lo script aggan­ciato sarà aggan­ciato in post-commit ed effet­tuerà il deployment.

I det­ta­gli importanti

Una cosa piut­to­sto sem­plice, insomma, anche se ci sono diverse cosine di cui tener conto. In primo luogo, è sem­pre pre­fe­ri­bile disim­pe­gnare Subversion il prima pos­si­bile1 e quindi dob­biamo posporre le varie ope­ra­zioni; inol­tre, dato che lo script è con­di­viso per tutta la repo­si­tory, dob­biamo avere l’accortezza di fare le azioni giu­ste per il pro­getto giu­sto; infine, visto che ogni pro­getto fa sto­ria a sé, dob­biamo tro­vare un buona fles­si­bi­lità2 per poter spe­ci­fi­care le azioni che vogliamo, nel modo che rite­niamo più oppor­tuno per quel progetto.

Disimpegnare velo­ce­mente la repository

Ad ogni com­mit viene creato uno script di shell (a par­tire da un tem­plate descritto più avanti) chia­mato con il numero di release. La crea­zione è pra­ti­ca­mente istantanea.

Questo script va a finire in una spe­cie di coda sul file­sy­stem. Il fatto di usare una direc­tory invece di un file sin­golo evita pro­blemi di accesso con­tem­po­ra­neo, lasciando com­pleta libertà nel suo con­te­nuto e mi con­sente di sfrut­tare laun­chd per fare in modo che il pro­ces­sa­mento degli script nella coda venga lan­ciato solo al momento oppor­tuno. Questo è il file di configurazione:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>it.refactor.deployment-queue</string>
<key>OnDemand</key>
<true/>
<key>Program</key>
<string>/usr/local/bin/projects-auto-deployment</string>
<key>QueueDirectories</key>
<array>
<string>/var/tmp/deployment-queue</string>
</array>
</dict>
</plist>

Il det­ta­glio impor­tante è la diret­tiva QueueDirectories che, a dif­fe­renza di WatchPaths, lan­cia il pro­cesso alla modi­fica del con­te­nuto della direc­tory, ma solo quando in pre­ce­denza era vuota.

In alter­na­tiva avremmo potuto usare un qual­che dae­mon. Non un gran pro­blema ma mi sem­brava un po’ meno robusto.

Progetti diversi, copioni diversi

Come dicevo prima, lo scopo di usare degli script di shell è quello di lasciare la mas­sima libertà.

Ogni voce della con­fi­gu­ra­zione letta dallo script è simile a questa:

    <regexp> {
        env {
            REL=$rev
        }
        preflight {...}
        deploy {...}
        postflight {...}
    }

Le quat­tro voci: env, preflight, deploy e postflight rag­grup­pano e ordi­nano i diversi fram­menti che vanno a com­porre lo script di deploy­ment, che viene atti­vato in base all’eventuale match dell’espressione regolare.

L’unica varia­bile cono­sciuta è il numero della release, che è pas­sato da Subversion, il resto è tutto libero. Più gene­rico di così!

Di solito, dopo aver defi­nito le varia­bili ambien­tali in env, il preflight si occupa di fare il chec­kout dal VCS; il deploy fa quello che si può imma­gi­nare; il postflight si occupa di fare un po’ di puli­zia ecc. Ribadisco però il fatto che quelle descritte prima sono solo sezioni: se per assurdo voglio met­tere tutto nella sezione env lo posso fare.

Ma non è finita qui…

Tutto bene? Quasi. Così com’è pen­sato, il sistema non per­mette di fare alcune cose molto importanti.

Percorsi varia­bili

Se vogliamo usarlo anche per il deploy­ment delle release “tag­gate”3, dob­biamo aggan­ciare lo script al per­corso dei tag. Tuttavia, dato che l’url com­pleta cam­bia ad ogni nuovo tag — ad esem­pio avremo …/tags/REL1, …/tags/REL2 — come fac­ciamo a sapere in post-commit quale prendere?

Per ora non ho tro­vato una solu­zione gene­rica. Mi sono affi­dato al fatto che il nome della ver­sione in tags è uguale al numero pre­ce­dente della release di post-commit4. Ad esem­pio, se l’operazione è stata ese­guita alla release 3753, cer­che­remo la direc­tory r3752. Una volta otte­nuta l’URL rien­triamo nel caso standard.

Azioni spe­ci­fi­che per le sin­gole release

Un’altra cosa abba­stanza fre­quente è l’esecuzione di ope­ra­zioni spe­ci­fi­che per una data ver­sione. Esempio tipico: delle modi­fi­che allo schema del data­base, che vanno fatte una volta sola e non devono essere riapplicate.

Per risol­vere que­sto pro­blema, all’interno del pro­getto, in una direc­tory nota, creiamo uno script che verrà cer­cato dal sistema di deploy­ment per essere ese­guito5.

roll-up delle modifiche

Infine, nello sce­na­rio sta­ging & deploy­ment è desi­de­ra­bile che una serie di ope­ra­zioni fatte in sta­ging pos­sano venire appli­cate in una volta sola in deployment.

Dato che lo script spe­ci­fico per una data release è anch’esso sotto con­trollo di ver­sione, abbiamo accesso a tutta la sua sto­ria. Bisognerà andare a pren­dere quella por­zione di modi­fi­che inter­corse fra l’ultimo deploy­ment e quello attuale e appen­derle ad un unico file, con un comando del genere, ad esem­pio:
svn log -r3778:3783 -q URL | egrep ^r | awk '{ print $1 }' | sort | while read r; do svn cat -$r URL; done

Come ottengo il range da pas­sare al comando appena visto? Partiamo da un sce­na­rio sem­pli­fi­cato all’osso, sup­po­nendo di par­tire da una repo­si­tory nuova di zecca.

Dalla r1 alla r10, lavoro solo nel trunk; quando creo un nuovo tag, in base alle con­ven­zioni adot­tate prima, il suo nome sarà r10 e il suo numero di release sarà r11. Proseguendo, dalla r12 alla r20, lavoro sem­pre nel trunk; come prima, creando un nuovo tag, il nome sarà r20 e il suo numero di release sarà r21.

A que­sto punto, se cerco tutte le modi­fi­che in tags, esclu­dendo quella rela­tiva alla crea­zione della direc­tory tags, avrò r11 ed r21. Come prima, in base al numero di release pas­sato in post-commit, che al secondo tag sarà 20, posso rica­vare il range da con­si­de­rare, cal­co­la­bile come (release immediatamente precedente):(numero di release - 1), ovvero, r11:r19.

There’s more than one way to do it

Per chi non avesse voglia di rein­ven­tare la ruota, ci sono delle alter­na­tive. In par­ti­co­lare, una delle pos­si­bi­lità che ho preso in con­si­de­ra­zione è quella di instal­lare il soft­ware di VCS diret­ta­mente sul server.

In effetti è una solu­zione piut­to­sto comoda, dato che basta fare un svn up per aggior­nare l’installazione e con VCS distri­buiti le pos­si­bi­lità sono ancora più ampie.

Ci sono però diversi punti dolenti. Come visto prima è raro che basti un sem­plice aggior­na­mento del codice; in secondo luogo non mi piace mol­tis­simo l’idea che si crei un’ulteriore dipen­denza fra il sistema che pub­blica gli aggior­na­menti e quello che li riceve.

Tolta que­sta pos­si­bi­lità, ci sono i soft­ware di SCM veri e pro­pri, da Puppet a Capistrano, pas­sando per Fabric. Il primo pro­pone un modello in pull, dove i cliente con­tat­tano il ser­ver per sta­bi­lire cosa c’è da fare; il secondo e il terzo sono più vicini ai sistemi in push, dove l’azione è ini­ziata dal server.

Infine, non dimen­ti­chia­moci di Hudson che, pur essendo un ser­ver di inte­gra­zione, può auto­ma­tiz­zare pra­ti­ca­mente qual­siasi cosa e quindi anche pro­cessi come questi.

Hudson è quello più adatto, essendo un vero e pro­prio ser­ver di con­ti­nous inte­gra­tion. Anzi, non escludo di comin­ciare ad usarlo a breve, ma per ora mi bastano le due righe che ho scritto in Tcl.

Per quanto riguarda gli SCM, più vicini al mondo dei sysad­min, Puppet mi piace di più, anche per­ché ci ho gio­cato un paio di volte, men­tre ho visto usare Capistrano in situa­zioni simili a quelle descritte.

Come si può notare, alcune delle parti più con­torte sono dovute a Subversion. Dato che ho in pro­getto di pas­sare a Git, sono curioso di sapere se e come il pro­ce­di­mento si semplificherà.

  1. In post-commit Subversion ignora l’esito delle ope­ra­zioni, dato che il com­mit è già stato fatto; tut­ta­via non mi è chiaro se lo ese­gua in asin­crono
  2. avete mai sen­tito di un pro­getto che non deve essere fles­si­bile?
  3. Per chi non lo sapesse, un tag è un’istantanea del codice sor­gente ad un dato momento. In Subversion, è di prassi che le ver­sioni uffi­ciali stiano in tags e le ver­sioni di svi­luppo che deviano da quella prin­ci­pale stiano in branches.
  4. l’uso dei numeri di release come nome del tag non mi risulta sia la cosa più con­si­glia­bile, lo so, tut­ta­via nelle appli­ca­zioni con rila­sci con­ti­nui la cosa non mi sem­bra così grave
  5. Qualcuno stor­cerà il naso nel vedere una com­mi­stione fra deploy­ment e svi­luppo, all’interno del sor­gente. Non è sicu­ra­mente la solu­zione più pulita anche se ha l’indubbio van­tag­gio di tenere sotto con­trollo di ver­sione anche cose che spesso ven­gono lasciate un po’ a se stesse. Ad oggi credo che il bilan­cio costi/benefici sia posi­tivo.

Dettagli sul font hinting

Friday, January 22nd, 2010

Nel mio post chi­lo­me­trico su @font-face ho accen­nato alla que­stione del font hin­ting e alle dif­fe­renze nel ren­de­ring delle font, in par­ti­co­lare, quello delle font OpenType CFF sotto Windows è net­ta­mente peg­giore di quelle TrueType 1.

PostScript vs TrueType

Il motivo di que­sta dif­fe­renza è dovuto al fatto che il for­mato CFF ere­dita una serie di scelte fatte in pas­sato con il PostScript, in par­ti­co­lare la descri­zione dell’outline e, appunto, il modello di hinting.

Questi modelli, però, erano creati per le stam­panti a bassa riso­lu­zione e non per il moni­tor; vice­versa, il TrueType è stato pen­sato fin dall’inizio per il ren­de­ring a video.

Perché il CFF usa il modello del PostScript?

La scelta usata per il CFF è moti­vata dal fatto che il for­mato outline con le curve di Bézier cubi­che del PostScript è quello usato quasi tutti i pro­get­ti­sti di font e soprat­tutto il modello di hin­ting è molto più sem­plice e può essere in larga parte auto­ma­tiz­zato 2.

In que­sto momento, quindi, la scelta del TrueType per @font-face sem­bra pra­ti­ca­mente obbli­gata, almeno fino al momento in cui il ren­de­ring tra­mite DirectWrite sarà suf­fi­cien­te­mente dif­fuso su Windows 3.

  1. Fonts e il web: a che punto siamo
  2. Font Hinting Explained By A Font Design Master
  3. A typo­gra­phic wor­k­book. Le infor­ma­zioni sui diversi for­mati si tro­vano alle pagg. 135–137.

Fonts e il web: a che punto siamo?

Saturday, January 2nd, 2010

Introduzione

Una dei temi ricor­renti dell’anno appena tra­scorso nell’ambito dello svi­luppo web è stato sicu­ra­mente quello delle font. Ho pen­sato per­ciò di rac­co­gliere alcuni arti­coli com­parsi recen­te­mente per dare una pano­ra­mica della questione.

In par­ti­co­lare, vedremo in cosa con­si­ste a grandi linee l’uso di @font-face, i punti a cui fare atten­zione, le impli­ca­zioni posi­tive e nega­tive. Ho cer­cato di estrarre gli aspetti più pra­tici, riman­dando agli arti­coli ori­gi­nali (lin­kati nei titoli delle sezioni) per i det­ta­gli teo­rici e le moti­va­zioni che stanno die­tro le varie soluzioni.

Per gli impa­zienti, comun­que, ecco il rias­sunto. Anche se i passi in avanti sono stati signi­fi­ca­tivi, credo sia pru­dente limi­tare @font-face a titoli e cose del genere, con­ti­nuando ad usare le font clas­si­che per tutto il resto, magari rive­dendo con più atten­zione gli stack delle font dichia­rate nei fogli di stile.

How to use CSS @font-face #

Cominciamo con la domanda pra­tica: cosa biso­gna fare per usare @font-face? Questo:

@font-face {
  font-family: "Kimberley";
  src: url(http://www.princexml.com/fonts/larabie/ »
  kimberle.ttf) format("truetype");
}

In altre parole, dob­biamo defi­nire ori­gine e for­mato per la font Kymberley in modo da poterla poi usare nelle stesse moda­lità delle font già installate.

Fin qui la teo­ria, in pra­tica dob­biamo risol­vere la que­stione dei diversi for­mati delle font 1. La cosa più veloce per risol­verle è gene­rare tutti quelli che ser­vono con Font Squirrel.

Una volta gene­rati i for­mati biso­gna irro­bu­stire la dichia­ra­zione che abbiamo visto prima per farla fun­zio­nare con i vari browser:

@font-face {
  font-family: "Your typeface";
  src: url("type/filename.eot");
  src: local("Alternate name"), local("Alternatename"),
    url("type/filename.woff") format("woff"),
    url("type/filename.otf") format("opentype"),
    url("type/filename.svg#filename") format("svg");
  }

La com­bi­na­zione dei due src si prende cura di Explorer 2; i due local con­sen­tono al bro­w­ser di cer­care prima la font in locale, e sono due per­ché alcuni bro­w­ser usano il nome Postscript e altri il nome del file; il resto sono elen­cati i for­mati in ordine di desiderabilità.

Anche se qui mostriamo una sola dichia­ra­zione, biso­gna tenere pre­sente che biso­gna crearne: una per il roman e una per l’italico 3.

Real Web Type in Real Web Context #

Una volta che abbiamo impo­stato i nostri fogli di stile, per testare una font serve un qual­che tipo di testo stan­dard che ne metta in luce pregi e difetti.

Web Font Specimen fa esat­ta­mente que­sto. Possiamo sca­ri­care la pagina cam­pione in locale, impo­starla con le nostre font e vedere come si com­porta dal vivo, con i vari bro­w­ser 4.

Designing For The Switch #

Rendering a parte, uno dei pro­blemi prin­ci­pali nell’uso di @font-face è il peso, dovuto prin­ci­pal­mente alle tabelle di hin­ting molto estese.

Il Georgia, ad esem­pio, è quasi 300 KB, suf­fi­cienti rovi­nare il primo impatto per­ché alcuni bro­w­ser, come Opera e FireFox, pre­sen­te­ranno per un attimo la pagina senza la font cor­retta, il fami­ge­rato Flash of Unstyled Text (FOUT), men­tre altri, come il WebKit, aspet­te­ranno di aver sca­ri­cato tutta la font, non mostrando nes­sun testo durante l’operazione.

Da un punto di vista stret­ta­mente pro­ce­du­rale, non c’è nes­suna alter­na­tiva: la font dev’essere sca­ri­cata e fino a quando l’operazione non è ter­mi­nata le scelte pos­si­bili sono quelle viste prima 5.

Fighting the @font-face FOUT — Quicken the load time #

Tuttavia ci sono alcuni truc­chi uti­liz­za­bili. Il primo con­si­ste nel ridurre all’osso il file della font, eli­mi­nando tutto quello che non è stret­ta­mente indi­spen­sa­bile 6; il secondo con­si­ste nel cali­brare atten­ta­mente l’elenco delle font nel foglio di stile per mini­miz­zare il FOUT; poi lo pos­siamo zip­pare, gua­da­gnando fino al 40%; infine dovremo fare in modo che la font sca­ri­cata rimanga in cache.

L’arma nucleare tat­tica 7è però quella di for­zare il cari­ca­mento della font prima che la pagina venga mostrata, in modo da averla pronta quando serve.

Better font stacks #

Come accen­navo all’inizio, l’estensione dello stack delle font dichia­rate può essere usato per que­sto scopo (com­bat­tere il FOUT) ma anche sem­pli­ce­mente per usare com­bi­na­zione meno scontate.

La pre­messa fon­da­men­tale è che, in realtà, il bro­w­ser ha a dispo­si­zione molte più font di quelle di solito con­si­de­rate. Inoltre, è pos­si­bile indi­vi­duare delle com­bi­na­zioni accet­ta­bili per coprire i casi in cui la font ideale non è presente.

Questo lavo­rac­cio è già stato fatto e il cam­pio­na­rio in pdf alle­gato all’articolo citato è uti­lis­simo per pren­dere una deci­sione 8.

Real Fonts and Rendering: The New Elephant in the Room #

E ora veniamo al vero pro­blema emerso nei primi usi sul campo: il ren­de­ring delle font, dovuto ai com­por­ta­menti molto ete­ro­ge­nei dei motori di ren­de­ring in com­bi­na­zione con i diversi sistemi ope­ra­tivi. 9.

Browser Choice vs Font Rendering #

L’analisi di Zeldman difetta forse di pre­ci­sione, visto che si limita a con­sta­tare il pro­blema, anche se posso capirlo: i det­ta­gli sono un po’ da mal di testa. Comunque, guar­dando le cose con più atten­zione il pano­rama sem­bra meno preoccupante.

L’attuale sistema di ren­de­ring sotto Windows, il GDI, che for­ni­sce la base per l’anti-aliasing in ClearType, fun­ziona in modo ade­guato solo le font TrueType.

Le nuove ver­sioni dei bro­w­ser use­ranno però un’altro motore, il DirectWrite, più sofi­sti­cato, in grado di for­nire un ren­de­ring ade­guato anche per i PostScript e gli OpenType. Ci saranno ancora delle dif­fe­renze rispetto a Mac OS X ma saranno “solo” diversi.

In con­clu­sione

Dopo tante attese e false par­tenze l’uso di @font-face non è più solo una pos­si­bi­lità teo­rica. Tuttavia, anche se la voglia di usarlo sem­bra con­ta­giare tutti, allo stato attuale va usato con atten­zione: mi limi­te­rei alle tito­la­zioni; per i testi estesi ci vuole più prudenza.

Questi sono pro­blemi che ver­ranno comun­que risolti. Più impor­tanti, invece, i mes­saggi per chi si occupa di design web.

In primo luogo biso­gna supe­rare la fissa di fare in modo che una pagina si veda esat­ta­mente allo stesso modo ovun­que 10. Il fatto di avere più font a dispo­si­zione ha fatto emer­gere dif­fe­renze enormi fra le varie piat­ta­forme e, a com­pli­care ulte­rior­mente le cose, le piat­ta­forme stesse sono in con­ti­nua diver­si­fi­ca­zione11. Inseguire l’assoluta omo­ge­neità è futile, però biso­gnerà essere più rigo­rosi nei test: le sor­prese del ren­de­ring sono sal­tate fuori in modo cla­mo­roso anche per­ché, a dispetto delle dichia­ra­zioni uffi­ciali, alcuni siti sono “usciti” con ver­sioni testate solo su Mac.

Inoltre e cosa più impor­tante, l’espansione dell’offerta di font uti­liz­za­bili signi­fica che è neces­sa­ria una mag­giore com­pe­tenza (tipo)grafica. Ci vor­ranno più gusto e più com­pe­tenza per la scelta e la com­bi­na­zione giuste.

Può darsi che quella dell’anno scorso sia stata solo una fiam­mata desti­nata a spe­gnersi e rima­nere dor­miente per altri anni ma non ci scom­met­te­rei: meglio prepararsi.

  1. Sono stati pro­prio i for­mati a fer­mare l’uso di @font-face fino ad oggi, ali­men­tando fra l’altro l’errata con­vin­zione che fosse una pos­si­bi­lità intro­dotta con CSS3.
  2. che userà comun­que il primo
  3. altri det­ta­gli sul per­corso che ha por­tato a que­sta solu­zione li tro­vate in Bulletproof @font-face syn­tax
  4. que­stione spi­nosa su cui tor­ne­remo più avanti
  5. Per quanto riguarda i motori di ren­de­ring, non escludo che gli svi­lup­pa­tori si inven­tino qual­che stra­ta­gemma per miti­gare almeno il pro­blema.
  6. Font Squirrel, di cui abbiamo par­lato prima, rende que­sta parte molto sem­plice
  7. anche a costo di ren­dere l’HTML non valido? Beh, a voi la scelta dell’esca­la­tion
  8. que­ste infor­ma­zioni le ho rica­vate da font-face e Webfonts: come usarli, un post com­ple­tis­simo, in par­ti­co­lare sulla suc­ces­sione degli eventi che ha por­tato alla situa­zione attuale
  9. Fra l’altro la que­stione non è limi­tata al ren­de­ring del sin­golo carat­tere ma si estende anche alla spa­zia­tura fra i carat­teri. In par­ti­co­lare, le tabelle di ker­ning non ven­gono rispet­tate
  10. Ignorance is bliss
  11. quante ver­sioni di WebKit ci sono in giro? Io ho perso il conto…

Sorprese di fine anno

Saturday, December 5th, 2009

“Non si potrebbe fare…?”

Come se non bastasse il lavoro di rifa­ci­mento, è arri­vata sulla scri­va­nia la richie­sta di una ver­sione che:

  1. possa essere usata in assenza di connettività;
  2. non richieda alcuna pro­ce­dura d’installazione;
  3. sia mul­ti­piat­ta­forma;
  4. sia ese­gui­bile diret­ta­mente da una chiave USB.

Insomma, non pro­prio un qual­cosa da fare nei rita­gli di tempo!

Cosa usare?

All’inizio avevo pen­sato ad una qual­che appli­ca­zione in Java, usando Swing o SWT ma non ho pra­ti­ca­mente nes­suna fami­lia­rità con appli­ca­zioni desk­top di quel tipo; inol­tre non è affatto scon­tato che Java sia sem­pre installata.

Sul lato .Net, cono­sco qual­cosa di più ma non ho idea se sia fat­ti­bile uno svi­luppo multipiattaforma.

“The sim­plest thing…”

Poi mi è venuto in mente che avrei potuto rispar­miare un bel po’ di lavoro usando una ver­sione rivi­si­tata di quella su web, con la parte ser­ver che gira diret­ta­mente sul com­pu­ter dell’utente. Fattibilissimo, certo, ma non pro­prio una cosa che non richiede alcuna installazione

Infine, credo di aver tro­vato una solu­zione in Tcl, tra­mite i cosid­detti StarKit e StarPack: un colos­sale (ma leg­ge­ris­simo, in MB) uovo di colombo.

In poche parole, uno StartKit con­sente di impac­chet­tare un’intera appli­ca­zione in una spe­cie di disco imma­gine. Questo disco imma­gine con­tiene anche tutti i file ausi­liari, binari o meno, anche per diverse piattaforme.

Fin qui niente di par­ti­co­lare. In fondo, con l’avvento delle mac­chine vir­tuali è diven­tata prassi comune distri­buire diret­ta­mente dei dischi imma­gine. C’è però da supe­rare l’ostacolo dell’installazione, visto che per ese­guire uno StarKit serve comun­que un inter­prete Tcl più una serie di librerie.

E qui entrano in scena gli StarPack, che accor­pano uno StarKit e l’interprete in unico file, con­fi­gu­rato per par­tire con un dop­pio click. Il peso? Pochi MB!

Nei pros­simi giorni vedremo un po’ più in det­ta­glio come fun­ziona que­sta tecnologia.

Life goes on

Nel frat­tempo, sul fronte del refac­to­ring, ho ter­mi­nato l’accorpamento di tutto l’SQL. Adesso dovremo comin­ciare a tagliare i ponti con le sezioni che si appog­giano a Joomla.

PS · Va pre­ci­sato che con l’arrivo ormai pros­simo dell’HTML 5, diven­terà con­ce­pi­bile pen­sare a solu­zioni che pos­sano girare in com­pleta auto­no­mia, senza alcuna con­nes­sione. Tuttavia, il sup­porto da parte di Explorer è ancora incompleto.

La mano di Google

Tuesday, October 13th, 2009

Design Observer, leg­gendo Conrad da Google Books, sco­pre con orrore una mano immor­ta­lata durante il pro­cesso di scan­sione del libro.

La foto getta una luce ridi­cola (quindi, umana) e un po’ inquie­tante que­sto enorme pro­getto. Sono abi­tuato a pen­sare che il livello tec­no­lo­gico di Google sia così supe­riore alla media che vedere una mano non pro­prio pulita con un ditale di gomma in mezzo alle pagine è quasi incredibile.

Comunque, diciamo che può suc­ce­dere, anche se come giu­sta­mente da notare il post di Design Observer, que­sta sto­ria fa nascere qual­che dub­bio sulla cura messa nel pro­cesso di scansione.

Più in gene­rale, riguardo a Google Books con­ti­nuo ad avere delle riserve: troppo, in poche mani.

WebKit: a ognuno il suo

Thursday, October 8th, 2009

Il grande ppk ha tor­chiato tutti i bro­w­ser basati su WebKit che è riu­scito a tro­vare, per veri­fi­care se sia poi vero che la dif­fu­sione di que­sto motore di ren­de­ring impli­chi neces­sa­ria­mente una mag­giore uniformità.

I risul­tati sono sco­rag­gianti: non ce n’è uno uguale all’altro.

« Voci Precedenti