E’​ il momento delle visioni condivise e dell’innovazione

L’emergenza del Coronavirus ha dato inizio a una serie di cambiamenti nelle abitudini delle persone creando nuove necessità. Allo stesso momento le modifiche delle normative e la profonda alterazione degli ambiti di mercato hanno impattato sulle aziende, facendo emergere sia problematiche che nuove strategie. Nascono così necessità di nuovi strumenti, adeguati alle sfide da affrontare.

In questo scenario le aziende che si occupano di tecnologia hanno un duplice ruolo. Da un lato possono offrire gli strumenti necessari alle aziende per affrontare le trasformazioni in atto, contribuendo attivamente in un rilancio dell’economia. Dall’altro possono cogliere l’opportunità di coprire le nuove esigenze che emergono dalla trasformazione della nostra quotidianità.

 

Affinchè questo possa essere realizzato, secondo il mio punto di vista, sono necessari due ingredienti:

  • la presenza di spirito di innovazione ed energia nelle aziende;
  • la capacità di identificare nuovi ambiti di servizio/mercato, verificare le iniziative e ridurre i rischi, attraverso un processo sperimentale ed incrementale.

Visioni condivise

Esprimere il concetto di visione non è semplice. Una visione non è un’idea. E’ qualcosa di più profondo. Va al di la dei risultati e degli scopi, che sono solo l’indicazione astratta di una direzione. Una visione è una destinazione specifica, l’immagine di un futuro a cui si aspira, è qualcosa di concreto. Ad esempio: “creare le tecnologie per conquistare lo spazio” è uno scopo, mentre quando John Fitzgerald Kennedy disse “Abbiamo scelto di andare sulla Luna in questo decennio” dipinse una visione.

Ognuno di noi sviluppa delle visioni, ed è ben cosciente della distanza che hanno dalla realtà. Può essere causa di scoraggiamento, ma è proprio la distanza della visione a spingerci ad agire, e questo fa delle visioni una grande fonte di energia.

Sono certo che l’esperienza condivisa della pandemia e del lockdown è anche fonte di ispirazione per visioni personali positive. Di queste, le visioni che vanno al di la del nostro perimetro familiare sono particolarmente preziose, soprattutto se si creano le condizioni per una convergenza. Attraverso il dialogo si può arrivare a una visione condivisa e, quando questo accade, quella di una azienda può coincidere con quelle delle persone che ne fanno parte. Questo consente alle persone e alle aziende di esprimere il massimo potenziale: l’impegno di ognuno non nasce dall’omologazione, ma dalla coscienza di essere co-creatori di una nuova realtà a cui tutti si tiene.

Sperimentazione

La visione condivisa può contribuire a far emergere il pensiero laterale e ispirare l’apprendimento e l’innovazione. In questo modo le visioni si trasformano in potenziali prodotti e servizi, che vanno proposti a un mercato particolarmente instabile. Le condizioni di business durante la pandemia si sono rivelate estremamente variabili, cambia la mobilità delle persone, cambiano le normative, nascono e spariscono focolai di infezione… Oggi più che mai è necessario un approccio adattivo, realizzando prodotti e servizi in modo progressivo e misurandone continuamente risultati ed efficacia. E’ il momento del Ciclo di Deming, a ogni piano e iniziativa deve seguire una verifica e un adattamento.

Questo approccio va usato anche per la validazione delle iniziative, prima ancora di iniziare effettivamente a realizzarle. Ad esempio, utilizzando il Design Sprint è possibile testare i prototipi del prodotto o del servizio in cinque giorni. Un Design Sprint consente di definire le priorità e identificare una serie di soluzioni. Eletta una soluzione, ne viene realizzato un prototipo realistico da testare con un campione dei clienti di riferimento. Il risultato del test consente di apprendere informazioni vitali sull’efficacia della soluzione e determinare le azioni strategiche da eseguire come passo successivo.

Per chi volesse approfondire, sul sito thesprintbook.com è disponibile la “Remote Design Sprint Guide” che suggerisce come poter procedere a un Design Sprint rispettando i requisiti di distanziamento sociale.

Opportunità

Qualche giorno fa ho avuto la possibilità di osservare la mappa mentale “Ripple effects of the Low Touch Economy” prodotta da Board of Innovation.

No alt text provided for this image

E’ un lavoro notevole che riassume molti degli effetti causati dalla pandemia e ne rappresenta in modo efficace le correlazioni. Ho cercato di focalizzarmi sugli effetti che possono essere gestiti creando un adeguato supporto tecnologico o che rappresentano opportunità di innovazione. Non sono pochi.

In questo periodo di stravolgimento sociale le opportunità di innovazione non andrebbero intese solo come occasioni di evoluzione tecnologica e rilancio economico, ma anche di crescita sociale ed etica. Ci sono molti ambiti in cui è possibile lavorare, provo a elencarvene qualcuno, ma vi invito a provare anche voi questo esercizio. La pandemia può essere affrontata con uno spirito positivo e lungimirante.

Una vita contactless

Le maggiori precauzioni dal punto di vista igienico scoraggiano i contatti tra persone e con gli oggetti condivisi. Nasce la necessità di cambiare il mostro modo di fare le cose, utilizzando sempre di più approcci che limitano il contatto. La risposta a queste nuove esigenze è già in atto, con soluzioni che, ad esempio, fanno leva sul riconoscimento del viso (o dell’iride) e sull’interazione con display olografici.

Un nuovo modo di concepire la sanità

La necessità di limitare l’esposizione ai virus ha disincentivato l’accesso agli ospedali. Questo da un lato ha portato a un incremento di pazienti con diagnosi tardive e dall’altro ha creato la necessità di nuove soluzioni e-health, di terapia remota e di monitoraggio dei soggetti a rischio. In questi ambiti c’è sicuramente molto da fare.

In ambito aziendale, la crescente attenzione all’igiene e alla prevenzione, da origine alla necessità di varchi di sicurezza sanitaria e sistemi discreti per il monitoraggio delle temperature corporee. Anche in questo caso ci sono molte necessità da coprire, anche nell’ambito dei servizi pubblici.

Turismo locale

Le restrizioni sui viaggi stanno alterando profondamente il mercato del turismo e incentiveranno forme di turismo locale. Si avrà un rinnovato interesse sulle offerte in aree rurali e naturalistiche, a svantaggio delle mete in ambito cittadino. La riduzione dei contatti farà si che il viaggio sia concepito in una sfera più familiare o, comunque, ridotta alla cerchia più ristretta delle amicizie. Tutto questo richiede che gli strumenti di promozione turistica e di organizzazione dei viaggi vadano ripensati ed adeguati.

Un nuovo approccio alla mobilità

Il distanziamento sociale ha già disincentivato l’utilizzo dei mezzi di trasporto pubblico, costringendo a una riduzione dell’offerta delle infrastrutture di trasporto. La conseguenza è una maggiore diffusione di modalità di trasporto individuale e maggiore interesse per le soluzioni di micromobilità. Questo implicherà delle opportunità di potenziamento dei sistemi si trasporto condiviso ma anche, viste le precauzioni di carattere igienico-sanitario, una revisione del modello di offerta.

