typescript-bannerGiusto quest’oggi si sono aperte le iscrizioni al LAB su Typescript che si terrà il prossimo 28 Febbraio a Mestre – Venezia. Nell’occasione avremo modo di affrontare questo interessante linguaggio che ha il non trascurabile scopo di semlificare lo sviluppo client side all’interno dei browser. Typescript infatti gode infatti di un compilatore (che curiosamente è scritto esso stesso in Typescript) che è in grado di convertire il codice in Javascript puro, capace di essere eseguito in qualunque browser, senza necessità di un plugin addizionale. Si tratta in effetti della nemesi, regalandoci un linguaggio di alto livello – anche se mantenendo degli interessanti risvolti semantici che lo rendono flessibile come Javascript – dotato di un set di tipi verificato a compile-time.

Chi desiderasse approfondire lo può fare nei seguenti post:

Chi di voi invece preferisse provare direttamente un esempio, può raggiungermi il 28/2 a Mestre, iscrivendosi al seguente link.

http://www.xedotnet.org/Home/Meeting/20140228

Durante il lab darò una infarinatura iniziale del linguaggio e in seguito potrete seguire un esercizio step-by-step, e porre le domande del caso per risolvere i vostri problemi reali.

A presto


typescript-bannerGiusto quest’oggi si sono aperte le iscrizioni al LAB su Typescript che si terrà il prossimo 28 Febbraio a Mestre – Venezia. Nell’occasione avremo modo di affrontare questo interessante linguaggio che ha il non trascurabile scopo di semlificare lo sviluppo client side all’interno dei browser. Typescript infatti gode infatti di un compilatore (che curiosamente è scritto esso stesso in Typescript) che è in grado di convertire il codice in Javascript puro, capace di essere eseguito in qualunque browser, senza necessità di un plugin addizionale. Si tratta in effetti della nemesi, regalandoci un linguaggio di alto livello – anche se mantenendo degli interessanti risvolti semantici che lo rendono flessibile come Javascript – dotato di un set di tipi verificato a compile-time.

Chi desiderasse approfondire lo può fare nei seguenti post:

Chi di voi invece preferisse provare direttamente un esempio, può raggiungermi il 28/2 a Mestre, iscrivendosi al seguente link.

http://www.xedotnet.org/Home/Meeting/20140228

Durante il lab darò una infarinatura iniziale del linguaggio e in seguito potrete seguire un esercizio step-by-step, e porre le domande del caso per risolvere i vostri problemi reali.

A presto


ios_iPad-3rd-(6.0)_6.0_portrait_thumbEra un po' di tempo che ne sentivo la necessità ma, per varie ragioni - tra cui la cronica mancanza di tempo e un po' di sana pigrizia - la revisione della grafica del mio blog personale è sempre stata posposta a data da destinarsi. Oggi finalmente va online il lavoro degli ultimi giorni in cui ho rifatto completamente tutto lo stile del blog, aggiornandolo ai più innovativi concetti di responsività e alle tecnologie quali HTML5 e CSS3. Per farvi un'idea del lavoro provate a cambiare la dimensione del browser e vi renderete conto di come l'interfaccia si adegua allo spazio disponibile, rendendo di fatto frubile il sito sia su schermi di grandi dimensioni, sia su tablet e smartphone. Ora vi prego non siate troppo pignoli, non più di quanto lo sia stato io, dato che a ben vedere ho lavorato per vestire ex-novo BlogEngine il quale, vi assicuro, è tutto fuorchè predisposto alle interfacce responsive. Si tratta infatti di un engine webforms, che utilizza spesso e volentieri tabelle e, soprattutto, non consente una personalizzazione eccessiva del markup. In definitiva, fatta eccezione per la master page e gli spazi dedicati al post e al commento, il resto dell’interfaccia è rimasto sostanzialmente invariato se non per un lavoro di fino con i CSS. Alla fine Browserstack mi consola dandomi l’ok su tutti i browser ad eccezione di IE8. L’immagine qui a lato ad esempio è tratta dallo schermo di un iPhone5s. Gli utenti di IE8 sono vivamente pregati di entrare nell’era moderna e quindi aggiornare il proprio PC. A parte BlogEngine, lo strumento principale di questa rivoluzione responsiva è Boootstrap 3.0. Per chi non lo sapesse si tratta di un toolkit che consente di progettare le interfacce web basate su html5 e css3 perchè siano fruibili da tutti i dispositivi. Si basa su una struttura fatta di righe e colonne alle quali possono essere agganciate porzioni dell’interfaccia nelle varie risoluzioni. Questo meccanismo, dopo un po’ di pratica, diviene familiare e si riescono ad ottenere dei cospicui risultati in un tempo non eccessivo, anche se, lo devo proprio dire, avessi potuto farlo in XAML, avrei finito molto ma molto prima… Ma tant’è, HTML5 e CSS3 sono una vera soddisfazione, soprattutto per chi come me ha affrontato i problemi di compatibilità dalla fine degli anni ‘90 quando ancora Netscape era un agguerrito concorrente e l’idea di vedere lo stesso sito in modo simile su due browser era semplicemente una follia. I moderni strumenti in definitiva danno un aiuto veramente efficace e i risultati, pur se ancora faticosi, si raggiungono molto più agevolmente. Boostrap mi è piaciuto fin da subito, per qualche verso più che Foundation con il quale condivide gran parte della filosofia di funzionamento. Credo che non mancherà l’occasione per parlare in questa pagine di entrambe le librerie e dei problemi della responsività. Grazie fin d’ora per i commenti, i suggerimenti e spero i complimenti che mi vorrete postare.

