Il framework 4.0 “is on the way”, c’è ancora molta strada da fare ma se non altro la via è stata imboccata; cominciano a girare un po’ di documenti sulle novità che verranno introdotte con il nuovo runtime e i cominciano anche a sprecarsi i post su “dynamic”, sui valori di default per i parametri etc… evito che è meglio ;-)

E’ ovvio che rivoluzioni come Linq si vedono una volta nella vita quindi secondo me non ha senso lamentarsi dell’apparente veste poco rivoluzionaria del nuovo framework, se però scaviamo a fondo, sotto sotto ci sono tante belle cose…

Una delle cose che mi attraggono e che verranno incluse nel nuovo runtime sono i Code Contracts, che sono già “utilizzabili” ora anche con VS2008, utilizzabili tra virgolette perchè l’attuale licenza permette solo sperimentazioni e nulla di più.

Vediamo di approfondire un po’ la questione:

class OrderProcessor
{
    public void Process( Order order )
    {
        
    }
}

ipotizziamo una situazione elementare come quella esposta, quello di cui dobbiamo preoccuparci è l’inevitabile e tedioso controllo della validità dei parametri in ingresso, classicamente quello che possiamo fare è:

class OrderProcessor
{
    public void Process( Order order )
    {
        if( order == null )
        {
            throw new ArgumentNullException();
        }
    }
}

se usiamo un pizzico di AOP possiamo scrivere una cosa decisamente più smart:

class OrderProcessor
{
    public void Process( [NotNull]Order order )
    {
        
    }
}

e otteniamo lo stesso identico comportamento. Ma non è tutto oro quel che luccica, purtroppo ;-), e quello che ci manca, e che a me piacerebbe molto è la possibilità di avere questo controllo direttamente a compile time, del resto quella non è logica di business ma è un constraint “punto”.

Vediamo cosa possiamo fare con i “Code Contracts”, una volta scaricato e installato il tutto quando creiamo un nuovo progetto di Visual Studio ci troviamo qualcosa in più, nella pagina delle proprietà c’è infatti una nuova tab:

image

se quindi aggiungiamo una reference all’assembly “Microsoft.Contracts” e riproviamo a compilare il codice del primissimo esempio, quello senza nessun controllo sui parametri, succede questo:

image

toghissimo!, Visual Studio al termine della compilazione invoca un nuovo tool (cccheck.exe) che fa analisi statica del codice e stabilisce che li c’è un potenziale problema. Già questo, a mio modo di vedere sarebbe, o meglio sarà, una vera manna dal cielo.

Ma non è finita, per eliminare il warning è sufficiente fare in modo che il codice sia safe quindi ad esempio rimettere il check sui parametri:

class OrderProcessor
{
    public void Process( Order order )
    {
        if( order == null )
        {
            throw new ArgumentNullException();
        }
    }
}

a questo punto Visual Studio compila felice come una pasqua, ma non è detto che questo ci basti, se questo è una condizione sufficiente a proteggerci a runtime rimane sempre la fastidiosa situazione che il tutto avviene a runtime mentre se avvenisse a compile time saremmo molto più felici.
Come fare in modo che Visual Studio si lamenti se trova una situazione come questa:

OrderProcessor op = new OrderProcessor();
op.Process( null );

Con Code Contracts è decisamente semplice:

public void Process( Order order )
{
    CodeContract.Requires( null != order );
}

aggiungendo questa dichiarazione e ricompilando quello che otteniamo è:

image

dove il primo warning con un doppio click ci porta al punto nel codice in cui c’è la condizione, mentre il secondo ci porta al punto in cui la condizione viene violata. La cosa fighissima è che funziona anche se il codice che “recupera” l’istanza di Order è decisamente complesso.

Faccio notare che Visual Studio genera degli Warning e, secondo me, è giusto così del resto il codice dal punto di vista del compilatore è corretto l’IDE ci informa solo dei potenziali problemi a cui potremmo andare incontro.