Nuove esperienze di acquisto

L’interazione tra dipendenti e clienti è già vista come un rischio. Questo farà acquisire maggior interesse verso le value chain con interazione minimale facendo aumentare la necessità di automazione del retail. L’esperienza di acquisto sarà rivista alla luce della necessità di distanziamento sociale, e il commercio elettronico evolverà con l’automazione del delivery. Nuove modalità di acquisto per le fasce più anziane della popolazione o su appuntamento saranno sempre più comuni e dovranno essere indirizzate con soluzioni mirate.

Conclusioni

I cambiamenti legati alla pandemia, nonostante gli impatti negativi dal punto di vista sociale ed economico, rappresentano anche opportunità di innovazione. Le aziende che si occupano di tecnologia hanno un ruolo strategico e possono contribuire in modo significativo sia al rilancio economico che a uno slancio nella crescita tecnologica, soprattutto se hanno spirito di innovazione e riescono ad attingere pienamente al potenziale umano di cui dispongono.

L’evoluzione continua della pandemia e delle condizioni di mercato richiederà la validazione delle iniziative con strumenti sia efficaci che economici, e renderà essenziale l’uso di strategie adattive con cicli di ispezione e adattamento.

Il cambiamento delle abitudini e dell’assetto sociale farà nascere nuovi prodotti e servizi e, per consentire il rispetto delle precauzioni igieniche e di distanziamento sociale, darà luogo alla trasformazione di quelli attuali. Questo può dare uno slancio all’innovazione e rappresentare un’opportunità di crescita etica e sociale.

Secondo voi quali in quale modo le aziende dei comparti tecnologici potranno assistere le altre nella ripresa economica? Quali immaginate possano essere le innovazioni che nasceranno a seguito della pandemia?

Pubblicato in Cloud computing | Lascia un commento

L’epidemia di Coronavirus in una visione di sistema

In questi giorni riflettevo sulla situazione del Coronavirus e, in particolare, su come il tempo di incubazione causi un notevole ritardo tra ciò che facciamo per ostacolarlo e l’effetto reale delle nostre azioni. Riflettevo anche sulla “fase di negazione” che, tutte, ma proprio tutte, le nazioni hanno fino ad ora attraversato prima di aggredire seriamente il problema.

In systems thinking mi hanno sempre affascinato gli archetipi. Gli archetipi sono una sorta di alfabeto che consente di descrivere sistemi complessi combinando insieme strutture fondamentali e per le quali corrisponde un principio di gestione ottimale. E’ un po’ come l’applicazione dei pattern architetturali nell’ingegneria del software, ma per descrivere una realtà già esistente.

Ciò che sta accadendo con il COVID19 può essere rappresentato nel linguaggio degli archetipi. Le loro rappresentazioni elementari rendono evidente la natura delle cose, i comportamenti delle persone e suggeriscono quali potrebbero essere le azioni corrette da perseguire.

L’arrivo del virus e la negazione

Di fronte all’arrivo del pericolo grave dell’epidemia la prima reazione che abbiamo osservato in tutti i paesi è stata quella di applicare una soluzione non definitiva, sintomatica, che va dal non affrontare il problema (vedi la teoria dell’immunità di gregge di Johnson) all’azione blanda (limitazione di alcuni voli in Italia). Le ragioni di questa inerzia sono molteplici (per un approfondimento suggerisco questo articolo di Hardward Business Review), ma sicuramente ha influito il potenziale impatto sulla nostra vita sociale ed economica di una azione radicale. Quello che è accaduto è un esempio da manuale dell’archetipo “Shifting the burden”:

No alt text provided for this image

Il sistema della diffusione del virus è controllato da due processi che tendono all’equilibrio, uno prevede l’applicazione di una soluzione fondamentale e l’altro di una soluzione sintomatica. La soluzione fondamentale consiste nell’applicazione di rigorose iniziative di distanziamento sociale, costose anche dal punto di vista economico, che hanno un effetto reale ritardato. La soluzione sintomatica, invece, ha un’apparente efficacia immediata ma presenta l’effetto collaterale di contribuire all’espansione del problema e di indebolire la capacità di risposta con una soluzione fondamentale. La perdita di tempo nell’applicazione delle iniziative di distanziamento sociale implica un aumento silente delle persone in incubazione ed asintomatiche e la diffusione ulteriore dell’epidemia. La diffusione dell’epidemia ha un impatto sul sistema sanitario che inizia a perdere la sua capacità di risposta. Il risultato è una possibile ulteriore diffusione delle infezioni, che limitano ulteriormente la capacità di reazione. Una sorta di “fuga termica” che, di fatto, riduce progressivamente la capacità di affrontare il problema.

Nonostante il notevole costo economico e l’apparente inefficacia iniziale, il modo migliore per afforntare questo archetipo consiste nel focalizzarsi sulla soluzione fondamentale, usando (se proprio è necessario) la soluzione sintomatica solo come un metodo per recuperare tempo per organizzare una azione realmente risolutiva.

La reazione

Fortunatamente la presa di coscenza del problema, nonostante gli impatti sui sistemi sanitari (e qui non posso non fare una carezza ai nostri amici spagnoli), ha dato luogo a reazioni corrette. Si è creata una nuova condizione, anch’essa descrivibile con un archetipo elementare noto come “Limits to growth”:

No alt text provided for this image

Come noto il contatto tra le persone ha un diretto contributo sulla diffusione del virus e provoca una crescita esponenziale dei casi. Per limitare la diffusione delle infezioni gli stati hanno applicato delle norme di distanziamento sociale. Il distanziamento sociale ha un costo significativo, sia in termini economici che emotivi, ed è applicato sotto la spinta della coscienza del pericolo e delle pressioni governative (sanzioni).

La mente umana non è capace di gestire bene realtà in cui il rapporto di causa ed effetto non è strettamente relazionato nel tempo e nello spazio e questo implica un pericolo di cui è bene che tutti prendano coscienza. In un sistema con queste caratteristiche la limitazione della crescita è strettamente legata alla pressione sulla condizione limitante.

Al rallentamento della diffusione del virus si presenterà naturalmente la tendenza a mollare la presa. Noi, sia come governi che come singole persone, spinti dalla rassicurazione dei dati, dal peso economico e desiderosi di ammorbidire una condizione emotivamente dolorosa, cercheremo di trovare un compromesso.

Questo è molto pericoloso.

La necessaria perseveranza

Il comportamento dell’epidemia è descritto da un archetipo noto come “Balancing process with delay”.

No alt text provided for this image

Le condizioni di diffusione dell’epidemia sono contrastate dalle iniziative di distanziamento sociale che, però, hanno un effetto ritardato sul problema. Questo archetipo richiede un principio di gestione ben noto, che cito testualmente dal libro La quinta disciplina di Peter Senge:

“In a sluggish system, aggressiveness produces instability. Either be patient or make the system more responsive.”

