venerdì 28 dicembre 2012

Sviluppare codice migliore con la programmazione funzionale


Minimizzare gli impatti del cambiamento dovrebbe essere uno degli obiettivi prioritari nella produzione del software, soprattutto se in contesti di medio-alta complessità. Normalmente, infatti, si assiste al fenomeno dell'ingessatura del codice: nessuno si azzarda a introdurre cambiamenti migliorativi perché questo potrebbe portare a conseguenze inaspettate, potenzialmente drammatiche.

Per minimizzare gli impatti del cambiamento esistono strumenti e tecniche diverse: ad esempio il test driven development, oppure il defensive programming. Un altro metodo è quello di scrivere codice secondo il paradigma della programmazione funzionale (FP = Functional Programming).




Un programma scritto in un linguaggio FP puro è normalmente esente da "side-effect": cioè è un software che si comporta in un solo modo, predicibile, e che ha un comportamento identico una volta compilato. Questo perché si traduce sostanzialmente in una funzione che prende in input una qualunque serie di funzioni che agiscono su costanti. E' come un meccanismo di ruote e pulegge: una volta in movimento, si comporta sempre nello stesso identico modo.

Purtroppo solo una piccolissima parte di programmi può essere scritta in FP pura. Questo perché un programma per essere utile deve poter prevedere: 1) input dall'esterno e 2) mantenimento di uno stato. Queste però sono due cose che sono "inesprimibili" in FP puro.

Quello che possiamo fare è invece utilizzare un linguaggio ibrido, che permetta cioè sia la programmazione imperativa (magari ad oggetti) cui siamo abituati, sia la programmazione funzionale, cercando di minimizzare e confinare la parte imperativa in un punto noto - e ridotto - del codice sorgente. Eccellenti esempi di linguaggi ibridi sono oggi Scala e C#.

