venerdì 24 giugno 2011

Fammi ripetere con parole mie

Come Software Architect, la lezione più preziosa è stata imparare che io e lo sponsor del progetto - o meglio, si dovrebbe dire gli stakeholder - parliamo lingue differenti.

Abbiamo del resto una formazione differente, esperienze differenti, e significative difformità nei punti di vista.

Per questo la chiave del successo di un progetto software, oggi, è la chiarezza di comunicazione tra chi fornisce la tecnologia - l'Architect, appunto - e chi intende utilizzarla per raggiungere i suoi scopi di business.

Ecco perché è fondamentale che l'Architect si chieda sempre: ho capito quali sono gli obiettivi di questo progetto? Esiste uno strumento formidabile: dopo aver letto un documento, aver partecipato a una riunione, avere ascoltato le parole degli stakeholder, fermarsi un attimo e dire: "Ok, ora fammi ripetere con parole mie". Vediamo cosa ho capito davvero.

Altrettando fondamentale è chiarire fin dall'inizio che cosa la tecnologia può offrire, e che cosa non può offrire. E' bene fin da subito spianare il campo da miti e leggende. (E lo so che è difficile: è bello all'inizio avere uno sponsor che ci guarda come Bilbo Baggins guardava Gandalf nello Hobbit!)

Direi quindi che sono due le chiavi importanti per il successo di un progetto software enterprise:

1) Voglio capire bene quali sono gli obiettivi da ottenere con il sistema
2) Voglio comunicare bene cosa un sistema è in grado di offrire (e cosa no)

Le questioni tecniche, i disegni architetturali, i dettagli implementativi vengono molto dopo.

venerdì 17 giugno 2011

Basta Database!

Una domanda che non fareste mai ad un Cliente, che ha un sistema informativo con un suo potentissimo sistema di RDBMS (database relazionale, normalmente Oracle o MS Sql Server), è: "Ok, ma a cosa ti serve?"

Come a cosa serve un database? (Ti guardano come un poveretto, con tanto di occhi sgranati)... Ma non lo sai che in un database ci sono tutti i dati aziendali? Ma non lo sai che è il cuore del sistema informatico? Ma non lo sai che nessuno nemmeno osa pensare di non averne uno...

Mentre sento queste cose mi aggiro curioso tra gli utenti (solitamente disperati) di un tale eccellente sistema: sono lì che combattono con infinite tabelle, piene di dati ridondanti e infinitamente inutili, che per essere tirati fuori hanno bisogno di uno stranissimo linguaggio, perlopiù incomprensibile alle logiche umane, chiamato SQL.

La maggior parte delle aziende, per cercare di tirar fuori qualcosa da quei mostri lì, compra sistemi di Datawarehouse e Business Intelligence che costano loro un ordine di grandezza in più...

Mi aggiro tra sistemisti che sognano vacanze ai Caraibi e mondi senza computer - soprattutto senza database - e tra manager che guardano fuori dalla finestra cercando di capire con quali soldi pagare l'espertone Oracle (o quello che volete) che gli risolverà il loro maggior problema, e cioè: perché ho milioni di dati inutili e non trovo mai quelli che mi servono?

A cosa serve un database? "Ad archiviare i dati". Sono scettico. "A gestire le transazioni..." ok, ci avviciniamo. "Ad estrarre dai miei dati le informazioni che servono per il mio business..." Ah no! Ecco il punto!

Il punto è che la tecnologia delle basi di dati è nata quando i computer erano relativamente lenti, soprattutto i dischi, poco capienti e le applicazioni molto costose da scrivere, perché difficili da creare e debuggare. Perciò si è inventato un sistema altamente efficace nell'archiviare i dati (scrittura) e nel recuperarli (lettura), e questo a scapito della loro intelligibilità e facilità d'uso.

Il sistema relazionale inventato da Cobb è un sistema efficace con computer poco potenti e capienti, esattamente il contrario dei computer di cui disponiamo oggi.

Oggi possiamo tranquillamente immaginare (e realizzare!) un sistema informativo complesso senza database sotto. "E come fai ad archiviare i tuoi dati?" Li scrivo sul disco, ovvio. Sì ma in che formato?