La natura del virus non consente di abbreviare il ritardo tra un intervento e il suo effetto, per cui è necessario esercitare la nostra pazienza. Di fronte a un’apparente rientro della crisi dovremo perseverare e attendere un po’ più a lungo di quanto l’intuito possa suggerire. E’ quasi paradossale, ma persistere nel distanziamento sociale è l’unico modo per ritornare velocemente ai nostri affetti e alla nostra quotidianità.

Pubblicato in Cloud computing | Lascia un commento

“Flight, EECOM. Try SCE to Aux”

14 novembre 1969, ore 16:22 UTC

Il razzo Saturn V della missione Apollo 12, immediatamente successiva a quella che portò l’uomo per la prima volta sulla Luna, inizia a sollevarsi dalla rampa di lancio. Il cielo sul Kennedy Space Center a Cape Canaveral è molto nuvoloso. Piove e durante l’ascesa i venti raggiungono velocità fino a 280 km/h.

36 secondi dal lancio

Un lampo brillante, uno scossone. Tre celle a combustibie si disconnettono dal bus di alimentazione e i 75 ampere necessari alla navetta sono prelevati dalle batterie. Gli specialisti del Controllo Missione iniziano a ricevere dati telemetrici confusi. I tre astronauti si rendono subito conto di avere un grosso problema e passano alla modalità “Abort Mode I-Bravo” preparandosi ad un eventuale annullamento della missione.

52 secondi dal lancio

Un nuovo scossone. La piattaforma di guida smette di funzionare. Un secondo fulmine colpisce il veicolo e fa perdere le informazioni sull’orientamento del razzo. Fortunatamente, in questa fase del volo, il sistema di guida è utilizzato dall’equipaggio per monitorare l’ascesa senza controllare attivamente il veicolo. Il Controllo Missione continua a ricevere dati telemetrici illeggibili.

1 minuto e 36 secondi dal lancio

John Aaron è il controllore di volo incaricato come Electrical, environmental and consumables manager (EECOM). Osserva i dati della telemetria, ancora confusi.

Suggerisce al direttore di volo di alimentare il SCE (Signal Conditioning Equipment) con il sistema ausiliario.

“Flight, EECOM. Try SCE to Aux”

Nei suoi dati alterati, Aaron ha riconosciuto uno schema. Un anno prima, per pura coincidenza, Aaron era in Mission Control durante una simulazione della piattaforma di lancio. E quella notte, ricordò, aveva brevemente notato sullo schermo una serie simile di dati incomprensibili. Si rese conto che la squadra che gestiva i sistemi aveva brevemente interrotto l’alimentazione della capsula.

La variazione di tensione aveva prodotto un malfunzionamento sul dispositivo SCE, responsabile del condizionamento dei segnali grezzi dai sensori in modo che le informazioni potessero essere visualizzate sugli strumenti e trasmesse a Houston. Commutando in modalità di alimentazione ausiliaria — Aux — il SCE avrebbe ripreso a funzionare e gli strumenti sarebbero tornati online. A quel punto, le celle a combustibile potrebbero essere ricollegate al bus di alimentazione.

“Try FCE to Auxiliary. What the hell is that?”

Aaron dovette ripetere il suo suggerimento al direttore di volo perchè il SCE era un componente oscuro ai più. Gli stessi astronauti nella navetta non identificarono al volo l’interruttore, come avrebbero fatto per la maggior parte degli altri comandi.

1 minuto e 50 secondi dal lancio

Con il SCE sull’alimentazione ausiliaria la telemetria riprende a funzionare correttamente. Le tre celle a combustibile sono di nuovo on line, i sistemi del veicolo gradualmente riprendono a funzionare. La missione è salva.

La curiosità di John Aaron

Alcune settimane dopo il suo pensionamento, John Aaron venne intervistato da uno storico della Nasa. Raccontò che quando notò una strana firma dei dati durante la simulazione di lancio in una notte del 1968, la sua “naturale curiosità” lo portò a capire meglio perché fosse accaduto. Si trovò di fronte alla stranezza di una telemetria con dati illeggibili (non tutti a zero come si sarebbe aspettato) e cercò di capire il perchè. Fu un’iniziativa personale, mossa dal desiderio di comprendere e di imparare, che ha salvato i costi e potenzialmente le vite legate alla missione.

Adesso diremmo che John Aaron ha percorso l'”extra mile”, approfondendo di sua iniziativa la funzionalità di un componente sconosciuto.

Extra mile e cultura aziendale

Secondo Peter Senge, un’azienda può sopravvivere se diventa una “learning organization”. Un’organizzazione in cui

  • le persone espandono continuamente la loro capacità di creare i risultati che desiderano
  • i risultati sono coerenti con una visione collettiva
  • sono alimentati nuovi ed espansivi schemi di pensiero
  • l’aspirazione collettiva viene liberata e le persone imparano continuamente come apprendere insieme.

Mi piace pensare che l’iniziativa di Aaron abbia avuto origine nella cultura e nella visione condivisa in quel periodo storico. Il personale coinvolto nelle missioni Apollo era il più capace sulla piazza e stava, letteralmente, costruendo una nuova tecnologia. Tutti stavano creando qualcosa di nuovo, puntando all’obbiettivo comune di eccellere nella corsa allo Spazio.

In queste condizioni, con questo livello di coinvolgimento, è naturale che le organizzazioni ottengano più di quanto si aspettano. Percorrere l'”extra mile” non è una cosa che può essere richiesta. Non è uno straordinario. E’ entusiasmo e coinvolgimento, e solo la giusta cultura aziendale può far si che si manifesti in modo spontaneo.

Pubblicato in Agile | Lascia un commento

4 aprile: Inizio sprint 1

Sono solito scrivere i miei appunti su carta e non butto mai via le mie vecchie agende. Ho sempre pensato siano utili, soprattutto quando sono ben “stagionate”, perchè riescono a rappresentare in modo oggettivo i cambiamenti e le evoluzioni rispetto al momento in cui sono state utilizzate.

Qualche giorno fa, senza una ragione particolare, ho pescato un’agenda dalla libreria e ho iniziato a sfogliarla. Pian piano mi ha evocato ricordi lontani, le esperienze condivise con i colleghi, i clienti e le sfide. All’improvviso, ecco il 4 aprile con una nota importante: Inizio Sprint 1.

Ricordo molto bene quel giorno. E’ stato un passaggio cruciale nella mia esperienza lavorativa e nella mia formazione personale. Dopo aver tanto letto e raccontato di approcci agili, si iniziava a dare corpo alle idee. Era una sfida: tutte le teorie di cui ero venuto a conoscenza fino ad allora reggeranno il confronto con la realtà?

Quel primo esperimento fu un successo, anche grazie alle persone eccezionali che mi circondavano, e sancì l’inizio di una agile transformation. Di fronte a questa pietra miliare non potevo non fermarmi a riflettere…

Le condizioni per la massima espressione del potenziale

“Bisogna aver cura delle persone”- E’ una frase che ho sentito dire tante volte. Tutti riconoscono come vera questa affermazione. E’ una considerazione ovvia, ma solo in apparenza. Ho sentito persone affermarla con forza, ma agire inconsapevolmente in modo distruttivo, così come ho visto persone sostenere al meglio i propri collaboratori, senza neanche rendersene conto. Non credo ci sia un unico approccio corretto, le variabili in gioco sono molteplici. Ci sono, però, delle condizioni che consentono di esprimerci al meglio e, per quanto possibile, è sempre neccesario crearle o mantenerle.