Pur se lo static type checking è un elemento importante nell'utilizzo di Typescript, tanto da essere già una ragione più che valide nella sua adozione, è chiaro che si può fare di più nella semplificazione del codice Javascript e nella sua organizzazione. Nel corso degli anni si sono consolidate alcune pratiche comuni nella stesura di Javascript, per venire incontro alla carenza dei concetti di base dell'object orientation che sono particolarmente labili e limitati. Tra essi si possono annoverare alcune naming convention - ad esempio prependere un underscore ad una variabile la identifica come privata - e dei veri e propri pattern quali le closure. Tutto ciò in effetti è più che altro una notazione stilistica che una vera e propria caratteristica del linguaggio e spesso e volentieri tali pratiche tendono a renderlo di difficile comprensione e manutenzione. Typescript ha tra i suoi costrutti alcuni che hanno proprio lo scopo di semplificare nettamente il codice mascherando la vera e propria complessità che origina dalla sua compilazione.

Interfacce e classi

Nel precedente articolo abbiamo visto che grazie allo structured typing, Typescript è in grado di riconoscere i tipi semplicemente analizzando la corrispondenza delle proprietà. L'esempio seguente riassume in breve la questione:

   1: function getArea(s: { width: number; height: number; }): number
   2: {
   3:     return s.width * s.height / 2;
   4: }
   5:  
   6: var area = getArea({ width: 20, height: 30 });
   7: console.log(area.toString());

E' del tutto chiaro che questo tipo di notazione, pur se tutelata dal compilatore, è eccessivamente prolissa e a lungo andare puà essere oggetto di errori e incomprensioni. Per questa ragione Typescript ammette innanzitutto la creazione di interfacce, che altro non sono che la definizione del contratto di un tipo, cui il valore deve conformarsi. Un concetto più che normale per chi mastica programmazione ad oggetti. Vediamo un esempio:

   1: interface Shape
   2: {
   3:     width: number;
   4:     height: number;
   5: }
   6:  
   7: function calculateArea(s: Shape): number
   8: {
   9:     return s.width * s.height  / 2;
  10: }
  11:  
  12: var area = calculateArea({ width: 20, height: 30 });
  13: console.log(area.toString());

Nelle prime righe dello snippet è visibile la dichiarazione di una interfaccia "Shape". Essa riporta le proprietà "width" e "height" e viene usata come parametro della funzione calculateArea, al posto della precedente notazione estesa. L'argomento passato alla calculateArea è rimasto invariato, ma se provate a modificarne i nomi vi renderete contro che lo structured typing continua a funzionare come prima, validando il parametro contro la definizione dell'intefaccia. Le interfacce ammettono anche metodi e proprietà opzionali (usando il ?). Ecco un esempio:

   1: interface Shape
   2: {
   3:     width: number;
   4:     height: number;
   5:     color?: string;
   6:     getArea(): number;
   7: }
   8:  
   9: function calculateArea(s: Shape): number
  10: {
  11:     return s.getArea();
  12: }
  13:  
  14: var area = calculateArea(
  15:     {
  16:         width: 20,
  17:         height: 30,
  18:         getArea: function() { return this.width * this.height / 2; }
  19:     });
  20:  
  21: console.log(area.toString());