Ecco una buona domanda. Le cui risposte possono essere almeno tre, e ricoprire con ciò gran parte delle necessità di archiviazione di un'applicazione anche di media/grande complessità.

Prima possibilità: flat file. Salviamo tutti i nostri dati in file di testo in formato flat. Esempi: il win.ini, YAML, SQLite, TextDB ecc. ecc. (http://en.wikipedia.org/wiki/Flat_file_database)

Seconda possibilità: chi ha necessità di immagazzinare relazioni gerarchiche di tipo padre-figlio, o strutture fortemente innestate, può usare il formato di testo più potente in assoluto: XML. Il che è però fin troppo per la stragrande maggioranza delle applicazioni.

Terza possibilità: ok, proprio non potete fare a meno di Oracle! Almeno lasciatelo scrivere a chi lo sa fare, e voi non sporcatevi le mani. Utilizzate dunque uno strumento di ORM - object relational mapping - che ha il compito di serializzare, deserializzare e ricercare i vostri oggetti di business in un normale database relazionale.

Quest'ultima possibilità è quella secondo me più interessante, e che spero prenda piede nelle applicazioni enterprise del prossimo lustro. L'articolo che più concisamente descrive la tecnica è questo.
Seguito dall'ottima voce su Wikipedia.

In soldoni, nelle applicazioni moderne, le attività di DDL (Data Definition Language) e DML (Data Manipulation Language) debbono essere demandate ad un apposito strato software (l'ORM appunto) che le svolge al meglio e in modo "trasparente" per l'utente. In questo caso ciò che conta maggiormente nell'applicativo non è più il modello concettuale dei dati, ma il modello concettuale degli oggetti (sottinteso, di business, cioè a dire: web services, remote procedure calls e quant'altro). Il vantaggio consiste, di fatto, nella drastica diminuzione delle risorse necessarie al disegno e allo sviluppo della base dati - fino quasi ad annullarle.

Per Java, il miglior strumento ORM è senz'altro Hibernate, mentre per il mondo Microsoft è l'Entity Framework

Entrambi sono ottimi punti di partenza per dire definitivamente addio agli odiati database.

giovedì 24 marzo 2011

Testo e font sfocati in IE9 e Firefox 4

Ok, vi siete scaricati Internet Explorer 9 o Firefox 4 o superiori e, dopo un iniziale periodo di eccitazione mistica, avete pensato di avere bisogno di un nuovo paio di occhiali! "Ma sono io, o si vede tutto un po' sfocato?"

Il fatto è che i nuovi engine grafici dei browser di ultima generazione utilizzano di default - quando la trovano - l'accelerazione hardware via scheda grafica. La rappresentazione di un documento HTML non è più la commistione di font raster (cioè disegnati pixel per pixel) e immagini, ma un'unica immagine che si va componendo mentre la pagina viene renderizzata. L'effetto "sfocatura" è dovuto al fatto che i font non sono più raster, ma vettoriali, e utilizzano le primitive grafiche per essere renderizzati - proprio come accade, ad esempio, nelle applicazioni Silverlight (WPF e compagnia).

Ok, ma io adesso come faccio? E' inaccettabile che lo schermo si veda "peggio" che con IE8 o Firefox 3.

Avete due possibilità: la prima è quella di disabilitare l'accelerazione hardware, ad es. in Firefox 4 sotto Opzioni / Navigazione / Utilizza l'accelerazione hardware quando disponibile. Chiaramente con questo vi giocate una delle più importanti innovazioni dei browser di ultima generazione, cioè l'utilizzo della GPU nel rendering delle pagine, con un sostanziale aumento delle performance.

Oppure potreste fare il "fine tuning" dell'engine di renderizzazione grafica dei font vettoriali. In Windows XP andando su questo sito:

http://www.microsoft.com/typography/cleartype/tuner/step1.aspx

Invece su Vista e 7, semplicemente da Menù Start, scrivendo "Ottimizzazione caratteri Clear Type"

(Io ho seguito quest'ultima strada e sono soddisfatto, però è questione di gusti)

martedì 14 settembre 2010

Il fisico e il meteorologo o del perché i progetti IT falliscono

I progetti IT normalmente falliscono. Esiste tutta una letteratura di report e di statistiche sui fallimenti (v. rif. in calce). Quella dello Standish Group (1995 e 2009) stima una percentuale attorno al 70% di fallimenti. Più drastico Gartner Group, che in diversi report, stima attorno all'85% i progetti IT che producono ritorni negativi (ROI < 0).

Chiaramente esiste una moltitudine di risposte alla domanda "Perché i progetti IT falliscono", e molti autori forniscono la loro ipotesi. Io credo che il motivo principale sia dovuto a un errato processo di valutazione dei costi e degli effort di un progetto, dovuto a una serie di miti su come si realizza e si sviluppa un progetto informatico.

Comincerò con un aneddoto. Un fisico e un meteorologo passeggiano in un parco. Entrambi guardano il cielo. Il fisico dice al meteorologo: "Non capisco. Noi fisici siamo in grado di predire al secondo la posizione di tutti i satelliti in cielo, e voi meteorologi non siete in grado di dire se domani pioverà o meno". Il meteorologo, per nulla scandalizzato, lo guarda e gli dice: "Hai ragione! Non siamo in grado di dirlo".

Durante il mio ultimo progetto informatico ho assistito alla stessa obiezione. Siamo in una grande fabbrica di aeroplani. "Ma come" dice il Cliente al Consulente Informatico "io sono in grado di dire esattamente quanto ci metterò a costruire e a consegnare al mio cliente un aeroplano, e tu non sei in grado di dirmi quanto ci metterai a costruire il mio sistema informativo e quanto ti costerà". "Hai ragione" dice l'onesto consulente "non sono in grado di dirtelo."

La verità è che di consulenti informatici onesti - o abbastanza coraggiosi da ammettere la dura realtà - ce ne sono pochi. Quando il progetto, com'è normale, esce dal budget previsto in termini di costi e tempi, si assiste al nascere di curiosissime scuse: il costo del vendor è aumentato, i dati storici erano sbagliati, il progettista che aveva fatto le stime aveva bevuto, il nostro miglior sviluppatore è dovuto andare in maternità, il server con i sorgenti si è impastato. Scuse, scuse, giusto?

I progetti IT - tutti quelli di una certa complessità e novità - sono caratterizzati dalla legge: prima volta-primo uso. E' quasi impossibile calcolare con esattezza il costo di qualcosa che non è mai stato tentato. È così unico, così sfaccettato, e ha così tanti fronti che il numero e la dinamica delle sue variabili crea un problema insormontabile a chiunque stia cercando di valutare i suoi costi a preventivo.

Il numero di variabili e la novità sono i tratti caratterizzanti di un progetto IT. La tecnologia cambia. Gli strumenti cambiano. Le soluzioni sono diverse e nuove. Gli sviluppatori bravi usano tecnologie obsolete, quelli che usano tecnologie nuove, sono impreparati e non hanno abbastanza esperienza. Inoltre, nessuno conosce "a preventivo" che cosa sarà effettivamente sviluppato.

Paradossalmente, il modello di project-estimation e di creazione dell'offerta ancor oggi più usato in ambito consulenziale è quello "Waterfall", costituito da sei step seriali:

1. Descrizione (sommaria e vaga) dei requisiti del progetto
2. Valutazione e stima degli effort e delle risorse necessarie
3. OFFERTA MONETARIA AL CLIENTE (spesso "chiavi in mano", tutto incluso e senza possibili variazioni)
4. Analisi funzionale (dove si comincia a comprendere che cosa era sbagliato al punto 2)
5. Analisi architetturale (dove i dubbi della fase 4 diventano certezze)
6. Sviluppo & Test (dove il disastro assume proporzioni irreparabili)

Da tempo esistono risposte e metodologie per mitigare gli effetti di questa errata impostazione. Queste sono figlie del movimento Agile e del concetto di Ciclo di Vita dello Sviluppo del Software (Application Life-Cycle Management).

Queste metodologie, abbastanza sorprendentemente, sono tuttora ignorate dalla gran parte del mondo consulenziale IT e delle aziende che hanno grandi e complesse realtà IT al loro interno. Questo per un motivo fondamentale, e cioè che la "stima a preventivo" è la testata d'angolo cui poggia tutto il business, sia per chi vende che per chi acquista soluzioni IT. Il problema, come si è visto, è che la "stima a preventivo" è quasi sempre totalmente errata, quando non addirittura una menzogna.

Se per un momento facciamo l'ipotesi di poter fare a meno della "stima a preventivo", possiamo immaginare un processo di Project Costing & Estimation efficace e, soprattutto, vantaggioso per tutti gli attori (win-win). Questo processo è un processo iterativo, che si svolge all'interno di uno "sprint" di tempo - solitamente pari a un mese. In un mese - ogni mese - si fanno:

1. Analisi dei requisiti (e backlog)
2. Analisi tecnica
3. Sviluppo
4. Test e stime (di completamento, di budget, di costo totale ecc.)

e poi si ricomincia. Questa iteratività è alla base di qualunque processo di cambiamento in azienda, e risponde precisamente alla necessità di conoscere qualcosa che, all'inizio, è inconoscibile. E' un processo di raggiungimento della verità.

Sono convinto che se le imprese che lavorano nel settore IT non cominceranno a predisporre processi inerentemente iterativi, i fallimenti non potranno che continuare a essere all'ordine del giorno.

Le tecniche di sviluppo agili, l'intero Agile Movement, il mondo Open-Source insegnano tutti che il modello iterativo - che parte inoltre dal basso, e cioè dal codice sorgente - è un modello che assicura risultati grandemente migliori rispetto al Waterfall classico. Le grandi realtà di sviluppo software globale (Google, Microsoft) da tempo seguono questo approccio.

Riferimenti:
STANDISH GROUP: http://www.projectsmart.co.uk/docs/chaos-report.pdf
http://www.standishgroup.com/newsroom/chaos_2009.php
http://www.gartner.com/5_about/news/exec_reports.jsp
http://www.itarchitect.co.uk/articles/display.asp?id=203
http://www.projectsmart.co.uk/project-cost-management.html
http://www.it-cortex.com/Stat_Failure_Cause.htm (altri report di fallimenti)
http://www.infoq.com/presentations/Agile-Management-Google-Jeff-Sutherland

venerdì 2 luglio 2010

Differenza tra 'object' e 'class' in Scala

Una delle cose che trovo più intelligenti nel linguaggio Scala, è la netta distinzione tra Tipo Object e Tipo Class. Il primo è un tipo che può avere soltanto una istanza. Il secondo è un tipo che può avere molteplici istanze.

Il primo ha sintassi 'object', il secondo 'class'.

Chiaramente il primo, essendo sostanzialmente una classe "statica", non va istanziato, i suoi metodi possono essere chiamati direttamente. Il secondo va istanziato.

Ecco un esempio:

class Molteplice(nr : Int)
{
def id = nr;

def parla()
{
println("Buongiorno, sono il Molteplice nr = " + id);
}
}

object Singleton
{
def parla()
{
println("Buongiorno, sono un singleton.");
}
}

object Main
{
def main(args : Array[String]) : Unit =
{
Singleton.parla();
val range = 0.until(10);

for (i <- range)
{
val m = new Molteplice(i);
m.parla();
}

}
}



Questo ci permette di capire subito le intenzioni del programmatore, che deve creare classi solamente dove questo ha realmente senso.

Nella mia esperienza di programmatore OO (in Java, C++ e C#), direi che su 100 tipi in un programma normale, ad esempio di integrazione aziendale, 70 sono singleton (cioè in Scala 'object'), ovvero collezioni statiche di metodi e proprietà, e solo 30 classi vere e proprie (in Scala, 'class').

venerdì 10 luglio 2009

Ereditarietà multipla in Scala

Il problema dell'ereditarietà multipla nei linguaggi fortemente tipizzati (C++) è, molto banalmente, che se un oggetto eredita da due differenti classi che implementano lo stesso metodo, il compilatore non sa quale implementazione di quel metodo associargli (bind).

In Java e in C# perciò si è deciso di abolire l'ereditarietà multipla, e di inserire il concetto di interfaccia. Il problema delle interfacce, però, è che attraverso di loro viene descritto il comportamento di un oggetto (quali metodi sicuramente quel metodo avrà), ma non viene implementato, perché l'implementazione si demanda alla classe di quell'oggetto.

Questa soluzione non è ottimale, perché se nella mia tassonomia di classi ho delle forti "somiglianze" tra una classe e l'altra, la scrittura dell'implementazione dell'interfaccia comune rischia di doversi ripetere da una classe all'altra. Insomma, rischiamo ripetizioni e riscritture.

In Ruby esiste il concetto di mixin, per cui posso "prendere a prestito" del codice che esiste "altrove" e inserirlo nella mia classe, senza doverlo riscrivere. Il problema è che Ruby è un linguaggio di scripting, e non è tipizzato.

Scala è invece un linguaggio tipizzato che permette - in un certo senso! - l'ereditarietà multipla, e lo fa attraverso i "trait".

Ecco un esempio:


abstract class Animale
{
def nome:String;
def classe:String;
def comeMiChiamo:String = ("Sono il " + this.nome + " e sono un " + this.classe);
}

trait Mammifero extends Animale
{
override def classe:String = "Mammifero";
}

trait Rettile extends Animale
{
override def classe:String = "Rettile";
}

class Delfino(aName: String) extends Animale with Mammifero
{
def nome:String = "delfino "+ aName;
}

class Serpente(aName: String) extends Animale with Rettile
{
def nome:String = "serpente "+aName;
}

object Main
{
def main(args: Array[String])
{
parla(new Delfino("Pippo"));
parla(new Serpente("Pluto"));
}

def parla(animale: Animale)
{
println(animale.comeMiChiamo);
}
}


In questo esempio, la classe Animale è una classe astratta, che definisce il metodo "comeMiChiamo" (ok, non mi veniva niente di meglio!). Questo metodo è polimorfico rispetto alla "specie" dell'animale. Definisco perciò due nuove classi, che incidentalmente sono anche "classi di animali": i rettili e i mammiferi.

L'output del programma in console è:


Sono il delfino Pippo e sono un Mammifero
Sono il serpente Pluto e sono un Rettile


Quello che voglio dimostrare, è che posso scrivere in Scala una classe che eredita sia da Animale (il metodo "come mi chiamo"), sia da Rettile oppure Mammifero. Per farlo, "Rettile" e "Mammifero" sono due trait, di fatto la trasposizione dei Mixin per Scala. Se vogliamo, sono delle interfacce, solo che, a differenza delle interfacce in Java, il metodo che espongono è anche già implementato - evitandoci riscritture e copia/incolla nel codice (che è sempre male).

PS: La questione della duplicazione dei metodi alla base del problema dell'ereditarietà multipla, non è risolta, in Scala, è solo "evitata", dal momento che il compilatore, quando si tratta di "trait", fa un bel copia e incolla e non si preoccupa di controllare la coerenza - provate infatti ad esempio a far ereditare a Delfino sia il trait Mammifero che il trait Rettile:


class Delfino(aName: String) extends Animale with Mammifero with Rettile

giovedì 30 aprile 2009

Ajax su Https

Scenario: avete un'applicazione Ajax che funziona benissimo. Switchate il protocollo da Http a Https (SSL) e non funziona più.

La prima cosa che vi viene da pensare (come è venuta a me) è che Ajax - o meglio, l'oggetto XmlHttpRequest - non funziona su Https.

Ricerche e un po' di approfondimenti hanno risolto la situazione.

Intanto confermo che XmlHttpRequest (su qualsiasi browser, in particolare Firefox 3 e Internet Explorer 8) funziona su Https.

Il problema è che la pagina chiamante e lo script Javascript (e tutte le altre eventuali sorgenti che formano la pagina, ad esempio le immagini) devono assolutamente provenire da fonti sicure - cioè da fonti sotto Https.

Nel mio caso, infatti, le pagine venivano servite da una directory virtuale sotto Https, mentre gli script in Javascript erano serviti via Http normale. Se questo è il caso, XmlHttpRequest restituisce un errore di Security.