Secondo la mia opinione, un approccio che danneggia gravemente la qualità dei risultati e il clima lavorativo è quello in cui le persone sono viste come puri esecutori. E’ una visione tayloriana, lontana dalla realtà di oggi, soprattutto in ambiti in cui la competenza e la specializzazione è elevata. La pura esecuzione di compiti trasforma il rapporto lavorativo in una transazione economica: l’azienda mi paga in cambio del lavoro che mi è stato indicato di fare. La perdita di valore è evidente. L’ingegnosità, l’entusiasmo e il contributo in termini di diversità di visione e pensiero è il vero contributo che ognuno di noi porta all’organizzazione per cui lavora.

Uscire da questo modo di lavorare a volte è complicato. Richiede la piena fiducia nelle persone con cui si lavora (non è sempre necessario?) e, soprattutto, richiede la reale delega di alcune responsabilità.

Il gruppo come unità produttiva

Spesso consideriamo come artefici del risultato le singole persone nel gruppo di lavoro. In realtà è molto più efficace intendere l’intero gruppo, il team, come unità produttiva. Pensiamo per un attimo al modello delle task force. Una task force è un gruppo di persone che lavora a un obiettivo chiaro e a breve scadenza. Il gruppo si organizza in modo autonomo, in base alle condizioni del momento, per raggiungere al meglio lo scopo da raggiungere. Tutti contribuiscono al successo, mettendo a frutto i propri talenti. Ogni componente del gruppo è sia protagonista che responsabile del risultato.

Il modello della task force è usato in condizioni di emergenza perchè è efficace, ed è efficace perchè consente la massima espressione di tutti. In generale se il gruppo possiede:

  • Un obbiettivo chiaro e condiviso
  • Competenze trasversali
  • Un numero di componenti limitato
  • La responsabilità completa e collegiale del risultato, per tempi, costi e qualità
  • La libertà organizzativa nel raggiungimento del risultato, mantenendo un approccio che punta all’eccellenza

è probabile che otterrà il risultato in modo ottimale.

L’efficienza e la quantità di lavoro in gioco

Un gruppo di lavoro efficiente non è compresso in deadline “subite” o in attività dai ritmi affannati. L’efficienza, ancora una volta, si ottiene consentendo alle persone di esprimersi al meglio. Ciò significa lasciare il gruppo libero di stimare l’effort delle sue attività, di influenzare la scelta di cosa è possibile ottenere in un certo tempo e avere la possibilità di lavorare senza interruzioni. Inoltre, e questo è anche più importante, se il gruppo misura la propria capacità produttiva e ambisce a un miglioramento continuo, avendo la facoltà di modificare le condizioni o gli strumenti di lavoro, può massimizzare spontaneamente la propria efficienza.

Il bisogno di crescere

Se avere un team che riesce a ottenere buoni risultati è importante, ambire all’eccellenza in ogni aspetto è la cultura vincente. Tutti noi abbiamo bisogno di una spinta evolutiva, che consente di mettersi in gioco e apprendere. Anche dai propri errori. Uno strumento eccezionale in questo senso è l’autocritica. Avere la facoltà e la completa libertà di criticare il proprio operato consente di capire come migliorarsi, e garantisce all’organizzazione di reagire naturalmente alle mutazioni del contesto in cui lavora. E’ un viaggio che ambisce a una meta ideale e che si muove asintoticamente in quella direzione.

L’illusione del buon senso

Creare le condizioni ottimali per la massima espressione del potenziale sembra una pura questione di buon senso. E questo è un problema perchè porta all’approssimazione. Anch’io in passato ho creduto che il buon senso fosse non solo necessario ma anche sufficiente a consentire le condizioni ideali di lavoro. Mi sbagliavo. E’ necessaria l’applicazione di un metodo formale e di tanto studio. Il buon senso è un falso consigliere perchè da una errata sensazione di padronanza del contesto o della situazione. Per dirne una, il buon senso direbbe di non toccare il codice che funziona, ma le buone pratiche prevedono il refactoring…

Spesso, quando iniziano ad affiorare i dubbi siamo sulla buona strada. Vuol dire che davvero si sta procedendo verso una maggiore presa di coscienza delle cose.

Pubblicato in Agile | Lascia un commento

Planning poker: il metodo Delphi al servizio di Scrum

Il problema

Immaginate di prepararvi per uno Sprint Planning Meeting: l’efficacia della pianificazione dipenderà, tra le altre cose, dalla qualità della stima dell’effort per ogni backlog item. La stima può essere effettuata discutendo insieme sui dettagli dell’attività e arrivando ad un valore condiviso ma questo percorso, apparentemente tranquillo, è pieno di trappole.
Ogni membro del team può avere una percezione differente dell’entità del lavoro necessaria e, nonostante questo, si può affidare al parere di un collega più esperiente, che ha inserito la storia nel product backlog dopo una telefonata col cliente o, semplicemente, non si  esprime perchè non è sufficientemente coinvolto.  Il risultato è che in una discussione “tradizionale” si possono perdere delle informazioni che, seppur presenti nel gruppo, non contribuiscono al processo decisionale.

Esistono dei metodi formali per approcciare il processo decisionale in modo ottimale e questi, aldilà delle valutazioni scientifiche, partono da un concetto ben noto: “due teste sanno più cose di una sola”. In un team ci sono tante teste, vediamo quindi come sfruttarle bene!

Il metodo

Il planning poker è una metodologia per la stima dell’effort necessario per portare a completamento una attività. Ogni partecipante al processo di stima è in possesso di una serie di carte simili a quelle da gioco (di cui il nome) rappresentanti la scala numerica della serie di Fibonacci o una sua approssimazione (ad.es: 0, 1/2, 1, 2, 3, 5, 8, 13, 20, 40, 100). Presentato l’argomento, ognuno sceglie una singola carta con valore adeguato alla propria stima personale e la depone sul tavolo coperta. Non appena tutti hanno fatto la propria scelta, le carte vengono scoperte contemporaneamente. Se i valori sul tavolo sono discordanti, viene avviata una discussione volta a identificare le ragioni delle differenze. Esaurita la discussione viene effettuata una nuova selezione delle carte, analogamente a quanto fatto inizialmente. Il processo viene ripetuto fino a quando non si ha una convergenza su un valore condiviso.

Il planning poker, molto diffuso tra gli utilizzatori di processi agili di sviluppo software, è  una applicazione del metodo Delphi messo a punto dalla RAND Corporation negli anni ’50 ed oggetto di studi e approfondimenti successivi. Il metodo Delphi è caratterizzato da:

  • Anonimità dell’opinione
  • Feedback controllato in un processo iterativo
  • Analisi della risposta statistica del gruppo