In Scala, le variabili vengono nominate in due modi diversi: var, la variabile "normale" cui siamo abituati, e val, una variabile che, una volta che abbia assegnato un valore, non lo modificherà mai per tutta la sua vita. (In C# le variabili val di Scala sono scritte come readonly) Un programma scritto in Scala che abbia molte var, è un programma che segue la logica imperativa, che crea oggetti che mantengono uno stato e che quindi è potenzialmente pieno di side-effects. Viceversa, un programma che abbia pochissime o nessuna var, e val al loro posto, è un programma scritto in logica funzionale, e che avrà pochi o nessun side-effect. Questo secondo tipo di programma è molto più facile da mantenere, dovrà essere testato di meno, e quindi avrà maggiore valore.

Come si possono scrivere normali costrutti in logica funzionale? E' difficile, perché il nostro cervello è abituato a pensare in termini di "oggetti" e di "stato", e molto poco in termini di "funzioni" e "funzioni di funzioni". Però con un po' di pratica l'obiettivo può essere centrato.

Vediamo un esempio. Supponiamo di voler scrivere una classe che prende in input una stringa e ne calcola il suo valore ASCII (il valore ASCII di una stringa è la somma dei suoi caratteri intesi secondo la codifica ASCII).


class TestClass(givenString: String) {

    require(givenString != null)
    private var gStr: String = givenString


    def getValue() = {
        this.compute()
    }

    private def compute(): Int = {
        var tempSum: Int = 0
        for (charV <this.gStr.toCharArray()) {
            tempSum += charV.toInt
        }
        tempSum
    }

}


Questo programma in Scala contiene due var: una per mantenere lo "stato", che è la variabile che contiene la stringa da trasformare in numero, e una per mantenere il numero associato alla stringa mentre viene calcolato, all'interno di un ciclo for.

Come trasformare questa classe in logica funzionale?

Dobbiamo come prima cosa far sparire lo "stato" dalla classe. La nostra classe deve comportarsi come una "funzione" e quindi non deve mantenere in memoria parametri che possono cambiare valore nel tempo. Farlo è molto semplice: invece che memorizzare givenString come variabile (var) lo memorizzeremo come costante (val). Oppure, potremmo non memorizzarlo del tutto e passarlo così com'è al metodo di calcolo compute().

Più difficile è invece sostituire il costrutto for che calcola il valore. Qui useremo invece una formula classica della FP. Creeremo un metodo che ritorna una collezione, cioè un array dinamico, di valori ASCII, ognuno per ciascun carattere che forma la stringa. Poi su questa collezione applicheremo una funzione di trasformazione: nel nostro caso "sum". Ogni collezione fornisce metodi operatore sui valori che la compongono, e in più può accettarne di nuovi appositamente scritti.

Ecco il nostro codice trasformato in logica funzionale:

class ImmutableTestClass(givenString: String) {

    require(givenString != null)
    private val gStr: String = givenString

    def getValue() = {
        this.compute(this.gStr)
    }

    private def listOfValues(valStr: String) = {
        for (j <- 0 until valStr.length()) yield {
            valStr.charAt(j).toInt
        }
    }

    // 1. Convert the sequence to actual collection
    // 2. Add "mapping" to collection, example: .sum, .mkString
    private def compute(valStr: String): Int = {
        val listOfVals: List[Int] = this.listOfValues(valStr).toList
        listOfVals.sum
    }

}


Abbiamo buttato via le var e le abbiamo sostituite con val. Il codice è ora puramente funzionale. (E, tra parentesi, funzionerà molto meglio in contesti multi-threading).

Naturalmente lo stesso risultato si può ottenere con C#:

class Immutable
{
    private readonly String tString;

    public Immutable(String testString)
    {
        this.tString = testString;
    }

    public int GetSum()
    {
        return this.CharList().Sum();
    }

    private IEnumerable<int> CharList()
    {
        foreach (char ch in this.tString)
        {
            yield return (int)ch;
        }
    }
}

sabato 22 dicembre 2012

Masterizzare e montare una ISO su Windows 8

Windows 8 supporta nativamente il formato ISO, cosicché è possibile sia montare un'immagine ISO come drive virtuale, sia masterizzarla su CD/DVD/BluRay.

ATTENZIONE: se si è installato un software che gestisce i file .ISO (ad esempio WinZip o Demon Tools), le opzioni per la gestione dei file ISO non sono più visibili da menù contestuale. Occorre modificare le impostazioni dei software di cui sopra, per togliere l'associazione con i file .ISO.

PER MONTARE UN FILE .ISO

Clickare con il tasto destro del mouse sul file .ISO e selezionare "Monta". Il nuovo drive apparirà tra le risorse del computer.




PER MASTERIZZARE UN FILE .ISO

Per prima cosa inserire un disco CD/DVD/BluRay vuoto nel masterizzatore. Quindi clickare con il tasto destro del mouse sul file .ISO e selezionare "Masterizza immagine disco". Il disco verrà masterizzato con i contenuti del file immagine .ISO












lunedì 22 ottobre 2012

Creare un'app per Google Chrome


Piuttosto sorprendentemente, non esiste in tutto il Chrome Web Store, un'app che aggiunga al browser di Google, la ricerca delle immagini attraverso il motore Google stesso.

Detto fatto, ne facciamo una noi. Con un solo, piuttosto importante limite: non potremo distribuirla sullo Store, poiché il sito in questione appartiene a Google.

La nostra "app" apparirà nella "Nuova Scheda" di default del browser, e assomiglierà all'icona col cerchio intorno:


Un "app" per Chrome è nel nostro caso - cioè se vogliamo tipicamente rendere un link - molto semplicemente l'unione di un file manifesto e di un'icona.

L'icona la potete scegliere liberamente tra le molte disponibili su Internet. Io ho scelto questa. Scaricatela come PNG e salvatela col nome di icon.png.

Create una cartella sul Desktop e nominatela "ImageSearch".

Adesso, occorre aprire un editor - a me ultimamente piace molto Sublime Text, ma il Notepad o Vim può andare lo stesso, e copiare il seguente testo.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{

"name": "ImageSearch",
"version": "1.1",
"manifest_version": 2,
"description": "Google Images",

"icons": 
{
"128": "icon.png"
},


"app": 
{
"urls": ["http://www.google.net/"],
"launch": 
{
"web_url": "http://www.google.it/imghp?hl=it&tab=wi"
}
},

"permissions": [ "http://www.google.it" ]

}

Infine, salvate il testo di cui sopra come "manifest.json". (Notate che nella sezione "urls" ho messo un indirizzo falso. Questo serve se voleste pubblicare la app su un sito di vostra appartenenza).

Per usare l'app, basta aprire il Menù di Chrome (il tasto a destra a fianco della URL) e scegliere Strumenti/Estensioni.

Dopo aver spuntato l'opzione "Modalità Sviluppatore", si clicka su "Crea Pacchetto Estensione". A questo punto basta dare in input la directory che contiene il file json e l'icona, e il gioco è fatto.


venerdì 31 agosto 2012

Come ti rimpiazzo iGoogle


iGoogle è stato la mia home page per quasi dieci anni. Mi ci trovavo molto bene. Era veloce, gradevole da vedere, aveva la toolbar di search di Google (fondamentale) e insomma tutto quello che secondo me la home page deve avere.

iGoogle

Dopo anni di ottimizzazioni varie, ci avevo messo dentro tutte le cose che volevo vedere dal Web appena collegato. Per esempio ci avevo messo:
  • News feed dei principali giornali italiani (Corriere, Repubblica, Sole 24 Ore)
  • Feed dei principali siti di gaming (Kotaku, Gamespot...)
  • Feed dei principali siti di programming (MSDNStackOverflow, CodeProject...)
  • Un traduttore online (il migliore: Google Translate)
  • Il meteo di Milano e dintorni
  • Una lista dei miei cinque link web preferiti
  • I blog miei e dei miei amici
  • Ultimi tweet che seguo
Cosa invece volutamente non ci avevo messo:
  • News feed sportive (terribili se per caso ho un evento "in registrazione")
  • Mail (troppo disturbo: meglio andarci di proposito)
  • Facebook (come sopra)
Poi improvvisamente una tragica notizia: iGoogle chiude! Pare che sarà a Novembre (2013, v.commenti), comunque è irrevocabile, han detto quelli di Google che chiude.

Così ho cominciato a guardarmi intorno per rimpiazzarlo, e ogni prova che facevo mi convinceva che iGoogle era meglio. Ad esempio ho provato:
Nessuno mi soddisfaceva. Allora ho cominciato a riflettere: ma insomma, cos'ha iGoogle di così speciale? O meglio, cosa deve avere una Home Page per essere una buona Home Page?

Fondamentalmente deve avere 3 cose:
  • Una toolbar di search (quella di Google va benissimo)
  • Link ai siti utili (Translate / Calendar / Mail...)
  • News dal mondo
Poi mi sono reso conto di una cosa: i primi due punti sono implementati direttamente dalla quasi totalità dei browser moderni. Ad esempio in Chrome la toolbar che mostra la URL di un sito, è anche una toolbar di ricerca in Google. Sempre in Chrome, la Home Page di default è una collezione di icone (apps) che portano ai siti di maggior interesse: ad esempio la mia è così:


Le "news dal mondo" sono sostanzialmente dei feed RSS. Quindi mi rimaneva solo da scegliere un buon "news reader", cioè un programma che mi mostrasse i feed RSS nel modo giusto, cioè che mi permettesse di categorizzarli (news, gaming, programming, blog...) e visualizzarli in modo piacevole.

Ne ho provati un po'. Google Reader è un po' troppo spartano, altri erano troppo "barocchi" o mancavano di funzionalità. Alla fine ho scelto Feedly e lo trovo perfetto (un po' ostica l'interfaccia utente, ma dopo qualche tentativo si riesce a fare quello che si vuole). Ecco la mia page di News:


In definitiva così ho rimpiazzato iGoogle: il browser Chrome mi toglie la necessità di partire da un sito di ricerca come Google. Come Home Page (e New Tab) ho la pagina di apps di Chrome che mi porta alla mail, a Facebook, a quant'altro mi interessa; infine per leggere le news clicko su Feedly, anch'esso disponibile come "app" di Chrome.





venerdì 24 agosto 2012

Convenzione invece che Configurazione


Una delle rivoluzioni silenziose più importanti degli ultimi anni in informatica è l'avvento di strumenti, linguaggi e sistemi che sposano il concetto di

Convention over Configuration (CoC)

ovvero, in italiano, potremmo dire: seguire una convenzione piuttosto che configurare.

I più eclatanti risultati di questa impostazione - ovviamente solo tra quelli che ho potuto provare - sono, ad esempio:

  • Maven
    Un tool di management dei sorgenti, che effettua l'organizzazione e la compilazione del codice e della documentazione di un progetto software
  • Ruby On Rails
    Un famoso framework per scrivere applicazioni Web data-intensive.
  • SBT
    Un tool per la compilazione di codice sorgente in Scala (e non solo...)

Che cos'hanno di speciale questi oggetti software che implementano la CoC? Be' è presto detto: funzionano "da soli" come per magìa, senza bisogno di:

  • parametri a linea di comando
  • file di configurazione

Li scarichi, li lanci, e funzionano. Così, senza far niente, magicamente appunto! Chiaramente, dopo una prima fase in cui il tool si comporta in default, è sempre possibile arricchire e dettagliare in modo che esso faccia esattamente ciò di cui si ha bisogno.

Faccio un esempio. Comincio a scrivere il mio codice in Scala, un progettino, niente di che, ma comunque un bel po' di file sorgenti e documentazione. Ho bisogno di compilare, e scelgo un tool CoC come SBT. Lo scarico e lo lancio, così, nudo, senza alcun parametro!

> sbt

  1. Come prima cosa, SBT si rende conto che gli mancano delle librerie per partire. Ok, le scarica tutte dalla rete e le installa.
  2. Poi vede che non ho l'ultima versione di Scala: me la scarica e la mette "a fianco" alla versione che uso io.
  3. Si accorge che l'ho lanciato in una directory che contiene codice Scala: fa il parsing dei sorgenti e individua il file che contiene il metodo principale (Main)
  4. Compila tutti i miei file 
  5. Trova le dipendenze (Scala e Java), le compila e le mette in una directory di libreria
  6. Esegue il mio programma compilato!
Fantastico, no?

Cos'ho fatto io per permettere a SBT di funzionare così bene? Nient'altro che seguire delle "convenzioni": ad esempio, ovviamente, i miei file in Scala hanno estensione .scala, ma non molto più di questo.

Allo stesso modo, se scarico Ruby On Rails e ho il database Pippo, mi basta lanciare:

> rails pippo

perché "lui" mi sondi il database e mi costruisca un sito Web completo con tutte le funzioni di front-end per gestire il DB Pippo.

In maniera analoga, Maven, è in grado di scandagliare un progetto in Java, identificare le dipendenze, scaricarle da Internet, aggiornare il sistema e infine compilare e lanciare il progetto. Basta ovviamente che io segua delle "convenzioni" (ad esempio, le librerie sono in una directory /lib).

Questo è il futuro dei tool per lo sviluppo software, e sempre maggiormente la comunità di sviluppatori si aspetterà di avere a che fare con sistemi CoC che funzionano bene out-of-the-box, senza dover leggere quintali di documentazione o seguire passo passo noiosissimi esempi.



lunedì 30 luglio 2012

Non molto Agili... fin qui!

Navigando sul sito http://agilemanifesto.org mi sono accorto che sono passati otto anni da quando firmai il manifesto sullo sviluppo agile.



Cos'è successo in questi otto anni? Si fa un gran parlare, è vero, delle tecniche di sviluppo agili e termini come Scrum ed eXtreme Programming sono molto di moda, ma di fatto nella realtà enterprise - specie in quella italiana - continuano a non vedersi progetti sviluppati secondo la filosofia Agile dello sviluppo del software. Viceversa, nel mondo Open Source, l'Agile è di fatto la norma.

Spesso si vedono applicate le tecniche agili, come ad esempio Pair programming o Feature Driven Programming, ma in contesti che sono quelli tradizionali, e cioè quelli dello sviluppo waterfall, che nella realtà enterprise è tuttora l'unico modello supportato.

Frequentemente ho proposto di utilizzare un approccio Agile in diversi progetti reali, ma al di là di un qualche superficiale apprezzamento non si è mai andati.

Perché dunque, nonostante l'entusiasmo, specie degli addetti ai lavori, la metodologia Agile non ha preso piede? Io credo che le cause siano principalmente tre.

1. Il sistema non recepisce processi iterativi

Quello che caratterizza principalmente l'approccio Agile rispetto al Waterfall è il suo essere iterativo by design. Il progettista Agile sa che lo sviluppo software è spesso un processo "prima volta-primo uso", caratterizzato da un altissimo grado di incertezza, per affrontare il quale deve applicarsi una metodologia di gestione del rischio che non può che essere iterativa. L'iterazione tipica dell'Agile è quella indicata in figura:


Normalmente, in un progetto complesso, le iterazioni possono essere decine. Ma il "sistema" non è in grado di gestire le iterazioni! Se da una parte il Cliente vuole subito sapere quanto costerà il suo nuovo sistema informativo e quanto durerà il suo sviluppo, anche dall'altra il Fornitore ha tutta una serie di strumenti che funzionano solo se vengono immessi valori "a preventivo": quante risorse il progetto occuperà e per quanto tempo. Come ho riportato in altri post, la stima del costo (tempo, denaro e altre risorse) di un progetto "prima volta-primo uso" è un esercizio di fantasia destinato al fallimento. Tipicamente perciò chi fornisce un servizio di sviluppo software applica dei coefficienti di rischio molto alti proprio per cercare di assorbire questa incognita. Di fatto, nei sistemi dove è "necessaria" una stima dei costi a preventivo, il metodo Agile è escluso a priori.


2. Un processo che ricicla è considerato un processo di "serie B"

Nella concezione del Project Management classico,  il "riciclo" - quindi la re-iterazione - è considerato come un "difetto", o meglio come la "conseguenza di un difetto". Il progetto perfetto non presenta ricicli: viene eseguito così com'era stato pensato la prima volta. Per chi non possiede una cultura informatica (direi, una cultura informatica recente) l'idea stessa che una metodologia preveda molti ricicli è semplicemente orrenda. E' orrendo dover immaginare di avere stime riviste, nuove implementazioni e nuovi test ad ogni riciclo. Impensabile immettere ad ogni nuova iterazione nuove funzioni e quindi nuovi bug! Il Cliente percepisce il metodo Agile come una mancanza di professionalità (non sviluppano: provano a sviluppare!) e lo staff non tecnico del Fornitore la percepisce come una intollerabile mancanza di certezze: quanto ci costerà il progetto, quante risorse impiegherà e per quanto tempo.
Bisogna però fare i conti con la dura realtà: che è tanto più vera e documentata quanto più i progetti aumentano in complessità e novità: all'inizio nessuno può sapere quanto costerà il progetto, nemmeno a grandi linee. Si possono fare delle stime, sulle quali però non può essere calcolato il prezzo al Cliente. Proprio per la grande aleatorietà di queste stime "a-priori", il prezzo sarà o largamente esagerato per assorbire il rischio, o sottostimato destinato cioè ad andare in perdita. Come dicevo, i sistemi (finanziari, di controllo e gestione e via dicendo) aziendali prevedono che questo prezzo venga calcolato all'inizio, sulla base del quale verranno poi derivati tutti i driver economici dell'azienda. Un calcolo basato, il più delle volte, sulla fantasia.


3. La metodologia Agile presuppone il Time&Materials

Esistono tipicamente due modi per vendere un servizio informatico: a pacchetto (turn-key o fixed bid) o a tempo (time&materials, T&M). Nel primo, chi offre "scommette" su quanto effettivamente gli costerà il servizio: applica alla scommessa il proprio coefficiente di profitto e ottiene il prezzo. Nel secondo, semplicemente vengono erogati dei servizi e il Cliente paga "il tempo" di erogazione.
Per quanto abbiamo detto sin qui, la metodologia Agile presuppone la seconda opzione. Perché per poter vendere qualcosa turn-key occorre essere confidenti sulla stima dei costi, cosa che abbiamo visto è molto difficile nel caso di progetti complessi. E perchè l'Agile è iterativo di suo.
Il committente di un progetto informatico complesso è molto poco propenso a iniziare a lavorare T&M, perché anche lui deve fornire una stima di quali saranno i suoi costi/tempi, e questo a priori! La naturale conseguenza di questo stato di cose è che si formulerà un'offerta turn-key molto sovrastimata nei costi, ed esageratamente lunga nei tempi.


Io credo che queste tre siano le cause principali che hanno bloccato l'introduzione dei modelli Agili nella pratica dello sviluppo software a livello enterprise. Sono convinto che un approccio iterativo e T&M possa permettere significative economie sia per chi vende, sia per chi compra soluzioni software. Tuttavia, perché lo sviluppo Agile possa essere effettivamente utilizzato, occorrono notevoli cambiamenti in termini di cultura, processi e strumenti di supporto aziendali.



venerdì 13 luglio 2012

Ajax + Prototype + CoffeeScript

In rete abbondano gli esempi CoffeeScript per chiamate Ajax con la libreria jQuery. Se uno - come me - preferisce Prototype, è abbandonato al proprio destino.

Perciò pubblico qui sotto l'esempio di una pagina CoffeeScript con chiamate Ajax in Prototype.

//= require prototype

pe = null

invitations_args =
  method: 'get'
  onSuccess: (transport) ->
    inviter = transport.responseText
    if inviter.length > 1
      $('invitation').show()
      $('proposal').update
             (inviter + ' invites you to join a game:')
      pe.stop()
      return
  onFailure: ->
    $('invitation').show() 
    $('proposal').update('Error retrieving invitation')
    return

invitations = ->
  new Ajax.Request 
      '/player/lookforinvitations', invitations_args
  
main_loop = ->
  pe = new PeriodicalExecuter( invitations, 3 )

Event.observe(window, 'load', main_loop)


La parte principale (main_loop) è invocata sull' onLoad della pagina HTML. Qui, un PeriodicalExecuter esegue una chiamata Ajax ogni tre secondi ad un metodo (/player/lookforinvitations) che cerca se sul database qualcuno ci ha invitato a giocare. Se sì la pagina mostra un messaggio: ad esempio: Pippo ti invita a giocare con lui, e ferma il processo PeriodicalExecuter. Altrimenti la pagina continua ad inviare richieste Ajax al server finchè l'utente non cambia pagina.

(Una cosa interessante e che mi ha fatto perdere molto tempo è che anche in CoffeeScript l'ordine in cui vengono definite le funzioni è importante!! Se mettete ad esempio Event.Observe all'inizio del file, otterrete un errore di oggetto undefined: l'oggetto in questione è main_loop, che viene definito solamente più sotto!)




mercoledì 11 luglio 2012

CoffeeScript e le var locali


CoffeeScript è un linguaggio moderno, sintetico ed efficace che compila in JavaScript. Nei progetti web complessi, l'uso di CoffeeScript si sta via via imponendo, perché rende la creazione e la manutenzione del codice lato client molto più veloce e snella.

Una delle prime difficoltà, tuttavia, che si incontrano quando si comincia ad usare CoffeeScript è il fatto che per convenzione tutte le variabili (e quindi anche le funzioni, che in CoffeeScript sono anonime e associate ad un nome di variabile) sono locali.

Un esempio può chiarire meglio. Supponiamo di avere questa semplice pagina in HTML5:

<!DOCTYPE html>
<html>
<head>
    <title>CoffeeScript Palestra</title>
    <link rel="stylesheet" href="css/main.css">
    <script src="js/vendor/jquery-1.7.2.min.js"></script>
    <script src="js/script.js"></script>
</head>
<body>
    <h2>CoffeeScript Scripts</h2>
    <p>Premi <a href="#" onclick="run()">qui</a></p>
    <div id="pippo">&nbsp;</div>
</body>
</html>

Se l'utente preme il link "qui" vogliamo che accada qualcosa, ad esempio compaia la scritta "Ciao Mondo!"

La prima idea che ci viene in mente è quella di scrivere due funzioni, una che ritorna "Ciao Mondo" e una che aggiorna il contenuto del DIV "Pippo" appunto con "Ciao Mondo", in questo modo:

# COFFEESCRIPT SCRIPTS

run = ->
  $("#pippo").html(helloworld)
  null


helloworld = -> 'Ciao Mondo!'

Mettiamo questo codice nel file "script.coffee" e poi lo compiliamo con CoffeeScript. Otterremo script.js che viene poi richiamato dal nostro file HTML (sotto la riga che carica JQuery).

Peccato che una volta eseguito il tutto, quando l'utente preme "qui", non accade nulla.

Il motivo è che il compilatore CoffeeScript traduce le due funzioni "run" e "helloworld" come funzioni locali, quindi di fatto invisibili all'esterno dello stesso codice. Ecco il codice compilato:

// Generated by CoffeeScript 1.3.3
(function() {
  var run, helloworld;

  run = function() {
    $("#pippo").html(helloworld);
    return null;
  };

  helloworld = function() {
    return 'Ciao Mondo!';
  };

}).call(this);

E' giusto che sia così: infatti per evitare conflitti di nomi e variabili globali che rimangono inutilmente appese, mentre in JavaScript è buona norma dichiarare tutto con "var", in CoffeeScript questa diviene la regola.

Per "esportare" il nome di una variabile all'esterno si può agire in diversi modi. Quello che personalmente preferisco è di associare allo spazio dei nomi dello script un nome che espliciti la sua funzione di "esportatore" (ad esempio: exports), e poi di dichiarare le variabili da esportare come appartenenti a questo spazio.

# COFFEESCRIPT SCRIPTS

exports = this

exports.run = ->
  $("#pippo").html(helloworld)
  null


helloworld = -> 'Ciao Mondo!'

In questo modo, la funzione run() - o meglio, la variabile 'run' associata alla funzione anonima - diventa visibile all'interno del nostro file HTML e perciò direttamente utilizzabile.


// Generated by CoffeeScript 1.3.3
(function() {
  var exports, helloworld;

  exports = this;

  exports.run = function() {
    $("#pippo").html(helloworld);
    return null;
  };

  helloworld = function() {
    return 'Ciao Mondo!';
  };

}).call(this);


Come conseguenza non banale, le funzioni ancillari come per esempio la 'helloworld', non vengono esposte, diventando di fatto 'private'.

giovedì 5 aprile 2012

Perle di Gantt

I fautori delle teorie di Project Management, i vari aficionados dei diagrammi Gantt e CPM che ogni azienda come si deve sparacchia su vecchi template Powerpoint per giustificare ogni tipo di decisione, dovrebbero rileggersi con attenzione queste parole che Henry Gantt, che fu tra i padri delle moderne teorie di programmazione e inventore del diagramma omonimo, scrisse nel 1900:

  "La programmazione è una scienza empirica 
basata su teoremi inesatti 
che sviluppa algoritmi approssimativi
 costruiti su ipotesi sommarie. 
Le persone che la praticano
 tentano di concretizzare l’astratto 
attraverso l’impossibile. 
Per fare programmazione 
non è necessario essere pazzi, 
ma il fatto di esserlo aiuta"

venerdì 9 marzo 2012

Un font monospace per Linux

Uno dei problemi "storici", diciamo così, di Linux, è che i suoi font di default sono mediamente bruttini.

La situazione si fa più drammatica quando uno in Linux ci programma. Stare ore davanti a un font brutto e per di più sfocato non è piacevole.

Ecco dunque la mia personalissima scelta come pretendente al titolo di miglior font monospace su Linux. E il vincitore è....

  • Droid Sans Mono

Ecco uno screenshot da Eclipse (Linux Mint 12):

Esempio di font 'Droid Sans Mono' sotto Linux Mint

mercoledì 29 febbraio 2012

Smascherare il phishing

Subiamo un tentativo di phishing quando riceviamo una e-mail che:


  • pretende di arrivare da un'istituzione di qualche tipo (finanziaria, commerciale)
  • contiene un link fasullo che ci porta su un sito sul quale ci viene chiesto di inserire qualche dato privato (ad esempio: una username e una password)


Normalmente queste mail sono studiate per catturare la nostra attenzione, dicendo ad esempio che il nostro account di banca, carta di credito, o altre forme di pagamento è stato bloccato, per cui "è urgente" fare qualcosa, cioè clickare sul link fasullo.

Una volta clickato il link, arriviamo su una pagina di un sito costruito per "sembrare" il sito dell'istituzione, ci viene chiesto di inserire la nostra password e il gioco è fatto: così rubano le password di accesso, che useranno in seguito per azioni fraudolente.

Fortunatamente è facile smascherare un tale tentativo di phishing. Ecco come.

Questa di seguito è l'immagine di un'e-mail di phishing:



Gli elementi ci sono tutti:


  •  la mail sostiene che "qualcosa di grave è successo": è stato "bloccato" l'account della carta di credito
  • c'è un link per "fare qualcosa per aggiustare la situazione"


Primo indizio - le banche non mandano e-mail
Nessuna istituzione seria (banche, carte di credito, siti commerciali) ci invierà mai una mail che contiene il link ad un sito. Proprio per evitare tentativi di phishing, tutte le mail che riceviamo da enti seri, non contengono link. Casomai l'invito a collegarsi autonomamente al loro sito. Ma, in generale, nessuna mail NON RICHIESTA ci verrà mai inviata.

Secondo indizio - orrori ortografici
Tutte le e-mail di phishing contengono orripilanti errori di italiano, perchè normalmente sono la "traduzione automatica" di analoghe e-mail in inglese. Leggiamo attentamente: 'Si prega di non utilizzare il link all'interno di questa e-mail a ripristinare un altro conto di quanto il tuo' oppure 'Si prega di seguire attentamente le nostre indicazioni e sarà in grado di ripristinare l'accesso al conto in pochi minuti'...

Terzo indizio - link fasulli
Come funziona il phishing? Cercando di portare la persona su un sito che "finge" di essere ciò che non è. E' facile in HTML dire che un link porta da una parte, quando invece porta da un'altra. Però è anche facile capirlo: basta posizionare il mouse sul link stesso per controllare che il link porti veramente dove dice di voler portare: la freccia in verde indica "dove" il link finge di volerci portare (su www.cartasi.it) e quella in blu dove ci porta veramente (su wiki.tenfor..com)



Quarto indizio - sender fasullo
Lo stesso giochetto viene applicato al sender della mail. La mail dice di essere stata spedita da CartaSi S.p.A. Ma se guardiamo bene nei dettagli scopriamo che invece è stata spedita da e-vendax.pop.com.br


Normalmente, in un tentativo di phishing questi indizi sono sempre presenti. Ovviamente: mai clickare sul link, e men che mai inserire informazioni personali (come username, password e numero conti) su siti che non abbiamo raggiunto "volontariamente" - ad esempio partendo da un bookmark del browser.

Cosa fare, infine quando si riceve una e-mail di phishing? Sicuramente segnalarlo al provider, in questo caso GMail:




Inoltre, è sempre possibile avvisare dell'avvenuto tentativo di truffa la sezione locale della Polizia Postale, che in Italia si occupa anche di reati informatici.

giovedì 23 febbraio 2012

Pensare in REST (Thinking in REST)

La progettazione di applicazioni Web based ha subìto una silenziosa rivoluzione quando nel 2000 Roy Fielding ha pubblicato la sua ormai celebre dissertazione dal titolo: "Architectural Styles and the Design of Network-based Software Architectures", e in particolare il capitolo cinque: "Representational State Transfer (REST)".

In cosa consiste questa rivoluzione? Esiste una modalità, diciamo così, "classica" di concepire un'applicazione per computer, e questa prevede la composizione di un algoritmo più o meno complesso che prende in input una serie di dati, li trasforma e poi li rende persistenti - ad esempio salvandoli su un database. L'essere umano interagisce con l'applicazione attraverso una "interfaccia utente" che viene aggiornata a seconda del cambiamento di stato - o dell'input o dell'output. Così, in modo appunto "classico", un'applicazione è costituita di un'interfaccia utente, una logica, e uno stato - cioè dei dati persistenti.

Le prime applicazioni Web complesse, rese possibili dalle primigenie tecnologie di trasformazione dinamica dell'HTML, lato server con ASP o PHP ad esempio e lato client con DOM/Javascript, implementavano questo modello classico. Vale a dire, presentavano all'utente un'interfaccia grafica con la quale inserire i dati, offrivano una serie di comandi associati a una logica di esecuzione, e infine persistevano i risultati su un database.

Il problema di questo approccio è che l'applicazione diventa un monolite che si può utilizzare solamente nel modo in cui è stata inizialmente concepita.

Con l'aumentare delle necessità di servizi Web, con l'aumentare dei device eterogenei che vi accedono - dai computer ai telefonini, dai videogiochi alle lavastoviglie - questo tipo di approccio è diventato controproducente: l'applicazione monolitica impedisce di utilizzare i dati e le informazioni che è in grado di veicolare appunto perché è concepita per essere utilizzata in un solo modo, che è quello inizialmente concepito dai suoi autori. La conseguenza di tutto ciò è che ogni nuova esigenza di accedere ad un dato o ad un servizio veicolato dall'applicazione necessita di un cambiamento nel codice applicativo o, peggio, nella creazione di una nuova applicazione ad hoc.

Oggi le aziende spendono moltissime risorse IT proprio perché hanno a che fare con applicazioni monolitiche che non riescono a "servire" il dato in maniera abbastanza neutra.

L'idea alla base del protocollo REST inventato da Roy Fielding è che le applicazioni Web devono essere progettate in modo tale per cui immettendo direttamente le URL (che così diventano URI) su un browser si ottengano immediatamente i dati che servono, e che queste URL possano essere "combinate" tra loro in un workflow per ottenere un'applicazione, allo stesso modo con cui nelle architetture SOA noi combiniamo i "servizi" per ottenere sempre nuove applicazioni.

La URL così richiamata deve essere in grado di rispondere in formato "neutro", possibilmente veicolando solamente "i dati", senza cioè alcuna informazione "grafica" di supporto. Le URL stesse devono specificare il formato dei dati che richiedono: se la URL finisce per ".xml" il dato verrà restituito in XML, per ".json" in JSON, e, naturalmente, di default rispondere con un HTML human readable.

Per finire un esempio. Supponiamo di scrivere un videogioco Web, magari per Facebook. Avremo da qualche parte una struttura dati che prende tutte le informazioni relative al giocatore (Player). Questa struttura dati raccoglie e persiste lo "stato" del giocatore durante il gioco. La modalità classica consiste nello scrivere un'applicazione che, a seconda dei comandi dati via web dal giocatore, cambia lo stato e aggiorna di conseguenza la tabella "Player". Esagerando, l'applicazione potrebbe essere costituita da un'unica "pagina" che, a seconda del comando HTTP ricevuto, risponde in un modo o in un altro. Ovviamente, così facendo, nessuno, ad esempio, potrebbe costruire un altro gioco a partire dai dati correnti dei giocatori: perché le informazioni di stato dei giocatori sono "chiuse", e utilizzabili solo dalla "pagina" di cui parlavamo prima.

Se volessimo applicare il protocollo REST all'entità "Giocatore" (Player), come prima cosa dovremmo definire le "URL" che accedono a ciascuna informazione del giocatore, e le URL che vanno a modificare lo stato del giocatore stesso. Ad esempio:

GET    /player/list(.:format)        player#list
POST   /player/list(.:format)        player#list
GET    /player(.:format)             player#index
POST   /player(.:format)             player#create
GET    /player/new(.:format)         player#new
GET    /player/:id/edit(.:format)    player#edit
GET    /player/:id(.:format)         player#show
PUT    /player/:id(.:format)         player#update
DELETE /player/:id(.:format)         player#destroy

Questa tabella fornisce un verbo HTTP e una URL associata. Queste URL, se chiamate con il rispettivo verbo HTTP, sono già in grado di descrivere le funzionalità di base con cui l'utente può ottenere le informazioni sui giocatori! La prima fornisce una lista dei giocatori, la seconda modifica la lista, la terza ottiene informazioni generiche, la quarta e la quinta inseriscono nuovi giocatori, la sesta permette di modificare i dati di uno specifico giocatore e via dicendo...

Se chiamo /player/list ottengo una pagina HTML, /player/list.json un array di giocatori, /player/list.xml un documento XML. Applicazioni sempre diverse accedono agli stessi dati in maniera omogenea. In questo modo, se l'applicazione è ben scritta, sarà sempre possibile immaginare nuovi modi per accedere ai dati, e produrre applicazioni nuove senza dover modificare il codice lato server.

Chiaramente, progettare un'architettura Web in modalità REST comporta un ribaltamento del modo di pensare: invece che partire dalle esigenze "funzionali", bisogna partire dai dati, e dal modo con cui si può manipolarli. Ma il vantaggio di farlo fin dall'inizio, con disciplina, produrrà significativi risparmi nella gestione evolutiva dell'applicazione, e darà l'opportunità di costruire nuovi modi d'uso di applicazioni esistenti praticamente senza sforzo.

Oggi esistono molti framework che producono applicazioni Web RESTful. Il più famoso è "Ruby On Rails". Seguono "Bowler" per Scala, "Jersey" per Java. E molti altri stanno nascendo.


martedì 24 gennaio 2012

Interoperabilità tra Scala e Java

Scala è interoperabile con Java, poiché entrambi i linguaggi producono Java bytecode. Questo significa che tutte le seguenti frasi sono vere:
  • Codice Scala può essere eseguito da una Java Virtual Machine
  • Codice Java può essere "visto" da codice Scala
  • Codice Scala può esserre "visto" da codice Java
Supponiamo di avere ad esempio la seguente classe di business in Scala, una generica struttura che rappresenta l'astrazione di un numero razionale. E' costruita passando numeratore e denominatore, ad esempio Rational(2,3) è due terzi (2/3).
 package net.alessiosaltarin.rationals  
   
 class Rational(n: Int, d: Int) {  
   require(d != 0)  
   
   private val g = this.gcd(n.abs, d.abs)  
   val numer: Int = (n / g)  
   val denom: Int = (d / g)  
   println("Created " + this.toString())  
   
   def this(n: Int) = this(n, 1)  
   
   override def toString = this.numer + "/" + this.denom  
   
   def +(that: Rational): Rational =  
     new Rational(  
       this.numer * that.denom + that.numer * this.denom,  
       this.denom * that.denom)  
   
   def *(that: Rational): Rational =  
     new Rational(this.numer * that.numer, this.denom * that.denom)  
   
   private def gcd(a: Int, b: Int): Int =  
     if (b == 0) a else gcd(b, a % b)  
 }  
   
 object RationalComputer {  
   
   def performSum(r1: Rational, r2: Rational): String =  
     (r1 + r2).toString()  
   
   def performMultiply(r1: Rational, r2: Rational): String =  
     (r1 * r2).toString()  
   
 }  
   
 object RationalFactory {  
   
   def create(rationalStr: String): Rational =  
     {  
       val indexOfSlash = rationalStr indexOf '/'  
       val n = nrParse(rationalStr.substring(0, indexOfSlash))  
       val d = nrParse(rationalStr.substring(indexOfSlash + 1))  
       new Rational(n, d)  
     }  
   
   private def nrParse(nstr: String): Integer = Integer.parseInt(nstr)  
 }  
Se vogliamo offrire a questo codice una user interface, che non sia Web, abbiamo ben poche possibilità, se vogliamo rimanere nell'ambito di Scala, e cioè quelle di usare il wrapping delle librerie Swing scritto in Scala, vale a dire: http://www.scala-lang.org/api/current/scala/swing/package.html Il problema di questo approccio è che alla data di questo post manca totalmente un editor visuale che generi in output un codice Scala. Quello che abbiamo, invece, sono degli editor visuali che generano codice Swing in Java, ad esempio:
  • Netbeans Matisse
  • Eclipse Visual Editor
La buona notizia è che, stanti le premesse di cui sopra, codice Scala può essere visto da Java come se fosse una "libreria" esterna (e viceversa, tra l'altro). Possiamo infatti pensare di realizzare un'interfaccia di questo tipo:
attraverso l'editor visuale che preferiamo, generare il codice Java equivalente, e poi eseguirlo. Per farlo possiamo seguire due approcci, entrambi validi: eseguire dalla macchina virtuale Scala il codice Scala e il codice Java interpretarlo come bytecode esterno, oppure eseguire da una qualsiasi macchina virtuale Java il codice dell'interfaccia grafica e da questo richiamare il bytecode compilato da Scala come una libreria esterna. Chiaramente, è il secondo approccio quello più interessante. Infatti nella pratica avremo a disposizione macchine virtuali Java, ottimizzate a seconda dell'uso. Perché questo approccio sia percorribile, occorre costruirsi un proxy Java in grado di richiamare il codice di business in Scala. Il proxy conterrà i metodi richiamati direttamente dall'interfaccia - nell'esempio, il pulsante di 'esegui operazione'. Ad esempio:
 package net.alessiosaltarin.javaproxy;  
   
 import net.alessiosaltarin.rationals.Rational;  
 import net.alessiosaltarin.rationals.RationalFactory;  
 import net.alessiosaltarin.rationals.RationalComputer;  
   
 public class ProxyLogic  
 {  
   public static String performOperation(Operation op,   
                           String rationalOne,   
                           String rationalTwo)  
   {  
     Rational r1 = RationalFactory.create(rationalOne);  
     Rational r2 = RationalFactory.create(rationalTwo);  
     String result;  
       
     switch (op)  
     {  
          case ADD:  
          default:  
               result = RationalComputer.performSum(r1, r2);  
               break;  
                 
          case SUBTRACT:  
               throw new UnsupportedOperationException();  
                 
          case MULTIPLY:  
               result = RationalComputer.performMultiply(r1, r2);  
               break;  
                 
          case DIVIDE:  
               throw new UnsupportedOperationException();  
     }  
       
     return result;  
   }    
 }  
Il codice sopra richiama il codice Scala - il namespace
net.alessiosaltarin.rationals.Rational
Come fa? Semplicemente lo trova nel percorso del codice compilato come Java bytecode, a patto di avere la libreria Scala
scala-library.jar
nel classpath corrente. Supponendo che la classe RationalGUI sia quella generata dal tool visuale, il codice eterogeneo Scala/Java verrà eseguito dalla JVM in questo modo:
java -cp scala-library.jar;[jre,...] net.alessiosaltarin.javaproxy.RationalGUI
Utilizzando ad esempio Eclipse, è possibile aprire due progetti, uno in Scala e uno in Java, e in quello Java che contiene il metodo main, referenziare come libreria esterna il codice Scala custom e la libreria scala-library.jar.