L'esempio in questione estremizza la definizione dell'interfaccia Shape richiedendo una proprietà opzionale "color" (che poi non viene passata più sotto) e un metodo che effettua il calcolo dell'area. In tal modo la funzione calculateArea non deve fare altro che chiamare il metodo getArea dell'interfaccia per ottenere il valore calcolato. Si tratta di un primo passo verso una conversione object oriented dell'esempio. A questo punto potremmo voler implementare l'interfaccia Shape in diverse figure e fornire una diversa formula per il calcolo. Lo possiamo fare grazie alla presenza delle classi. Vediamo come:

   1: interface Shape
   2: {
   3:     width: number;
   4:     height: number;
   5:     getArea(): number;
   6: }
   7:  
   8: class Triangle implements Shape
   9: {
  10:     constructor(
  11:         public width: number,
  12:         public height: number) { }
  13:  
  14:     getArea(): number {
  15:         return this.width * this.height / 2;
  16:     }
  17: }
  18:  
  19: class Square implements Shape
  20: {
  21:     constructor(
  22:         public width: number,
  23:         public height: number) { }
  24:  
  25:     getArea(): number {
  26:         return this.width * this.height;
  27:     }
  28: }
  29:  
  30: function calculateArea(s: Shape): void
  31: {
  32:     var area = s.getArea();
  33:     console.log(area.toString());
  34: }
  35:  
  36: calculateArea(
  37:     new Square(20, 30));
  38: calculateArea(
  39:     new Triangle(20, 30));

Grazie alla keyword "class" è possibile creare delle vere e proprie classi che, a differenza di quello che succede per le interfacce, che spariscono nel codice Javascript, generano una struttura che chi è avvezzo a Javascript riconoscerà sicuramente.

   1: var Triangle = (function () {
   2:     function Triangle(width, height) {
   3:         this.width = width;
   4:         this.height = height;
   5:     }
   6:     Triangle.prototype.getArea = function () {
   7:         return this.width * this.height / 2;
   8:     };
   9:     return Triangle;
  10: })();

Nel precedente snippet abbiamo anche la dimostrazione che una classe può implementare una specifica interfaccia, per mezzo della keyword "implements" e così facendo il compilatore verificherà a tempo di compilazione che la classe supporti i metodi e le proprietà da essa richieste. Siamo a questo punto arrivati ad una programmazione ad oggetti del tutto raffinata, che poco ha a che vedere con la complessità cui si è abituati con Javascript, totalmente mascherata dal compilatore Typescript.

Oltre all'implementazione di interfacce è del tutto possibile estendere classi esistenti. Per fare questo dovremo utilizzare la keywork "extends" al posto di "implements". Vediamo come usare l'ereditarietà per create una classe "Cube" derivando da "Square":

   1: class Cube
   2:     extends Square
   3: {
   4:     constructor(
   5:         width: number,
   6:         height: number,
   7:         public depth: number)
   8:     {
   9:         super(width, height);
  10:     }
  11:  
  12:     getArea(): number
  13:     {
  14:         return (super.getArea() * 2) +
  15:                (this.depth * this.width * 2) +
  16:                (this.depth * this.height * 2);
  17:     }
  18: }
In questo esempio vediamo che al costruttore della classe viene aggiunto un ulteriore parametro "depth" che identifica l'altezza del parallelepipedo. Avendo modiificato la firma il compilatore richiede che la prima chiamata nel body del costruttore sia la funzione "super" che ha lo scopo di chiamare il costruttore della classe base. Questa deve essere specificata come faremmo usando "base" in C#. La medesima keyword può essere usata anche per chiamare i metodi della classe base. Ad esempio il metodo getArea richiama l'omonimo della classe base per poi sfruttare il risultato integrando la rimanente parte dell'area.

Usare i moduli

Una volta che abbiamo classi e interfacce i benefici che ne derivano sono numerosi, soprattutto in termini di organizzazione logica del codice e di manutenzione. Il passo successivo è di organizzare il codice in moduli - i programmatori C# li conosceranno meglio come "namespace" - per riuscire a creare vere e proprie librerie i cui nomi siano univoci. Anche in questo Typescript ci aiuta; grazie alla keyword "module" infatti sarà possibile creare dei veri e propri namespace:

   1: module Shapes
   2: {
   3:     export class Square implements Shape
   4:     {
   5:         constructor(
   6:             public width: number,
   7:             public height: number) { }
   8:  
   9:         getArea(): number
  10:         {
  11:             return this.width * this.height;
  12:         }
  13:     }
  14: }

Interessante notare che la classe definita nel modulo "Shapes" è stata decorata con "export". Infatti, una volta che abbiamo messo una classe (o qualunque altro costrutto) in un modulo possiamo renderlo visibile o invisibile all'esterno beneficiando di un incapsulamento che in termini di librerie riutilizzabili è prezioso.

Come si è abituati a fare con i namespace in C#, anche in Typescript i moduli possono essere annidati in modo del tutto analogo, creandoli effettivamente l'uno nell'altro:

   1: module Shapes
   2: {
   3:     export class Square implements Shape
   4:     {
   5:         constructor(
   6:             public width: number,
   7:             public height: number) { }
   8:  
   9:         getArea(): number
  10:         {
  11:             return this.width * this.height;
  12:         }
  13:     }
  14:  
  15:     export module ThreeD
  16:     {
  17:         export class Cube extends Square
  18:         {
  19:             // ... omissis
  20:         }
  21:     }
  22: }