L’anonimità dell’opinione è richiesta per limitare l’effetto della presenza di individui dominanti nel processo decisionale. Il loro effetto è tipicamente quello di annullare il contributo di alcuni partecipanti, che adeguano la loro posizione sulla base dell’autorevolezza di qualcun’altro. Ciò riduce l’efficacia del processo: una divergenza iniziale è sempre un contributo alla qualità della decisione finale. Nel planning poker ciò è ottenuto presentando le stime contemporaneamente, a garanzia dell’autonomia della decisione dei partecipanti.

La revisione dei risultati di ogni interazione rappresenta il feedback controllato sul processo decisionale. La divergenza di opinioni può nascere, oltre che dal diverso grado di esperienza dei partecipanti, anche dalla sottovalutazione (o sopravvalutazione) della complessità dell’argomento o da una comprensione differente dello scope dell’attività oggetto di discussione. La discussione avviata alla fine di ogni iterazione permette lo scambio di informazioni tra i partecipanti col risultato di una definizione più precisa dei contorni dell’argomento discusso e una migliore valutazione delle implicazioni nascoste. L’effetto è che ad ogni iterazione si ha una sempre più definita convergenza verso un valore condiviso.

Il metodo Delphi, e quindi anche il planning poker, in virtù dello scambio di informazioni  e del valore attribuito al contributo di ogni partecipante, permette non solo di mantenere la discussione stimolante e interessante per tutti ma anche di rassicurare il gruppo sulla qualità delle decisioni assunte. Infatti, l’uso di una procedura sistematica e formale, attribuisce oggettività ai risultati.

Una nota sulle carte

L’utilizzo della serie numerica di Fibonacci o un suo adattamento non è casuale. E’ una garanzia ulteriore della qualità della stima effettuata: la sequenza numerica ha numeri progressivamente più distanti al crescere del loro valore, il che equivale a dire che più tempo  immagino di impiegare per portare a termine il lavoro, maggiore sarà l’imprecisione della stima. Ciò porta naturalmente alla frammentazione delle storie sul product backlog troppo ad alto livello in un insieme di storie minori che portano comunque un valore tangibile.
Oltre alle carte numeriche possono essere presenti due carte aggiuntive: una col punto interrogativo ed una con una tazza da caffè.
La prima indica che non si è in grado di fare nessuna stima. Se viene usata da uno o più  partecipanti significa che l’argomento di discussione non è ben definito o è troppo vasto: va chiarito o frammentato.
La carta con la tazza di caffè, che credo sia stata aggiunta da Crisp, rappresenta un concetto semplice: pausa! Questa carta è più efficace se, a dispetto delle regole, ci si mette d’accordo per avere la convergenza di opinione!

Se voleste approfondire la conoscenza del metodo Delphi, vi suggerisco The Delphi Method – An Experimental Study of Group Opinion, liberamente scaricabile dal sito della RAND Corporation.  Se invece siete alla ricerca delle carte da planning poker, vi raccomando un mazzo come quello che ho fotografato. Potete acquistarlo da Crisp a soli 6.38 euro+IVA, spedizione inclusa.

Pubblicato in Agile, Project management | Contrassegnato , , , , , , , | 2 commenti

Windows Azure Web Role in PHP

Windows Azure non è solo per chi sviluppa soluzioni utilizzando Visual Studio ed i framework .NET. Infatti, è possibile creare ed erogare dei cloud service anche utilizzando Java, Ruby o PHP. In questo post vedremo quanto è semplice usare PHP per muovere i primi passi su Windows Azure.

Per seguire questo tutorial è necessario predisporre  Eclipse per lavorare su Windows Azure. Maggiori dettagli sui prerequisiti e sulla preparazione dell’ambiente di sviluppo sono disponibili nel post Anatomia e sviluppo di una soluzione cloud per Windows Azure. Inoltre, sebbene faccia riferimento all’utilizzo di Visual Studio, è consigliabile dare una lettura ai due post della serie Hello Web Role! per familiarizzare con i web role e gli storage service.

Un po’ di teoria

Windows Azure supporta il modulo FastCGI di Internet Information Server 7.0 consentendo la realizzazione di web role che eseguono applicazioni scritte in linguaggi interpretati o in codice nativo. Per creare un web role che esegue una applicazione FastCGI è necessario innanzitutto verificare che l’impostazione  del flag enableNativeCodeExecution sul file ServiceDefinition.csdef sia true (è il valore di default sugli ultimi SDK):

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="Simple"
xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="WebRole" enableNativeCodeExecution="true">
    <ConfigurationSettings>
    </ConfigurationSettings>
    <InputEndpoints>
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
  </WebRole>
</ServiceDefinition>

Inoltre è necessario includere il file opzionale web.roleConfig sulla radice del progetto. In questo file va specificato il percorso assoluto all’interprete o all’applicazione in codice nativo. Per specificare il percorso assoluto viene utilizzata la variabile d’ambiente %RoleRoot%. Questa ritorna il percorso assoluto alla radice dell’albero di directory in cui è in esecuzione il web role (dove sono presenti i file web.config e web.roleConfig). Un esempio di file web.roleConfig è:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.webServer>
    <fastCgi>
      <application fullPath="%RoleRoot%\approot\php\php.exe"/>
    </fastCgi>
    </system.webServer>
</configuration>

Un handler specifica quale risorsa di IIS gestisce la risposta per un certo tipo di richiesta. Configurando opportunamente l’handler è possibile indicare che sarà l’interprete PHP a gestire le richieste al server che fanno riferimento a file con estensione php. Tutte le richieste che collimano con il filtro path sulla definizione dell’handler verranno girate a php.exe (vedi MSDN). La configurazione degli handler viene effettuata nell’elemento handlers dell’elemento system.webServer sul file web.config, come segue:

<system.webServer>
…
  <handlers>
  …
    <add name="PHP via FastCGI" path="*.php" verb="*"
        modules="FastCgiModule"
        scriptProcessor="%RoleRoot%\approot\php\php-cgi.exe"
        resourceType="Unspecified" />
  </handlers>
</system.webServer>

Affinchè il role funzioni correttamente è necessario includere l’interprete nel progetto. Questo sarà compatibile con Windows Azure solo se è possibile effettuarne il deployment attraverso un semplice xcopy. La posizione dell’interprete deve combaciare con quella specificata con l’attributo fullPath dell’elemento application nel file webRole.config.

Sviluppare il web role con Eclipse

Muoverei primi passi verso lo sviluppo di un web role in PHP con Eclipse è estremamente facile. Vedremo infatti che la procedura guidata per la creazione del progetto permette di selezionare le feature da utilizzare e genera dei file php con degli esempi d’uso molto utili. Apriamo Eclipse, lanciamo la procedura guidata per la creazione di un nuovo progetto Windows Azure PHP Project e inseriamo il nome:

Windows Azure PHP ProjectPHP Azure Project NameAl terzo passo è possibile iniziare la configurazione del web role, a partire dal nome. Il checkbox Enable Windows Azure App Fabric support for this project inserisce nel progetto le classi per l’utilizzo dell’Access Control Service e il Service Bus. Visto il livello introduttivo del tutorial non approfondiremo l’argomento in proposito, ma vi consiglio di dargli un’occhiata. Il tab Data Storage Options permette di abilitare l’utilizzo dei servizi di storage e configurare le credenziali di accesso. Nel nostro caso useremo il development storage. Opzionalmente è possibile configurare anche le credenziali per l’accesso ad un database SQL Azure. Prima del deployment sarà possibile cambiare le impostazioni editando il file ServiceConfiguration.cscfg.

