Natural user Interfaces


Natural user Interfaces, NUI (http://en.wikipedia.org/wiki/Natural_User_Interface), e' un argomento che attrae attenzione di ricercatori, designer e programmatori da quando

e' nato il computer. Molto lavoro e' stato fatto e possiamo dire che gia' oggi si intravedono grandi risultati, ma siamo ancora molto lontano dall'obiettivo finale.

Uno dei principi fondamentali delle NUI consiste nello sfruttare tutte le capacita' umane in base al contesto. Per capacita' umane intendo quelle capaci di interagire con

un dispositivo, qualunque esso sia. Ad esempio:

1. Tastiera
2. Mouse
3. Penna
4. Multi touch
5. Voce
6. Movimenti spaziali
7. Pensiero

Avere a disposizione dispositivi capaci di sfruttare le suddette capacita', in una scala da 1 a 10 direi che siamo a livello 2 nella commercializzazione ed a livello 6

nella ricerca. La ricerca pero' non si sofferma solamente ai dispositivi, va oltre definendo l'iterazione dei suddetti dispositivi con l'uomo nei vari contesti sociali e

storici. Ad esempio la psicologia cognitiva gioca un grande ruolo in questa ricerca.

Per dare una assaggio di quello di cui sto parlando, rimando a questo video, mms://msvcatalog-1.wmod.llnwd.net/a2249/e1/ft/share3/dd69/0/Productivity_Future_Vision.wmv.

author: Pierre Greborio | posted @ lunedì 16 agosto 2010 16.30 | Feedback (0)

Si volta pagina


Questo sarebbe il primo post del 2010 e dato che nel 2009 ne ho scritti ben 8, devo darmi da fare prima di abbassare il mio record negativo :-)