Oppure usando una notazione puntata

   1: module Shapes.ThreeD
   2: {
   3:     export class Cube extends Square
   4:     {
   5:         // ... omissis
   6:     }
   7: }

Ciascuna delle due notazioni può essere tranquillamente utilizzata assieme all'altra creando vere e proprie composizioni in cui i moduli si combinano. Una volta che i moduli sono stati creati sarà possibile raggiungere i tipi definiti nei moduli specificando l'intero namespace:

   1: var square: Shapes.Square;
   2: var cube: Shapes.ThreeD.Cube;

Data la notevole lunghezza e ridondanza che i nomi completi di namespace possono raggiungere è del tutto possibile creare degli shortcut che siano in grado di semplificare la scrittura del codice:

   1: import sh = Shapes;
   2: import sh3d = Shapes.ThreeD;
   3:  
   4: var square: sh.Square;
   5: var cube: sh3d.Cube;

Come a casa propria

Sono convinto che i programmatori C#, ma in generale qualunque sviluppatore sia avvezzo all'uso di un linguaggio evoluto basato sui paradigmi della programmazione ad oggetti, leggendo il codice Typescript si senta bene come a casa propria. In effetti se si da uno sguardo veloce al codice generato dal compilatore si comprende come Typescript sia in grado di fornire strumenti che la programmazione Javascript può dare solo a caro prezzo. Per intenderci vediamo un esempio di cosa sia possibile fare:

   1: module Shapes
   2: {
   3:     export interface Shape
   4:     {
   5:         width: number;
   6:         height: number;
   7:         getArea(): number;
   8:     }
   9:  
  10:     export enum ShapeType
  11:     {
  12:         Square,
  13:         Triangle
  14:     }
  15:  
  16:     export class ShapeFactory
  17:     {
  18:         static create(type: ShapeType, width: number, height: number): Shape
  19:         {
  20:             switch (type)
  21:             {
  22:                 case ShapeType.Square:
  23:                     return new Square(width, height);
  24:                 case ShapeType.Triangle:
  25:                     return new Triangle(width, height);
  26:             }
  27:  
  28:             return null;
  29:         }
  30:     }
  31:  
  32:     class Triangle implements Shape
  33:     {
  34:         constructor(
  35:             public width: number,
  36:             public height: number) { }
  37:  
  38:         getArea(): number
  39:         {
  40:             return this.width * this.height / 2;
  41:         }
  42:     }
  43:  
  44:     class Square implements Shape
  45:     {
  46:         constructor(
  47:             public width: number,
  48:             public height: number) { }
  49:  
  50:         getArea(): number
  51:         {
  52:             return this.width * this.height;
  53:         }
  54:     }
  55: }
  56:  
  57: import sh = Shapes;
  58: var sq = sh.ShapeFactory.create(sh.ShapeType.Square, 20, 30);
  59: console.log(sq.getArea());
Credo che la combinazione di moduli, classi, interfacce ed enumeratori di questo esempio, assieme con l'applicazione di metodi statici e dell'incapsulamento nei moduli sia molto significativa di come si possa scrivere con proprietà un codice molto efficace.

Come indica il nome "TypeScript", una delle principali ragioni dell'introduzione di questo linguaggio, è la necessità di risolvere uno dei maggiori problemi di Javascript, ovvero la mancanza si un sistema di tipi verificato staticamente. Dire che Javascript non sia tipizzato è un errore, infatti nella realtà esso dispone di un certo numero di tipi, i quali però vengono risolti a tempo di esecuzione e non a tempo di compilazione. Questo può portare a errori comuni che si possono verificare come vere e proprie eccezioni oppure come più subdoli errori logici. Vediamo il seguente esempio:

   1: var a = 10;
   2: var b = '32';
   3: console.log(a + b);

Il risultato di questo snippet Javascript è la implicita concatenazione di stringhe che deriva dalla conversione del valore numerico 10 in stringa per ottenere il risultato finale "1032" anzichè, come ci si potrebbe attendere 42. In un linguaggio che ha il controllo dei tipi a tempo di compilazione, questo tipo di operazione non sarebbe mai arrivata all'esecuzione e il problema non si sarebbe posto. L'intervento del compilatore sarebbe intervenuto indicando che è impossibile applicare l'operatore '+' tra numerici e stringhe.

Pur prendendo origine da codice Javascript e producendo come output sempre Javascript, Typescript ha l'intento di aggiungere questa verifica statica, a tempo di compilazione, che prevenga gli errori suddetti consentendo così la realizzazione di applicazione real-world in cui sarebbe inamissibile/costoso il rischio di arrivare con un errore in produzione. Il supporto al type-checking in Typescript inizia fin da subito grazie alla capacità di inferire i tipi dall'utilizzo e applicare il risultato di questa inferenza come vere e proprie dichiarazioni di tipo. Vediamo uno snippet di esempio:

   1: function getArea()
   2: {
   3:     var width = 20;
   4:     var height = '30';
   5:     var area = width * height / 2;
   6:     alert(area);
   7: }