Windows Azure PHP Web RoleIl tab PHP Runtime permette di scegliere tra l’interprete PHP 5.3.4 compreso nel kit di sviluppo o una versione specifica installata sulla macchina.

Windows Azure PHP web role PHP runtimeSu Diagnostics è possibile attivare Windows Azure Diagnostics e specificare lo storage in cui inserire le informazioni diagnostiche, il livello di logging e l’intervallo di trasferimentio dei dati. Su Windows Azure Drives è possibile configurare l’utilizzo di eventuali Drives.

Windows Azure PHP web role diagnosticsCliccando su Finish viene creato il progetto. Le impostazioni di cui abbiamo parlato in precedenza dovrebbero essere già corrette. Dopo aver avviato il Compute Emulator e lo Storage Emulator, clicchiamo sul file index.php e selezioniamo Run/Run As/PHP Windows Azure Page. Dopo alcuni istanti viene aperta la pagina contenente il tipico output della funzione phpinfo() di PHP:

Windows Azure PHP runningIn cima alla pagina possiamo notare due link che permettono di effettuare il test delle operazioni sui blob e sulle table. Come dicevo all’inizio le pagine relative sono generate automaticamente e permettono di comprendere come effettuare delle operazioni sugli storage service. Non esiste un esempio riguardo le code, ma sulla documentazione del Windows Azure SDK for PHP è possibile trovare tutte le informazioni necessarie.

Dando un’occhiata al file BlobSample.php vediamo che innanzi tutto vengono inclusi i riferimenti alle librerie dell’SDK:

/**
 * Add PHP Azure SDK to the PHP include_path. This SDK is avilable in Application Root directory.
 * This can be done by adding following set_include_path statement in
 * every PHP file refering PHP Azure SDK.
 *
 * Alternatively user can update the include_path in PHP.ini file.
 */
set_include_path(get_include_path() . PATH_SEPARATOR . $_SERVER["RoleRoot"] . "\\approot\\");

/**
 * Refer PHP Azure SDK library files for Azure Storage Services Operations
 */
require_once 'Microsoft/WindowsAzure/Storage.php';
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';

All’interno del file Storage.php è definita la classe Microsoft_WindowsAzure_Storage, mentre in Blob.php è definita la classe Microsoft_WindowsAzure_Storage_Blob, che estende la prima.

Proseguendo con la lettura del file BlobSample.php, vediamo che viene creato lo storage client:

  $blobStorageClient = createBlobStorageClient();

  if(!isBlobServiceAccessible($blobStorageClient))
  {
    return;
  }

La funzione createBlobStorageClient() è definita più in basso come segue:

function createBlobStorageClient()
{
  if (azure_getconfig('UseDevelopmentStorage') == 'false')
  {
    $host = Microsoft_WindowsAzure_Storage::URL_CLOUD_BLOB;
    $accountName = azure_getconfig('StorageAccountName');
    $accountKey = azure_getconfig('StorageAccountKey');
    $usePathStyleUri = false;

    $retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::retryN(10, 250);

    $blobStorageClient = new Microsoft_WindowsAzure_Storage_Blob(
                                    $host,
                                    $accountName,
                                    $accountKey,
                                    $usePathStyleUri,
                                    $retryPolicy
                                    );
  }
  else
  {
    $blobStorageClient = new Microsoft_WindowsAzure_Storage_Blob();
  }
  return $blobStorageClient;
}

come possiamo vedere, nel caso in cui non venga utilizzato il development storage, vengono recuperate le credenziali e creato il client facendo riferimento a queste ultime. L’oggetto Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract permette di specificare il numero di tentativi e la distanza tra questi (vedi il file Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php).  Come è possibile vedere in Storage.php, non specificando le credenziali, il client viene creato per il development storage.
Il passo successivo è quello di recuperare la lista di container usando il metodo listContainers dello storage client. La funzione listContainers($blobStorageClient), definita come segue, stampa i nomi dei container trovati.

function listContainers($blobStorageClient)
{
  echo "<strong>List of Containers:</strong>";
    $containers = $blobStorageClient->listContainers();
    foreach ($containers as $container)
    {
        echo "- $container->Name </br>";
    }
    echo "</br>";
}

Viene creato un nuovo container con un nome unico prefissato dalla string “testcontainer” (ad es. testcontainer4d641216454b0) utilizzando il metodo createContainer dello storage client.

  $containerName = uniqid("testcontainer");
  $result = $blobStorageClient->createContainer($containerName);
  echo "New container with name <strong>'" . $result->Name . "'</strong> is created.";

Dopo aver ristampato la lista dei container, per poter verificare che il container sia stato effettivamente creato, vengono creati due blob con nome differente dall’immagine WindowsAzure.jpg presente nella root del progetto usando il metodo putBlob:

$azureLogoFile = ".\\WindowsAzure.jpg";
$result = $blobStorageClient->putBlob($containerName, 'WindowsAzure.jpg', $azureLogoFile);
echo "New blob with name '<b>" . $result->Name . "'</b> is created. <br/><br/>";

Dopo aver stampato l’URL per il primo blob creato, viene stampata la lista di tutti i blob contenuti nel container usando la funzione listBlobs, costruita intorno al metodo listBlobs dello storage client:

function listBlobs($blobStorageClient, $containerName)
{
    echo "<b>List of blobs in container '" . $containerName . "': </b><br/>";
    $blobs = $blobStorageClient->listBlobs($containerName);
    foreach ($blobs as $blob)
    {
        echo " - $blob->Name " . "<br/>";
    }
    echo "<br/>";
}

A questo punto viene dimostrata la funzionalità di impostazione e lettura dei metadati sui blob con i metodi getBlobMetadata e setBlobMetadata. Vengono impostati i valori ‘createdby’ = ‘PHPAzure’ e ‘FileType’ = ‘jpg’.

/**
* Set metadata on blob "WindowsAzure.jpg" in $containerName container
*/
$blobStorageClient->setBlobMetadata($containerName, 'WindowsAzure.jpg',
array('createdby' => 'PHPAzure', 'FileType' => 'jpg'));
echo "Set metadata for '<b>WindowsAzure.jpg</b>' blob!<br/><br/>";
/**
* Read metadata on blob "WindowsAzure.jpg" in $containerName container
*/
$metaData = $blobStorageClient->getBlobMetadata($containerName, 'WindowsAzure.jpg');
echo "metadata for '<b>WindowsAzure.jpg</b>' blob:<br/>";
var_dump($metaData);
echo "<br/><br/>";

Il metodo getBlob dello storage client permette di effettuare il download del blob su un file temporaneo in locale:

$temp_file_name = tempnam(sys_get_temp_dir(), 'WindowsAzure');
$blobStorageClient->getBlob($containerName, 'WindowsAzure.jpg', $temp_file_name);
echo "Downloaded WindowsAzure.jpg blob to <b>" . $temp_file_name . "</b><br/><br/>";

Per dimostrare le funzionalità relativa all’impostazione del livello di accesso ai container viene impostato quello finora utilizzato come pubblico. Successivamente viene creato un nuovo container e impostato come privato. In esso viene creato un blob e generata una shared signature con validità di 5 minuti:

  /**
   * By default, blob storage containers on Windows Azure are protected from public viewing. If
   * any user on the Internet should have access to a blob container, its ACL can be set to public.
   * Note that this applies to a complete container and not to a single blob!
   */
  $blobStorageClient->setContainerAcl($containerName, Microsoft_WindowsAzure_Storage_Blob::ACL_PUBLIC);
  echo "Made container '$containerName' <b>public!</b> <br/><br/>";

  /**
   * Create shared signature for specified 'WindowsAzure.jpg' blob in private container
   */
  /**
   * First create a private container with uniq name and add 'WindowsAzure.jpg' blob file
   */
  $privateContainerName = uniqid("privatecontainer");
  $result = $blobStorageClient->createContainer($privateContainerName);
  $blobStorageClient->setContainerAcl($privateContainerName, Microsoft_WindowsAzure_Storage_Blob::ACL_PRIVATE);
  $result = $blobStorageClient->putBlob($privateContainerName, 'WindowsAzure.jpg', $azureLogoFile);

  $startTime = time();
  $endTime = $startTime + 5*60;  // Timestamp after 5 minutes

  $sharedSignatureURL = $blobStorageClient->generateSharedAccessUrl(
                $privateContainerName,
                "WindowsAzure.jpg",
            	'b',
            	'r',
            	isoDate($startTime),
            	isoDate($endTime)
          );

  echo "<b>SharedSignature for '$privateContainerName/WindowsAzure.jpg' with 5 minutes validity:</b><br/>" .
    '<a href="' . $sharedSignatureURL . '">' . $sharedSignatureURL . '</a><br/><br/>';

Infine viene cancellato il container pubblico col metodo deleteBlob e verificata l’effettiva cancellazione con il metodo containerExists:

  /**
   * Delete "WindowsAzure.jpg" blob from the $containerName container
   */
  $blobStorageClient->deleteBlob($containerName, 'WindowsAzure2.jpg');
  echo "Deleted blob <b>'WindowsAzure2.jpg'</b> from container <b>'$containerName'</b><br/><br/>";

  /**
   * Check if container exists
   */
  if ($blobStorageClient->containerExists($containerName))
  {
    echo "Container <b>'$containerName'</b> exists<br/><br/>";
  }
  if ($blobStorageClient->containerExists($privateContainerName))
  {
    echo "Container <b>'$privateContainerName'</b> exists<br/><br/>";
  }

Prima di concludere questo post vorrei indicarvi un utilizzo del table storage molto interessante per una applicazione PHP eseguita su Windows Azure. Quando l’applicazione è eseguita su almeno due istanze (a garanzia dello SLA), è necessario che lo stato delle sessioni sia condiviso tra le macchine virtuali. A tale scopo l’SDK per PHP mette a disposizione la classe Microsoft_WindowsAzure_SessionHandler  che permette di utilizzare il Table Storage di Windows Azure come session handler. Maggiori dettagli sono disponibili sulla documentazione del Windows Azure SDK for PHP.  Alla prossima!

Pubblicato in Programmazione, Windows Azure Tutorial | Contrassegnato , , , , , , , , | Lascia un commento

Hello Web Role! – Parte 2: Alla scoperta dello storage service

Nel post precedente abbiamo visto come realizzare la nostra prima soluzione cloud con un web role e come controllare il suo funzionamento utilizzando Windows Azure Diagnostics. In questo post vedremo come è possibile utilizzare lo storage service per memorizzare e pubblicare dati ed informazioni. I web role ed i worker role vengono eseguiti su istanze di macchine virtuali che mettono a disposizione uno spazio per la memorizzazione locale di file (local storage) volatile e quindi non utilizzabile per la memorizzazione persistente di file. Per la memorizzazione stabile di informazioni è possibile usare lo storage service o un database relazionale come SQL Azure.

Gli storage services di Windows Azure forniscono spazio di memorizzazione per dati testuali e binari, messaggi e dati strutturati.

I servizi offerti includono:

  • Il Blob service, per la memorizzazione di file
  • Il Queue service, per la memorizzazione di messaggi in una coda
  • Il Table service, per la memorizzazione di dati in forma strutturata non relazionale
  • I Windows Azure Drives, che permettono il mount di volumi NTFS da parte di una singola istanza

I servizi sono accessibili attraverso API REST che permettono l’accesso da una soluzione in esecuzione su Windows Azure o direttamente da qualunque applicazione in grado di inviare richieste e ricevere risposte HTTP/HTTPS su internet. L’accesso agli storage service avviene attraverso l’account. L’account è il livello più elevato nello spazio dei nomi per l’accesso ai servizi ed è alla base del processo di autenticazione. Nelle API REST l’account è esposto dai servizi come una risorsa.

Il blob service

Il Blob service fornisce lo storage per la memorizzazione di entità come file binari e di testo.Le API REST del blob service espongono due risorse: i container e i blob. Un container è un set di blob e ogni blob appartiene ad un container. Il blob service definisce due tipi di blob: i block blob, ottimizzati per lo streaming, ed i page blob. Questi ultimi sono ottimizzati per le operazioni di lettura e scrittura random, permettendo la scrittura di un range di byte in un blob. Sia ai container che ai blob è possibile associare metadati come coppie nome-valore definiti dall’utente.

Sebbene la struttura sia essenzialmente orizzontale, con i blob contenuti in un container, è possibile creare una struttura gerarchica simile ad un file system. I nomi dei blob possono contenere la codifica della gerarchia usando un separatore del percorso configurabile. Ad esempio i nomi di blob Gruppo/Blob1 e Gruppo/Blob2 implicano una organizzazione gerarchica virtuale. Ad agevolare questo genere di approccio, le API espongono dei metodi che permettono la navigazione delle gerarchie in modo simile a come siamo soliti fare sui file system consentendo, ad esempio, il recupero dei blob appartenenti ad un gruppo. Sull’MSDN è disponibile la reference delle API del blob service.

Il queue service

Il queue service fornisce un sistema affidabile per lo scambio di messaggi all’interno di un servizio e tra servizi differenti. Le API REST del queue service espongono due risorse: code e messaggi. Le code supportano la definizione di metadati come coppie nome-valore. Ogni account può contenere un numero illimitato di code di messaggi con nome univoco. Ogni coda può contenere un numero illimitato di messaggi con dimensione massima pari a 8 KB.

Quando un messaggio viene letto dalla coda, viene reso invisibile agli altri consumatori per un certo periodo di tempo. Se il messaggio non viene cancellato entro la scadenza dell’intervallo, viene ripristinata la sua visibilità in modo da permettere ad un altro consumatore di processarlo. Per approfondire l’argomento sulle code, la reference sulle API del queue service disponibile sull’MSDN è un ottimo inizio.