L'inizio del 2009 e' stato parecchio pesante, a maggio abbiamo shippato KIN (http://www.facebook.com/KIN). La parte sulla quale ho lavorato io non aveva nulla a che fare con il cellulare, io mi occupavo del sito Silverlight chiamato KIN Studio (http://studio.vz.kin.com). Dopo aver lavorato in media 12 ore al giorno per 1 anno e mezzo, inclusi parecchi week-end, a giugno mi sono preso un mese di vacanza nella bellissima Calabria :-)

Durante il mio soggiorno vengo a sapere che KIN e' dato per defunto, da un lato perche' le vendite erano basse e dall'altro per focalizzarsi su Windows Phone 7 (http://www.windowsphone7.com/). Quando ho letto la notizia ho lanciato qualche imprecazione, ma poi ho dimenticato tutto con un bel bagno al mare. Non c'e' momento migliore per essere in vacanza!!

Che si fa ora? Il nostro nuovo charter e' sviluppare applicazioni per Windows Phone 7. La buona notizia e' che continuero' a sviluppare con Silverlight, la brutta e' che mi dovro' dimenticare di avere un giga di memoria a disposizione ed uno schermo da 24 pollici.

Sinceramente mi sento molto ottimista con Windows Phone 7. C'e' molto lavoro e la competizione, aka iPhone, Android, Nokia e RIM e' ferocissima, ma stiamo veramente lavorando sodo per cambiare le cose. Sono pronto as commettere che in 2 anni ci riprendiamo il 20% del mercato :-)

author: Pierre Greborio | posted @ martedì 3 agosto 2010 22.39 | Feedback (0)

Sistemi di logging


La mia carriera e' iniziato con lo sviluppo client side, dopo pochi anni sono passato al server side e da circa 1 anno e mezzo sono nei cloud services. E' incredibile vedere quante differenti problematiche si debbano affrontare.

Recentemente abbiamo discusso del sistema di logging. Non tanto in termini di quale tecnologia quali .NET logging, NLog, ETW, o altro, quanto le problematiche da superare nel cloud. Uno dei probemi maggiori e la quantita'. Pensate a Facebook (http://idleprocess.wordpress.com/2009/11/24/presentation-summary-high-performance-at-massive-scale-lessons-learned-at-facebook/) il quale processa 25TB di messaggi al giorno. Solo nel nostro ambiente di test, con circa 300 utenti, generiamo circa 25MB di messaggi al minuto.

Nella discussione abbiamo caratterizzato la problematica in quasti termini:

  • Minimizzare l'impatto sui server di produzione, bufferizzaddo i messaggi di log in memoria e scrivedoli su disco a blocchi
  • Minimizzare l'impatto sui dischi usando un sistema di rotazione dei files
  • Minimizzare l'impatto sulla rete spostando log files non troppo grossi per una successiva processazione
  • Non filtrare per severita' a priori. Il logging serve a capire che cosa e' successo port-mortem, se si filtra si perdono informazioni preziose
  • Arricchire i protocolli di comunicazione fra componenti in modo da permettere la tracciabilita' (correlazione)
  • Accettare perdite di dati (logs)

Nel nostro team usaimo un sistema proprietario (MS) consolidato da altri servizi. Detto cio', credo che siamo ancora abbastanza lontano da una soluzione generalizzata per i cloud services.

 

 

 

author: Pierre Greborio | posted @ lunedì 14 dicembre 2009 15.45 | Feedback (2)

Nuovo attacco alla logica di rinegoziazione TLS


E' notizia di oggi, http://extendedsubset.com/?p=8, che sia stata trovata una falla nella rinegoziazione TLS.

Per sommi capi, l'hacker puo' avviare una negoziazione TLS con il server and successivamente fare da proxy alla negoziazione del client attraverso lo 'stesso' canale. Questo permette all'hacker di iniettare del contenuto arbitrario all'inizio dei dati spediti dal client TLS al server TLS. I server trattera' questi dati come se provenissero dal client. Una volta che l'handshake si e' concluso, l'hacker non puo' fare piu' nulla di utile.

L'hacker non sara' in grado di vedere il contenuto (plaintext) scambiato con il server, ma puo' comunque:

  • Mandare comandi che vengono rispediti al client, ad esempio comandi di autenticazione (incluso quello basato su certificati)
  • Potenzialmente accedere ai dati spediti dal client usando i comandi spediti al punto precedente che implicano l'invio di questi ad un server terzo

La cosa sembra parecchio seria e riproducibile. Non ci sono al momento fix disponibili.


author: Pierre Greborio | posted @ giovedì 5 novembre 2009 6.55 | Feedback (0)

Storage nel cloud: Partizionamento


Mi sono assentato per in certo periodo in quanto aspettavo un buon momento per poter parlare di SDS (SQL Data Services). Purtroppo, non ne posso ancora parlare e quindi mi invento un'altro argomento, comunque fondamentale.

Una delle caratteristiche peculiari dello storage nel cloud e' quella di poter scalare, potenzialmente scalare indefinitivamente. Fino a qualche anno fa, scalare il database significava aggiungere dischi, e se la potenza di calcolo non era sufficiente, aggiungere nodi al cluster. Non vi e' dubbio che scalare con un cluster, oltre ad incrementare i costi esponenzialmente, presenta comunque un limite fisico oltre al quale non si puo' crescere.

Google, sin dalla sua prima comparsa, ha introdotto il concetto di scalabilita' usando un hardware di basso costo. SDS, cosi' come altre soluzioni, stanno cavalcando la stessa idea. Ma come fanno a scalare un database linearmente mantenendo i costi accettabili.

La soluzione si basa su due aspetti importanti:

  • Partizionamento dei dati
  • Replica

Immaginiamo che un singolo data server (SQL Server) sia in grado di gestire 10GB di dati. Bene, se dovete gestire 25GB di dati vi serviranno 3 data server e farete in modo di spalmare i dati fra i tre server, possibilmente in modo uniforme.

Avere un singolo server, nodo, ci espone di fronte ad un singolo punto di fallimento. Ecco che quindi entra in gioco la replica. In altre parole i dati potranno essere replicati su altri server in modo che se uno di questi fallisce, l'altro compensa.

Questa semplice tecnica permette servizi come Microsoft SDS, Amazon Simple DB ed altri, di poter fornire il servizio del database a basso costo e con grande livello di affidabilita'. Nel caso particolare di SDS, Microsoft garantisce 3 copie dei dati per ogni partizione.

Per ora mi fermo qui, in un prossimo futuro entrero' meglio nei dettagli del partizionamento in quanto ha un impatto diretto su come si scrivono le applicazioni.

author: Pierre Greborio | posted @ lunedì 1 giugno 2009 23.18 | Feedback (0)

Storage nel cloud: latenza, BEB


Nel post dedicato alla latenza, ho illustrato una delle tecniche per mitigare il piu' possibile i problemi legati al timeout. La tecnica si basa sostanzialmente sul riprovare.

L'algoritmo che ho implementato, NRetryPolicy, e' molto primitivo e presenta parecchie imperfezioni, oltre a non risolvere il problema e potenzialmente peggiorarlo. Il lettore attento infatti si sara' accorto che se riproviamo ad intervalli fissi potremmo avere un effetto a valanga generando, involontariamente, un attacco di DOS (Denial Of Service) al servizio stesso. Come?

Immaginiamo di avere un carico costante di chiamate di 100 RPS. Ad un certo punto il 20% di queste vanno in timeout. Queste riproveranno dopo un certo ammontare, che avete definito voi, di tempo. Scattato questo intervallo il servizio dovra' supportare il 20% in piu' di richieste, quindi 120 RPS. La probabilita' che queste vadano ancora in timeout aumenta, e quindi si ripropone il problema al prossimo intervallo. Immaginiamo ora che 40 di queste richieste siano andate in timeout. Al prossimo giro 140 RPS. Avento un limite di tentativi, diciamo 3, non dovremmo superare 160 RPS considerando un errore (timeout) costante del 20%.

Come risolvere il problema? Cambiando il pattern dei tentativi, passando da un sistema costante e statico ad un sistema casuale. Essendo un problema molto comune, anche nelle telecomunicazioni e nelle reti, ci appoggeremo ad un algoritmo ben conosciuto, denominato Binary Exponential Backoff.

L'algoritmo e' semplice, riprova randomicamente sulla base di un intervallo esponenziale (2n - 1). Immaginando che l'unita' di intervallo (delta backoff) sia 1 secondo, al primo fallimento riprova subito, al secondo un tempo random incluso fra 0 e 1 secondo, la seconda volta un tempo random fra 0 e 3 secondi, la terza volta un tempo rando fra 0 e 7 secondi e cosi' via.

L'implementazione e' abbastanza triviale:

 

public class ExponentialNRetryPolicy : RetryPolicy
{
    int numberOfRetries;
    TimeSpan minBackoff;
    TimeSpan maxBackoff;
    TimeSpan deltaBackoff;
    private readonly Random Random = new Random();

    /// <summary>
    /// Policy that retries a specified number of times with a randomized exponential backoff scheme
    /// </summary>
    /// <param name="numberOfRetries">The number of times to retry. Should be a non-negative number.</param>
    /// <param name="deltaBackoff">The multiplier in the exponential backoff scheme</param>
    /// <returns></returns>
    /// <remarks>For this retry policy, the minimum amount of milliseconds between retries is given by the
    /// StandardMinBackoff constant, and the maximum backoff is predefined by the StandardMaxBackoff constant.
    /// Otherwise, the backoff is calculated as random(2^currentRetry) * deltaBackoff.</remarks>
    public ExponentialNRetryPolicy(int numberOfRetries, TimeSpan deltaBackoff)
        : this (numberOfRetries, TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(30), deltaBackoff)
    {           
    }

    /// <summary>
    /// Policy that retries a specified number of times with a randomized exponential backoff scheme
    /// </summary>
    /// <param name="numberOfRetries">The number of times to retry. Should be a non-negative number</param>
    /// <param name="deltaBackoff">The multiplier in the exponential backoff scheme</param>
    /// <param name="minBackoff">The minimum backoff interval</param>
    /// <param name="maxBackoff">The maximum backoff interval</param>
    /// <returns></returns>
    /// <remarks>For this retry policy, the minimum amount of milliseconds between retries is given by the
    /// minBackoff parameter, and the maximum backoff is predefined by the maxBackoff parameter.
    /// Otherwise, the backoff is calculated as random(2^currentRetry) * deltaBackoff.</remarks>
    public ExponentialNRetryPolicy(int numberOfRetries, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff)
    {
        if (minBackoff > maxBackoff)
        {
            throw new ArgumentException("The minimum backoff must not be larger than the maximum backoff period.");
        }
        if (minBackoff < TimeSpan.Zero)
        {
            throw new ArgumentException("The minimum backoff period must not be negative.");
        }

        this.numberOfRetries = numberOfRetries;
        this.minBackoff = minBackoff;
        this.maxBackoff = maxBackoff;
        this.deltaBackoff = deltaBackoff;
    }

    public override void Retry(Action action)
    {
        int totalNumberOfRetries = numberOfRetries;
        int retryCount = numberOfRetries;
        TimeSpan backoff;

        do
        {
            try
            {
                action();
                break;
            }
            catch (RetryException e)
            {
                if (retryCount == 0)
                {
                    throw e.InnerException;
                }
                backoff = CalculateCurrentBackoff(minBackoff, maxBackoff, deltaBackoff, totalNumberOfRetries - retryCount);
                if (backoff > TimeSpan.Zero)
                {
                    Thread.Sleep(backoff);
                }
            }
        }
        while (retryCount-- > 0);
    }

    private TimeSpan CalculateCurrentBackoff(TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff, int curRetry)
    {
        long backoff;

        if (curRetry > 30)
        {
            backoff = maxBackoff.Ticks;
        }
        else
        {
            try
            {
                checked
                {
                    // only randomize the multiplier here
                    // it would be as correct to randomize the whole backoff result
                    backoff = Random.Next((1 << curRetry) + 1);
                    backoff *= deltaBackoff.Ticks;
                    backoff += minBackoff.Ticks;
                }
            }
            catch (OverflowException)
            {
                backoff = maxBackoff.Ticks;
            }
            if (backoff > maxBackoff.Ticks)
            {
                backoff = maxBackoff.Ticks;
            }
        }
        return TimeSpan.FromTicks(backoff);
    }
}

 

 

E con questo credo che abbiamo concluso l'argomento di come limitare gli effetti indesiderati della latenza.

author: Pierre Greborio | posted @ giovedì 12 marzo 2009 23.11 | Feedback (0)

Storage nel cloud: le soluzioni in casa Microsoft


Nel primo post dedicato all'argomento, ho elencato due servizi che verranno forniti da Microsoft nei prossimi mesi. Si tratta di Windows Azure Storage e SQL Server Data services (SSDS).

Che differenza c'e' fra questi servizi? Detto che saranno tutti in hosting presso i datacenter di Microsoft, possiamo dire che Windowas Azure Storage fornira' lo storage per blobs, queue e tables (non relazionali), mentre SSDS un database relazionale.

Chi ha avuto modo di guardare a SSDS in passato, si sara' reso conto che di relazionale ha ben poco a che fare, se non il legame fra authority, container ed entity. Bene, quella versione (comunque una CTP) di SSDS sparisce per fare spazio al database relazionale. E' infatti di ieri l'annuncio ufficiale sul blog di SSDS.

I dettagli mancano ancora, io comunque darei un acch'io al prossimo MIX (sessione MIX09-T06F) ;)

author: Pierre Greborio | posted @ mercoledì 11 marzo 2009 0.48 | Feedback (2)

Storage nel cloud: latenza


Immaginatevi una sera a casa, avete un problema con un servizio o un contratto e decidete di chiamare il call center. Un call center e' pensato e progettato per essere scalabile (ho detto scalabile, non cortese :-)), tutte le chiamate vengono accettate, accodate ed evase il prima possibile. Bene, chiamate e dopo un secondo inizia la musichetta che vi mette in attesa (coda). Se va male qualche cosa, cade la linea e riprovate. Se va bene iniziate a parlare con l'operatore. Se va bene finite la richiesta, avete la risposta e chiudete. se va male cade la linea con l'operatore e ripartite da capo.

Il mondo del cloud computing non e' poi cosi' tanto differente. Quando dovete salvare un record non fate null'altro che fare una HTTP POST (nel caso il servizio sia RESTish) con il record in formato XML e il provider tradurra' questo payload XML in un record (ad esempio trasformandolo in uno statement SQL che eseguira' su SQL Server).

Se stessimo parlando di effettuare la stessa operazione sul nostro database locale, la latenza sarebbe molto ridotta, in quanto legata al throughtput della rete locale (solitamente molto alto) e da quanto il nostro database engine e' occupato.

Con uno storage nel cloud il numero di variabili aumenta incredibilmente, ed oltre a quelle appena menzionate, possiamo ricordare le condizioni di rete fra noi ed il cloud provider, il server web che accetta la richiesta, la componente che transcodifica, e cosi' via.

Quindi, se con il nostro SQL Server locale il numero di timeout era un'eccezione, con lo storage nel cloud il timeout diventa la regola. Come mitigare questo problema?

Una delle soluzioni e' proprio quello di fare quello che avete fatto con il call center, ci riprovate. In altre parole, prima di rilanciare l'eccezzione al chiamante, ci riprovate qualche volta. Ma quale schema adottare?

Come tutte le cose e' bene iniziare con qualche cosa di semplice, ed eventualmente nel futuro si puo' raffinare. Iniziamo quindi con una classe base (il contratto) che definisca la nostra policy di retry (il codice e' ispirato dall'esempio StorageClient fornito con Windows Azure SDK):

public abstract class RetryPolicy
{
    public abstract void Retry(Action action);
}


Ovviamente non puo' mancare la policy che non faccia nulla:

public class NoRetryPolicy : RetryPolicy
{
    public override void Retry(Action action)
    {
        try
        {
            action();
        }
        catch (RetryException e)
        {
            throw e.InnerException;
        }
    }
}

Dato che questa policy risulta abbastanza inutile, possiamo implementarne una che riprovi per un certo numero di volte ad un determinato intervallo:

 

public class NRetryPolicy : RetryPolicy
{
    private int numberOfRetries;
    private TimeSpan intervalBetweenRetries;

    public NRetryPolicy(int numberOfRetries, TimeSpan intervalBetweenRetries)
    {
        this.numberOfRetries = numberOfRetries;
        this.intervalBetweenRetries = intervalBetweenRetries;
    }

    public override void Retry(Action action)
    {
        int retryCount = numberOfRetries;

        do
        {
            try
            {
                action();
                break;
            }
            catch (RetryException e)
            {
                if (retryCount == 0)
                {
                    throw e.InnerException;
                }
                if (intervalBetweenRetries > TimeSpan.Zero)
                {
                    Thread.Sleep(intervalBetweenRetries);
                }
            }
        }
        while (retryCount-- > 0);
    }
}

Ora, immaginiamo di voler riprovare a salvare il record 3 volte a distanza di 1 secondo, dovremo scrivere qualche cosa del tipo:


NRetryPolicy retryPolicy = new NRetryPolicy(3, TimeSpan.FromSeconds(1));
retryPolicy.Retry(() =>
{

    // Salvo il record
    if (<e' un timeout ?>)
        throw new RetryException("Throwing an exception from RetryTest");
});

In questo modo, il nostro codice riprovera' al massimo tre volte prima di fallire definitivamente. Ovviamente lo schema e' molto semplice e potrebbe essere ottimizzato ulteriormente, ma questo lo lascio ad un prossimo appuntamento. Per ora, abbiamo prodotto una tecnica semplice per mitigare un timeout ricorrente rendendolo meno ricorrente.

author: Pierre Greborio | posted @ lunedì 9 marzo 2009 1.40 | Feedback (2)

Storage nel cloud


Il cloud computing non e' un'idea nuova, anzi l'idea nasce negli anni 60 dal computer scientist John McCarthy. Che cosa lo ha reso cosi' popolare cosi' recentemente? I motivi sono veramente innumerevoli e per ora sorvolero' rimandando nel prossimo futura l'analisi piu' approfondita.

Di certo uno dei motivi principali della popolarita' oggi e' il costo. Con pochi dollari al giorno si possono gestire milioni di transazioni business senza dover fare investimenti infrastrutturali ingenti a priori. Ecco che quindi possiamo iniziare a pensare a usufruire di public utilities installandoci i nostri servizi e mettendoci i nostri dati, senza preoccuparci di investire a priori un euro (o dollaro) in infrastruttura. Se il nostro business va bene, pagheremo [volentieri] di piu', altrimenti pagheremo meno. Se abbiamo un piccho di utilizzo in un certo periodo dell'anno non dovremo preoccuparci di comprare 50 server che rimarranno a dormire 300 giorni all'anno, sara' un problema del cloud provider.

In questo post mi soffermero' su uno degli aspetti del cloud computing: storage. Supportare anche pochi milioni di dati dei clienti per un servizio online richiede un certo livello di infrastruttura, licenze e manutenzione. Sono costi up-front veramente ingenti (centinaia di migliaia di dollari) su un business basato interamente su delle proiezioni. La soluzione potrebbe essere quella di affidarsi ad un cloud provider.

Tanto per citare un esempio, ho fatto una stima dei costi per supportare un sistema di provisioning con 5 milioni di clienti, contanto lo storage e la banda (in e out). Il costo sarebbe di circa 21 dollari al mese (tutti i providers si equivalgono in termini di pricing)!

Negli USA i cloud providers piu' popolari sono:
  • Amazon S3, SompleDB e SQS
  • Windowws Azure Storage (Table, Blob e Queue) e SSDS
  • Google MegaStore
Praticamente tutti provvedono un set di API basato su protocolli ed architetture standard, REST (HTTP POX) e SOAP.

La domanda che ci dobbiamo porre quindi e', ma come ci arrivo li? Prendo il mio database e lo copio nel data center ed inizio a fornire il servizio? No! Bisogna fare i conti con le limitazioni, piu' o meno comuni a tutti i providers:
  1. Non e' un database relazionale
  2. Non c'e' supporto alle transazioni
  3. La latenza e' un dato di fatto percettibile
  4. Ci sono piu' possibilita' di race condition
  5. Non tutti supportano la data locality
  6. Il numero di timeout aumenta
  7. Le tipologie query sono decisamente limitate
  8. I data types sono limitati
Ora, molti si saranno detti:
  • Leggendo la prima parte del post "bellissimo, lo voglio!"
  • Leggendo la seconda parte del post "non se ne parla nemmeno!"
Ottimo, se siete arrivati sino a qui, allora avete resistito abbastanza. La prossima volta parlero' dei singoli punti e come mitigarli il piu' possibile.

author: Pierre Greborio | posted @ domenica 8 marzo 2009 3.40 | Feedback (5)

Il mondo mobile cambia tono


Dopo l'uscita dell'iPhone e l'arrivo di Palm Pre possiamo dire che i paradigmi del mondo mobile sono decisamente cambiati. I criteri di usabilita' sono decisamente piu' alti ed i competitors dovranno veramente darsi da fare per raggiungere Apple e Palm. In questo periodo sono andato a guardare e provare i modelli di programmazione di entrambe i devices, da un lato giochicchiando con l'iPhone SDK e xCode, dall'altro leggendo le recensioni del nuovo Palm. Sulla carte Palm e' avanti anni luce, con tanto di HTML, CSS, Javascript e JSON si puo' estendere le funzionalita del nuovo device. iPhone e' legato al mondo Objective-C, Cocoa, xCode ed il suo omonimo SDK. Sviluppare per iPhone e' all'apparenza banale, ma in realta' tutt'altro che banale. Molto spesso, se il problema e' nel suo framework e' bene abituarsi a saper legger l'assembler per debuggare. Chi e' poi abituato a Visual Studio si sentira' parecchio frustrato a passare a xCode. Eppure l'iPhone ha comunque catalizzato un certo numero di sviluppatori che han postato 15.000 applicazioni dall'uscita dell'SDK. Non male se consideriamo non piu' di due anni. Cosa faranno gli altri? Bh, stiamo a vedere...

author: Pierre Greborio | posted @ venerdì 23 gennaio 2009 9.05 | Feedback (2)