Il risultato della compilazione di questo codice - che ad una attenta analisi contiene due palesi errori che Javascript rivelerebbe solo a runtime - come facilmente intuibile è il seguente:

(5,15): Operator '*' cannot be applied to types 'number' and 'string'
(6,4): Supplied parameters do not match any signature of call target

In buona sostanza avviene proprio che il compilatore inferisce il tipo delle variabili width, height e area e sulla base del risultato determina che l'operazione di moltiplicazione "width * height" e il passaggio di un valore numerico ad "alert" sono errati. Possiamo ovviamente correggere rapidamente l'errore e beneficiare dell'aiuto offerto dal compilatore ma in Typescript possiamo anche tutelarci da ulteriori errori esprimendo esplicitamente il tipo delle variabili come segue:

   1: function getArea()
   2: {
   3:     var width: number = 20;
   4:     var height: number = 30;
   5:     var area: number = width * height / 2;
   6:     alert(area.toString());
   7: }

La differenza in questo caso non è immediatamente apprezzabile se non nel fatto che, riproducendo l'errore precedente esprimendo il valore '30' come stringa, l'errore sarà evidenziato nell'esatto punto in cui si verifica:

(4,25): Cannot convert 'string' to 'number'

Il beneficio diventa più evidente se introduciamo dei parametri di ingresso della funzione, ai quali venga applicato il calcolo:

   1: function getArea(width, height)
   2: {
   3:     return width * height / 2;
   4: }
   5:  
   6: var area = getArea(20, '30');
   7: alert(area.toString());

Il problema in questo caso passa inosservato anche all'inferenza in quanto i due parametri vengono interpretati di tipo "any". Quest'ultimo è il tipo che Typescript adotta come "nativo" delle variabili Javascript  e ad esso è impossibile applicare alcuna verifica. Per questo motivo l'operazione "width * height" passa il controllo perchè "any" potrebbe contenere un "number". A tutela di questa situazione esprimere il tipo dei parametri è essenziale:

   1: function getArea(width: number, height: number) : number
   2: {
   3:     return width * height / 2;
   4: }
   5:  
   6: var area = getArea(20, '30');
   7: alert(area.toString());

"any", "number", "string" and "bool" sono i soli tipi primitivi disponibili in Typescript ma grazie ad essi il codice, come dimostra la funzione qui sopra, risulta decisamente più solido e al sicuro da sorprese.

Tuttavia Typescript è in grado di fare molto di più applicando il concetto di "structural typing". Questo concetto è in grado, con il minimo dispendio in termini di codice, di gestire anche i tipi impliciti tipici di Javascript. Facciamo un esempio per chiarezza:

   1: function getArea(s: { width: number; height: number; }): number
   2: {
   3:     return s.width * s.height / 2;
   4: }
   5:  
   6: var area = getArea({ width: 20, height: 30 });
   7: console.log(area.toString());

In questo esempio la dichiarazione del parametro "s" impone che esso debba avere almeno le proprietà "width" e "height". A questo parametro sarà possibile passare l'istanza di qualunque tipo che soddisfi questo requisito minimo. Nelle riga 6 ad esempio viene fornito un JSON che rispetta questo vincolo. Rimuovendo l'uno o l'altro delle proprietà il compilatore ci avviserà che il tipo non è conforme alle aspettative:image

Inutile rimarcare l'utilità di questa caratteristica che ha un valore decisamente importante nella tutela del codice. Ricordo che, pur se in questo esempio l'intervento di Visual Studio rende più leggibile la condizione di errore, è chiaro che essa è attribuibile al compilatore perciò sarà evidenziata con un messaggio di errore anche se il codice è scritto con un editor alternativo (notepad, Vim, Emacs, SublimeText, etc...).

Interessante notare che, nella dichiarazione del parametro possiamo rendere opzionale uno dei campi, salvo poi avere l'onere della verifica. A titolo di esempio modifichiamo il tipo di cui sopra aggiungendo la proprietà "color".

   1: function getArea(s: { width: number; height: number; color?: string; }): number
   2: {
   3:     if (typeof color !== "undefined")
   4:     {
   5:         // qui posso usare "color".
   6:     }
   7:  
   8:     return s.width * s.height / 2;
   9: }
  10:  
  11: var area = getArea({ width: 20, height: 30 });
  12: console.log(area.toString());