Il table service

Il table service fornisce uno storage strutturato sotto forma di tabelle che supporta le API REST ed è compatibile con le API REST di ADO.NET Data Services. All’interno dello storage account è possibile creare tabelle con nome univoco, all’interno delle quali vengono memorizzate informazioni come entità. Le entità sono collezioni di proprietà con i relativi valori, in modo similare ad una riga. Le tabelle sono partizionate al fine di supportare il load balancing tra i nodi e ogni tabella ha la prima proprietà utilizzata come chiave (partition key) per identificare la partizione a cui appartiene. La seconda proprietà identifica la riga (row key) che identifica un’identità all’interno della partizione. La combinazione tra la partition key e la row key forma la primary key che identifica l’entità in modo univoco all’interno della tabella. La tabella non impone nessuno schema, di conseguenza è lo sviluppatore a implementare e imporre lo schema lato client. Come per gli altri servizi, anche le API del table service sono ben descritte in una sezione dell’MSDN.

Al lavoro!

Adesso che abbiamo fatto amicizia con gli storage service, riprenderemo il progetto del post precedente e vedremo come è possibile effettuare l’upload di un file sul local storage e la sua successiva memorizzazione sullo storage service. Parallelamente, memorizzeremo un messaggio che notifica l’avvenuto upload.

Come prima cosa assicuriamoci della correttezza della configurazione del local storage sul web role:

Annotiamo il nome del local storage, utilizzato per l’acquisizione della risorsa. Apriamo la pagina default.aspx ed inseriamo un campo fileupload ed un pulsante. Per evitare confusione lasciamo i nomi predefiniti. Andiamo sull’handler del click e inseriamo il codice per l’upload sul local storage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.IO;

namespace WebRole1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            LocalResource LocalStorage =
                  RoleEnvironment.GetLocalResource("LocalStorage1");
            if (FileUpload1.FileContent.Length > 0){
                FileUpload1.SaveAs(
                      LocalStorage.RootPath + FileUpload1.FileName);
            }
        }
    }
}

Utilizzando il metodo RoleEnvironment.GetLocalResource(“LocalStorage1”) (vedi MSDN) otteniamo l’accesso all’oggetto LocalResource che contiene i dettagli sul local storage LocalStorage1: Name, MaximumSizeInMegabytes e RootPath. Quest’ultimo contiene il percorso fisico alla directory assegnata al local storage, che utilizzeremo per salvare il file.

Lanciamo il progetto ed effettuiamo l’upload di un file. Se apriamo il l’interfaccia utente del Compute Emulator possiamo verificare l’effettivo upload. Basta cliccare col tasto destro sull’istanza (se sono due potremmo dover ritentare con l’altra) e scegliere “Open local store”. I file del LocalStorage1 sono contenuti in \directory\LocalStorage1.

Prima di passare alla scrittura del codice relativo alle operazioni sullo storage service, è necessario impostare il settaggio relativo alla stringa di connessione all’account. Nel nostro caso useremo il development storage e aggiungeremo, immediatamente sotto la stringa di connessione impostata per la memorizzazione dei dati diagnostici, la voce “BlobConnectionString” di tipo connection string con valore “UseDevelopmentStorage=true”.
Per maggiori informazioni sulla configurazione delle stringhe di connessione, c’è una sezione ad hoc sull’MSDN.

Riprendiamo l’handler dell’evento click di Button1 e iniziamo a scrivere il codice che ci permetterà di copiare il file su un blob. Per prima cosa è necessario creare un oggetto CloudStorageAccount inizializzato utilizzando la stringa di connessione che abbiamo inserito in precedenza. Per recuperarne il valore utilizziamo la classe RoleEnvironment che permette l’accesso all’ambiente di esecuzione del role e che abbiamo già utilizzato per avere accesso al local storage (vedi MSDN).
Adesso, disponendo dell’oggetto CloudStorageAccount e quindi l’indirizzo dell’endpoint Blob e delle credenziali, possiamo inizializzare il CloudBlobClient, l’oggetto che rappresenta il client di accesso al blob service:

CloudStorageAccount Storage = CloudStorageAccount.Parse(
RoleEnvironment.GetConfigurationSettingValue("BlobConnectionString"));
CloudBlobClient Client =
     new CloudBlobClient(Storage.BlobEndpoint, Storage.Credentials);

A questo punto possiamo passare alla definizione del container utilizzando il metodo GetContainerReference. E’ bene ricordare che il nome dei container deve eseguire le regole  per qualunque nome DNS valido:

  1. Il nome deve iniziare per lettera o numero e contenere solo lettere, numeri ed il carattere – (trattino).
  2. Il carattere – deve tassativamente essere preceduto e seguito da una lettera o da un numero.
  3. Tutte le lettere del nome devono essere minuscole.
  4. Il nome deve avere una lunghezza compresa tra 3 e 63 caratteri.

Il metodo SetPermissions permette di impostare il livello di accesso al container. Nel nostro caso il container non ha restrizioni d’accesso. Come di consueto, l’MSDN potrà fornirvi maggiori informazioni in proposito. L’ultima operazione da fare sul container è chiamare il metodo CreateIfNotExist, dal nome più che autodescrittivo.

CloudBlobContainer Container = Client.GetContainerReference("uploads");
Container.SetPermissions(new BlobContainerPermissions
 { PublicAccess = BlobContainerPublicAccessType.Container });
Container.CreateIfNotExist();

In modo analogo a come fatto in precedenza per il container, creiamo il riferimento al blob usando il metodo GetBlobReference del container. Come detto in precedenza, ai blob è possibile associare dei metadati sotto forma di coppie nome-valore. In questo caso creeremo il metadato “MIME” contenente il content type del file. Il metodo UploadFile del container ci permette di uploadare il contenuto, creando il blob o sovrascrivendo l’eventuale blob omonimo.

   CloudBlob Blob = Container.GetBlobReference(FileUpload1.FileName);
   Blob.Metadata["MIME"] = FileUpload1.PostedFile.ContentType;
   Blob.UploadFile(LocalStorage.RootPath + FileUpload1.FileName);

A questo punto, con un processo assolutamente analogo, definiamo una coda chiamata “filequeue”. E accodiamo un messaggio contenente il nome del file appena uploadato sul cloud storage. Maggiori informazioni sullla gestione delle code è disponibile in questa pagina dell’MSDN.

   CloudQueueClient QueueClient = Storage.CreateCloudQueueClient();
   CloudQueue Queue = QueueClient.GetQueueReference("filequeue");
   Queue.CreateIfNotExist();
   CloudQueueMessage Message = new CloudQueueMessage(FileUpload1.FileName);
   Queue.AddMessage(Message);

A questo punto non resta che lanciare il progetto e uploadare un file. Giocando con i breakpoint,  il Compute Emulator ed il Server Explorer è possibile vedere il file apparire prima sul local storage e poi sul blob service.

Alla prossima!

Pubblicato in Programmazione, Windows Azure Tutorial | Contrassegnato , , , , , , , , , | Lascia un commento