Tempo fa ho introdotto PostSharp, dal primo approccio è passato ormai un anno e da qualche mese lo uso con soddisfazione, in produzione, per la gestione della parte noiosa del tracing.
In questi giorni ho ripreso in mano la parte di AOP per la validazione dei parametri di input di un metodo, tipicamente quello che si fa è questo:
void StandardValidation( String v )
{
if( v == null )
{
throw new ArgumentNullException( "v" );
}
}
oppure, evolvendosi leggermente, si può scrivere questo:
void EnsureValidation( String v )
{
Ensure.That( v ).Named( "v" ).IsNotNull();
}
che è effettivamente più elegante e anche leggibile (pensatelo proiettato in produzione e quindi applicato in uno scenario complesso). Resta però il fatto che è da scrivere e che sta li in mezzo ai piedi, ricorrendo a PostSharp si può arrivare a questo:
void AspectValidation( [NotNull]String v )
{
}
che ha lo stesso identico risultato e inoltre ha il pregio notevole, IMHO, di non avere nulla in mezzo ai piedi.
E le perfomance?
tutto bello e funzionale, ma le prestazioni che fine fanno? come al solito dipende da quali sono le nostre necessità: non abbiamo un problema di prestazioni finchè qualcuno non ci dice che va piano.
detto questo però ho voluto provare un test molto casalingo ma ridotto all’osso in modo che l’unica variabile fosse proprio o il codice per la validazione o il codice per il tracing.
Qui di seguito uno screenshot con i risulati, interessanti direi.
- la prima batteria di test è un’iterazione (100k volte) chiamando un metodo con 1 solo parametro, come nel codice di esempio del post, che esegue la validazione tradizionale;
- la seconda è sempre un’iterazione di 100k volte che però chiama un metodo, nei tre modi noti, con 5 parametri… con risultati curiosi: la validazione classica cuba un tempo doppio ma comunque irrilevante, la validazione con le fluent interface, “Ensure”, invece scoppia passando da 198ms a 955ms, pessimo non c’è che dire; la terza invece curiosamente è quella che in termini percentuali perde pochissimo nonostante tempi comunque molto alti in termini assoluti;
E’ altresi vero che se misuriamo la singola chiamata il tempo in tutti i casi scende a 0ms, il terzo test viene penalizzato dall’infrastruttura di PostSharp 1.5 che permette cose mirabolanti ma in questo scenario inutili, il tutto in attesa di PostSharp 2.0 (oggi in CTP1) che promette, e i test iniziali lo dimostrano, di fare una “code injection” intelligente e quindi eliminare l’overhead a runtime ove non necessario.
Il secondo test, quello del tracing/logging, in effetti fa questo, in questo caso la fa con uno Weaver per PostSharp 1.5, uno Weaver è un plugin per PostSharp che inietta codice custom direttamente a compile time scrivendo esattamente il codice che scriveremmo noi senza aver bisogno del runtime di PostSharp, che infatti non è più una dipendenza a runtime. Il piccolo problema, sempre in attesa di PostSharp 2.0, è che scrivere un Weaver è un delirio :-)
CompileTimeValidate
Una nota infine su quella che secondo me è una delle feature migliori e più sottovalutate di cui ho già parlato. In attesa di “Compiler-As-A-Service” di cui si sa poco o nulla sarebbe un gran bello avere degli attributi che vengono considerati dal compilatore come ad esempio ObsoleteAttribute.
Si… può… fare…! <cit.>
Non vi tedio con i dettagli tecnici, che ci sono nel post che ho linkato, ma mi soffermo sul fatto che mentre con la versione 1.0 era impossibile fare molte cose a compile time con la 1.5 si può fare pressochè tutto permettendo di intervenire nel processo di compilazione e ad esempio validare anche cose che per il compilatore sarebbe impossibile anche solo prendere in considerazione.
.m
Technorati Tags:
AOP,
PostSharp