La proprietà color, grazie all'utilizzo del carattere "?", è a tutti gli effetti opzionale e di conseguenza alla riga 11, una istanza che contiene solo "width" e "height" è perfettamente ammissibile. Naturalmente all'interno del metodo sarà necessario effettuare il controllo per "undefined" allo scopo di evitare errori.

La potenza dello "structural typing" è tale che potremmo applicarla non solamente a proprietà, ma anche a funzioni e metodi. una delle caratteristiche dei metodi Javascript, è spesso di richiedere il passaggio come argomento di funzioni di callback. Mediante una opportuna dichiarazione sarà possibile verificare la firma del metodo passato come gestore del callback:

   1: function getArea(
   2:     s: { width: number; height: number; },
   3:     callback: (area: number) => void): void
   4: {
   5:     callback(
   6:         s.width * s.height / 2);
   7: }
   8:  
   9: getArea({ width: 20, height: 30 },
  10:     function (area)
  11:     {
  12:         console.log(area.toString());
  13:     });

In questo esempio è simulato una chiamata asincrona, in cui il metodo gestore deve ricevere un valore di tipo "number". Il requisito è espresso mediante la dichiarazione con l'operatore "=>" (arrow), da non confondere con le lambda expression di C#. Passando come argomento un metodo che non rispetti il requisito, il compilatore ci avviserà puntualmente dell'anomalia:

image

E' del tutto evidente che i costrutti che abbiamo visto finora sono propri di Typescript. Tali dichiarazioni rispettano i dettami delle nascenti specifiche Ecmascript 6.0 ma a tutti gli effetti sono poi trasformate in un codice che sarà compatibile con Ecmascript 3.0 o 5.0 a scelta. Dato che queste ultime specifiche non supportano il controllo di tipo al suo interno questo sarà rimosso ma lavorando sempre con Typescript potremo beneficiare di un controllo "not provably safe" ma sufficiente a consentirci una sicurezza molto più vicina a quella di un linguaggio di alto livello.


Mi è stato segnalato che talvolta il debug di typescript sembra non funzionare. ll debugger mostra i breakpoint con il classico pallino bianco anzichè con quello rosso pieno, ad indicare che non è in grado di trovare le informazioni di debug.

Il problema è capitato a me stesso e sono arrivato a comprenderne la ragione, almeno quella relativa la mia problematica. Per fare in modo che il debug funzioni correttamente è necessrio referenziare il file "non minimizzato" nella pagina html. Infatti la mappa generata dal compilatore (il file .map) fa riferimento a questo file. Se invece, come ho fatto io referenziate il file ".min.js" Visual Studio non è in grado di trovare la corrispondenza e il debug non funziona.

A questo punto rimane però il dubbio... dato che non esistono direttive di compilazione che si possano applicare all'HTML, come faccio a referenziare il file ".min.js" al momento del deploy della release?


Se mi guardo indietro mi vedo, numerosi anni fa, seduto sulla panchina del binario 3 della stazione di Venezia Mestre - probabilmente in attesa del treno che mi portava al lavoro - mentre leggo avidamente di un interessante linguaggio che Netscape aveva realizzato e Microsoft aveva introdotto in Internet Explorer 3.0; tale Javascript. La lettura, del tutto tecnica e didascalica ebbe la capacità di svegliare quelle attenzioni per le questioni "Rich Internet" che tutt'oggi mi accompagnano in varie esperienze.

Javascript, infatti, fu allora la risposta alle necessità che fin da subito permearono l'esperienza dello sviluppo di applicazioni web, in cui il gap nella user experience era talmente ampio rispetto quella della classiche applicazioni desktop da risultare indigesto ai più. Poter in qualche modo accedere alla dinamicità della pagina sul client e migliorare l'interazione con l'utente, era una necessità sentita e in qualche modo Javascript, in compagnia di DHTML, apriva un barlume di speranza.

Paradossalmente, oggi a distanza di almeno 17 anni da allora - in termini informatici almeno un paio di ere geologiche - Javascript è assurto al linguaggio per eccellenza, non esclusivamente dedicato allo sviluppo "rich" ma ormai con ampi spazi anche server-side. Dopo essere passati per numerose esperienze, che hanno visto alti e bassi, corsi e ricorsi, parziali abbandoni e ritorni, alla fine l'unico vero linguaggio che può vantare l'aggettivo "cross-platform" è Javascript.

Ma nonostante la longevità, anche nella sua più recente standardizzazione che va sotto il nome di EcmaScript 5.0, Javascript soffre dei problemi tipici dei linguaggi di scripting. In particolare la mancanza di tipi e la sua peculiare visione dell'object-orientation che omette concetti importanti quali l'incapsulamento e l'ereditarietà. A causa di questi problemi, nello sviluppo di applicazioni reali Javascript diventa un linguaggio ostico e, troppo spesso, pericoloso per la sua capacità di digerire qualunque cosa salvo poi scoppiare nel momento peggiore e cioè dopo il rilascio in produzione.