In questo esempio, quindi, per far si che il controllo statico a compile time passi senza warning è sufficiente soddisfare il contratto:

class Program
{
    static void Main( string[] args )
    {
        Order o = Compless.GetOrder();
        if( o != null )
        {
            OrderProcessor op = new OrderProcessor();
            op.Process( o );
        }
    }
}

E’ quindi il chiamante che deve assicurarsi di effettuare i controlli di rito. Avendo soddisfatto il contratto succede un’altra cosa molto interessante, se spulciamo con il fido Reflector il codice generato scopriamo che non vi è traccia alcuna:

image

Questo porta all’indubbio vantaggio che le performance ne giovano perchè i controlli sulla coerenza dei parametri in ingresso vengono fatti solo ed esclusivamente dove hanno senso, notiamo infatti che un’eventuale chiamata del tipo:

op.Process( new Order( 100 ) );

viene perfettamente digerita.

Ci sono però delle casistiche in cui potremmo volere che il controllo venga effettuato anche a runtime, un “classico” esempio potrebbe essere quello della Class Library, noi scriviamo la libreria e altri la usano, tutto ciò è possibilissimo, basta cambiare la dichiarazione:

public void Process( Order order )
{
    CodeContract.RequiresAlways( null != order );
}

e il fido Reflector conferma:

image

Garantendoci un’exception a runtime se il contratto non fosse rispettato.

Ma andiamo oltre, è si non è finita :-D…

Supponiamo di trovarci nella casistica appena esposta, il nostro ruolo è quello di developer di framework e non conosciamo chi saranno i nostri utilizzatori ma non vogliamo neanche il potenziale impoverimento delle perfromance che il controllo a runtime potrebbe comportare: si può fare <cit.>

Condizione necessaria è abilitare sul/i progetto/i class library la generazione di un assembly per i contratti, quello che succede a questo punto quando compiliamo è che vengono generati 2 assembly/progetto: uno con la class library vera e prorpia e uno con i soli contratti. Sempre dal fido Reflector scopriamo che se il codice che compiliamo è questo:

public void Process( Order order )
{
    CodeContract.Requires( null != order );

    Int32 qty = order.ItemQty;
}

il prodotto sarà nella class library:

image

mentre nell’assembly dei contratti:

image

sulla macchina dell’utilizzatore il motore di analisi statica del codice sarà nuovamente in grado di fare tutti i suoi ragionamenti e verificare il codice che accede alla class library notificando i potenziali problemi, garantendo anche all’utilizzatore che il contratto sia stao rispettato.

Quello che abbiamo visto è solo una piccola parte di quello che si può fare, le varie “assert” possibili con Code Contracts sono veramente tante, la documentazione fortunatamente, anche se ridotta ad un semplice pdf, è esaustiva.

Una cosa di cui non ho parlato, ma che è decisamente potente, è che c’è anche la possibilità di esprimere contratti sulle interfacce, eccezziuuunale veramente <cit.>

Attenzione: è una cosa in divenire… e come tale va presa con le pinze. Quello che sappiamo è che:

  • ci sarà nella RTM del fx 4.0;
  • i nomi cambieranno: CodeContract –> Contract;
  • molto probabilmente non sarà più un assembly Microsoft.Contracts e quindi non sarà più necessario aggiungere la reference a mano, con il CLR v4.0 il namespace System.Diagnostics.Contract sarà definito in mscorlib.dll;

Se mettiamo insieme i 3 mondi TDD/UnitTesting + Code Contracts + PEX abbiamo in mano la possibilità di avere controllo quasi totale su quello che sta succedendo per il resto c’è il fidato e inseparabile debugger… come cosa è PEX?!?!?!: http://research.microsoft.com/pex/ …prossimo post… abbiate fede :-D

Che dire a me piace un sacco… CodeContract.Requires( ( Mauro as IHappyDeveloper ).BeginUsing() );

.m