Dn163601.78CFF275500F1DB4436598BF65141A6A(it-it,MSDN.10).png

E' questa la ragione per cui molti si stanno orientando ad un nuovo tipo di strumenti, che abbia la capacità di tutelare lo sviluppatore mediante la type-safety e una programmazione object oriented vera, senza però perdere tutti gli indiscutibili vantaggi di Javascript con il cross-platform in testa a tutti. Microsoft in questo campo si sta muovendo rapidamente con la presentazione di un nuovo linguaggio denominato Typescript, giunto oggi alla versione 0.8.2.

Pur trattandosi di una preview e omettendo ancora molti costrutti che uno sviluppatore normalmente si potrebbe aspettare, Typescript è un linguaggio sofisticato che ha la preziosa caratteristica di estendere Javascript, senza però richiedere un "interprete" nuovo nel browser, perchè il risultato della sua compilazione è Javascript. Un sorgente Javascript è a tutti gli effetti un sorgente Typescript perfettamente valido. Un sorgente Typescript genera comunque e sempre un sorgente Javascript valido. La parte del leone la fanno qui il compilatore "tsc.exe" e l'IDE di sviluppo, che anche se non necessariamente deve essere Visual Studio 2012, qualora lo si utiizzi è in grado di portare l'esperienza di sviluppo a livelli del tutto paragonabili a quelli che si hanno con linguaggi di alto livello come C#.

Ma andiamo con ordine: le prime prove con Typescript si possono già fare online nel playground. Il compilatore Typescript infatti è scritto in Typescript - per inciso è anche open source - perciò è in grado di girare perfettamente all'interno del browser e in questa pagina è possibile scrivere, compilare e provare le prime righe di questo linguaggio, vedendone al contempo il risultato in termini di javascript prodotto. In alternative è possibile scaricare i tool per Visual Studio e avere così una esperienza integrata, garantita da alcuni template e da un editor suddiviso in due aree che mostrano assieme sorgente e compilato.

Possiamo quindi sperimentare facilmente, e per farlo proviamo ad immettere il seguente codice nell'editor online oppure se preferite in Visual Studio 2012:

   1: function calculateHypotenuse()
   2: {
   3:    var c1 = 5;
   4:    var c2 = '2';
   5:    var hy = Math.sqrt(c1 * c1 + c2 * c2);
   6:    alert(hy);
   7: }

Ad un occhio attento appare evidente che, purtrattandosi di codice perfettamente legale per Javascript, esso poi genererà un errore di runtime dovuto al fatto che il valore di c2 è impostato come una stringa invece che come un valore numerico, richiesto dalla funzione Math.sqrt(). Inoltre, un po' meno evidente ma anch'esso sorgente di un ulteriore errore, il valore hy ritornato è un numerico e non può essere passato direttamente alla funzione alert() che richiede una stringa. Il codice così com'è incollato nell'editor di Visual Studio ci metterà immediatamente in guardia proprio a causa dei suddetti problemi:

Dn163601.8B3D2FD3F499553C04C1E790E9A91B60(it-it,MSDN.10).png

Visual Studio 2012, mediante le sottolineature in rosso evidenzia il problema, pur trattandosi di codice Javascript senza alcun costrutto particolare di Typescript.

Il compilatore Typescript infatti è in grado di inferire il tipo delle variabili dal loro utilizzo e di conseguenza segnala l'anomalia. Ovviamente, nella parte laterale, il codice Javascript non sarà generato ma sarà sostituito da un commento che riporta gli errori riscontrati.

Piuttosto che correggere semplicemente gli errori, lavorando con typescript, però possiamo blindare il codice dichiarandone i tipi.

Qui sotto vediamo il codice modificato e possiamo notare che a questo punto l'errore, visualizzato da Visual Studio, si è spostato nel punto, più opportuno, in cui avviene l'assegnazione. Il tooltip stesso evidenzia la causa dell'errore molto chiaramente. Poco sotto, parzialmente nascosto dal tooltip, viene usato toString() per fornire una stringa ad alert.

Dn163601.87DF99060FE245829E025F8DB6D090ED(it-it,MSDN.10).png

La sintassi di Typescript è piuttosto semplice e leggera rispetto a javascript, lasciando per quanto possibile inalterato il codice originario. Il proposito del team è di mantenere per quanto possibile una compatibilità con lo standard Ecmascript 6.0 in corso di definizione, così da mantenere sempre inalterato il paradigma che sostiene che un sorgente Javascript è un Typescript valido. Una volta corretto l'ultimo errore nell'esempio avremo finalmente un output Javascript come segue:

   1: function calculateHypotenuse() 
   2: {
   3:      var c1 = 5;
   4:      var c2 = 2;
   5:      var hy = Math.sqrt(c1 * c1 + c2 * c2);
   6:      alert(hy.toString());
   7: }

Questo esempio banale, è però significativo e dà la misura di come, grazie al supporto di uno strumento di sviluppo quale il compilatore e in parte dell'IDE di Visual Studio 2012 in grado di sfruttarlo opportunamente, saremo in grado di scrivere codice di qualità che tuteli il nostro operato evitando che i normali errori si presentino nei momenti meno opportuni.

Typescript contiene una serie di altre feature molto importanti, come la definizione di interfacce e tipi custom, che lo arricchiscono di una espressività che spesso è limitata dai costrutti molto arzigogolati di Javascript. Spesso tali feature sono del tutto sostitutive e simulano a compile time feature che Javascript non include. E' il caso ad esempio dei metodi e delle proprietà private che, pur non essendo supportate da Javascript in alcun modo, in Typescript trovano applicazione e un eccellente supporto di intellisense in Visual Studio 2012. Il codice compilato naturalmente perderà questa caratteristica ma solo dopo che essa ha perso la sua utilità.


In seguito alla pubblicazione del nuovo sito della , sono per un po' tornato alle origini e sto cercando di seguire il posizionamento delle pagine su Google. Una cosa che mi ha divertito molto quest'oggi è il risultato della indicizzazione di un PDF che per un po' di tempo mi ha fatto scervellare. Ecco una immagine di come appare al momento l'indicizzazione:

Capture

In compagnia di , abbiamo cercato di scoprire l'origine del problema, che appariva piuttosto incomprensibile dato che quella frase non è per nulla presente nel PDF. Questo finchè doc, ha provato a fare copia e incolla del testo su notepad e l'arcano è da subito diventato chiaro. Per creare una sorta di effetto profondità, chi ha creato il PDF ha sovrapposto numerose volte la stessa frase. Questa sovrapposizione è mal digerita da Google che vede il tutto come una frase unica con le lettere ripetute più volte.

Da questo se ne può ricavare una morale. Quando pubblicate sul web, provare sempre a ragionare come un BOT e semplificate il più possibile, non solo in funzione del peso delle pagine ma anche in funziona di quello che il BOT leggerà sulla vostra pagina.


CaptureLavorando ad un piccolo sito realizzato completamente in HTML mi sono imbattuto in uno strano problema relativo la Compatibility View. Il problema un po' subdolo causava un rendering diverso del sito quando era chiamato con "localhost" piuttosto che con il nome della macchina.  Alla fine mi sono reso conto che nelle impostazioni del browser (in Tools->Compatibility View Settings) di default i siti intranet vengono visualizzati in "Compatibily View".

Si tratta con tutta probabilità di una precauzione per evitare che siti intranet vengano "rotti" dalle nuove versioni, tuttavia la cosa mi ha causato svariati grattacapi perchè molti dei margini degli oggetti venivano renderizzati completamente sbagliati. Il fatto è che in realtà sia "localhost" che il nome macchina vengono riconosciuti da Internet Explorer 8 come Intranet, tuttavia pare che la Compatibility View non venga applicata a "localhost".

Alla fine ho risolto forzando con un meta tag la visualizzazione normale:

   1: <meta http-equiv="X-UA-Compatible" content="IE=8" />

Così facendo le impostazioni del browser vengono trascurate e il sito viene visualizzato correttamente in ogni caso.

Ok, torno a Silverlight... per fortuna :P


CaptureLavorando ad un piccolo sito realizzato completamente in HTML mi sono imbattuto in uno strano problema relativo la Compatibility View. Il problema un po' subdolo causava un rendering diverso del sito quando era chiamato con "localhost" piuttosto che con il nome della macchina.  Alla fine mi sono reso conto che nelle impostazioni del browser (in Tools->Compatibility View Settings) di default i siti intranet vengono visualizzati in "Compatibily View".

Si tratta con tutta probabilità di una precauzione per evitare che siti intranet vengano "rotti" dalle nuove versioni, tuttavia la cosa mi ha causato svariati grattacapi perchè molti dei margini degli oggetti venivano renderizzati completamente sbagliati. Il fatto è che in realtà sia "localhost" che il nome macchina vengono riconosciuti da Internet Explorer 8 come Intranet, tuttavia pare che la Compatibility View non venga applicata a "localhost".

Alla fine ho risolto forzando con un meta tag la visualizzazione normale:

   1: <meta http-equiv="X-UA-Compatible" content="IE=8" />

Così facendo le impostazioni del browser vengono trascurate e il sito viene visualizzato correttamente in ogni caso.

Ok, torno a Silverlight... per fortuna :P