Questo si che è giornalismo…


image

http://www.giornaleditreviglio.it/login.php?artID=1136762

Da notare che sulla versione cartacea la notizia è su 9 colonne… dei veri personaggi inutili… :-D

.m

author: Mauro Servienti | posted @ venerdì 3 luglio 2009 11.21 | Feedback (4)

Misteri dell’etere…


I telefoni cellulari esistono da un bel po’ di tempo ormai ma in questi ultimi anni, diciamo almeno un paio, la sensazione è che la qualità delle comunicazioni (le telefonate in particolare) via cellulare siano drasticamente peggiorate.

Ora… la tecnologia ha fatto passi da gigante quindi l’unica spiegazione che mi do, si lo so sono sempre in malafede… ma si sa siamo italiani e siamo molto abituati ad essere presi per il c*lo, è che qualcuno investa molto in pubblicità ma un gran poco in infrastrutture, quindi il numero di terminali è cresciuto andando ben oltre quello che l’attuale rete è in grado di sopportare/gestire.

Semplici elucubrazioni personali… ma sta di fatto che parlare al cellulare è spesso un’impresa.

.m

author: Mauro Servienti | posted @ venerdì 3 luglio 2009 11.18 | Feedback (0)

UGI.Alt Conf: recap


Sabato sono stato alla IV UGI.Alt Conf tenutasi a Bologna, è stata un’esperiamza decisamente interessante e per la quale non posso far altro che ringraziare tutta l’organizzazione.

Dovevo tenere una sessione, come da agenda, ma alla fine ne ho tenute 2, la seconda (prima in ordine di apparizione) è stata una sessione OpenSpace su Model-View-ViewModel. E’ stata la prima volta come moderatore di OpenSpace e devo dire che è stata un’esperienza interessante di cui magari parlerò in futuro.

Alla fine sono riuscito a seguire una sola sessione per intero, quella su Mono tenuta da Massimiliano Mantione, sessione che avrei voluto seguire già al workshop UGI a Predappio ma che era in parallelo proprio con la mia. La sessione di Massi, imho, è stata perfetta. Il “ragazzo” poi è l’equilibrio fatto a persona, ha una capicità di giudizio scevra da pregiudizi (almeno in ambito informatico) degna di invidia, complimenti.

Sono inoltre decisamente lusingato, e in quanto decisamente orso anche un po’ “intimorito”, dai complimenti che ho letto riguardo le mie sessioni, semplicemente grazie!, è un ottimo stimolo per fare sempre meglio.

Infine, ma non per questo meno importante, anzi, un accenno alla serata pre-conf magnificamente piacevole grazie alla solita inpeccabile ospitalità di casa Scardova, quindi grazie Ale e Lucy!

Carnazza rulez!!! vero Matteo?

.m

P.S. il post contiene un solo link perchè sono in albergo, su gprs…, e la navigazione è semplicemente un delirio… mi perdonate? ;-)

author: Mauro Servienti | posted @ lunedì 29 giugno 2009 22.47 | Feedback (2)

Non sono un test addicted, ma…


Non sono mai stato un “test addicted” nel senso che non scrivo i test per tutto, scrivo i test per molte cose (ed in alcuni casi tendo maniacalmente ad un 100% di Code Coverage), alcune le faccio in TDD, e per altre ritengo semplicemente inutile scrivere test, se non a fronte di un bug dove allora prima scrivo il test, e se assenti, un set di test che mi parino da eventuali regressioni, che lo riproduce poi procedo con la fix.

Credo di avere una minima esperienza da garantirmi un buon deisgn anche se non è emergente, ne è riprova il fatto che tutte le volte che ho dovuto scrivere test su qualcosa di già disegnato non mi sono mai pentito del design; in questo senso c’è anche da dire che l’uso spinto di un tool per Inversion of Control obbliga ad un design di un certo tipo.

Resta il fatto che ci sono momenti, per tutto c’è sempre mastercard sia chiaro, in cui la scrittura di un paio di test toglie dalle grane mostruosamente più rapidamente dell’F5. Sto lavorando ad una cosa in cui la base dati sta in parte dietro un set di servizi quindi per poter “mixare” questi dati con quelli provenienti dal db “locale” mi sono dovuto parzialemnte reinventare la ruota (non ho trovato di meglio e sono aperto a suggerimenti) e mascherare completamente l’ORM dietro una mia “Unit of Work” che sia in grado di fare il dispatch delle chiamate “a destra e a manca” in base al tipo di entità che state chiedendo, simulando ove possibile anche le “join” e altri giochetti. Detto fatto.

Oggi pomeriggio mi sono dedicato alla gestione della IdentityMap e in questo caso gli Unit Test sono una vera manna dal cielo perchè vi permettono di simulare quello che volete senza fare il benchè minimo sforzo:

[TestMethod]
public void dataContext_getByKey_using_identityMap_should_return_the_same_instance()
{
    var paf = MockRepository.GenerateStub<IPersistanceActionFactory>();

    var rp = MockRepository.GenerateMock<IRepositoryProvider>();
    rp.Expect( obj => obj.Resolve<IRepository<StubEntity>>() )
        .Return( new StubEntityRepository() )
        .Repeat.Once();

    var dc = new DataContext( new IdentityMap(), rp, paf );

    var a = dc.GetByKey<StubEntity>( new Key<Int32>() );
    var b = dc.GetByKey<StubEntity>( new Key<Int32>() );

    a.ShouldBeEqualTo( b );

    rp.VerifyAllExpectations();
}

[TestMethod]
public void dataContext_getByKey_then_getAll_using_identityMap_should_return_the_same_instance()
{
    var paf = MockRepository.GenerateStub<IPersistanceActionFactory>();

    var rp = MockRepository.GenerateMock<IRepositoryProvider>();
    rp.Expect( obj => obj.Resolve<IRepository<StubEntity>>() )
        .Return( new StubEntityRepository() )
        .Repeat.Once();

    var dc = new DataContext( new IdentityMap(), rp, paf );

    var a = dc.GetByKey<StubEntity>( new Key<Int32>() );
    var list = dc.GetAll<StubEntity>();

    a.ShouldBeEqualTo( list.ElementAt( 0 ) );

    rp.VerifyAllExpectations();
}

[TestMethod]
public void dataContext_getAll_then_getByKey_using_identityMap_should_return_the_same_instance()
{
    var paf = MockRepository.GenerateStub<IPersistanceActionFactory>();

    var rp = MockRepository.GenerateMock<IRepositoryProvider>();
    rp.Expect( obj => obj.Resolve<IRepository<StubEntity>>() )
        .Return( new StubEntityRepository() )
        .Repeat.Once();

    var dc = new DataContext( new IdentityMap(), rp, paf );

    var list = dc.GetAll<StubEntity>();
    var a = dc.GetByKey<StubEntity>( new Key<Int32>() );

    list.ElementAt( 0 ).ShouldBeEqualTo( a );

    rp.VerifyAllExpectations();
}

Altrimenti l’unica soluzione plausibile è una tonnellata di F5 (che fatti su una solution con 68 progetti non è certo una passeggiata ;-)) uniti a tanta fantasia per capire se nel complesso di quello che l’applicazione sta facendo il vostro componente si sta comportando nella maniera attesa… che equivale ad una soluzione non plausibile ;-)

.m

author: Mauro Servienti | posted @ giovedì 25 giugno 2009 19.01 | Feedback (2)

db4o: update


Qualche giorno fa ho parlato di db4o dal punto di vista dello sviluppatore, devo dire che nell’insieme ho trovato molto interessante il tutto e sto seguendo il feed del team di sviluppo.

Ci sono interessanti novità per quel che riguarda il supporto a linq/IQueryable<T> il che non è niente male, inoltre con la versione 7.10, ancora in beta, viene distribuito gratuitamente anche il db4o ObjectManager (una sorta di Enterprise Manager per db4o) la cosa interessante è che questa versione:

  • ha funzionato al primo colpo, a differenza del predecessore;
  • è un add-in che si integra molto bene in Visual Studio;

image

Inoltre spulciano i vari post ho capito qualcosa in più, nel mio primo post ho parlato delle varie modalità di interrogazione (query) supportate da db4o, definendo la Native Query (NQ) come la modalità nativa, come si evince dalla documentazione allegata, in realtà le cose non sono proprio così:

Da quel che posso intuire dai post che ho letto internamente il motore di db4o utilizza SODA e non NQ, il nuovo supporto per IQueryable<T> infatti adesso trasforma quasi tutto l’expression tree in query SODA, facendo solo in rari casi, per gli operatori non supportati, il fallback a NQ che sostanzialmente si traduce in Linq2Objects che è sempre meglio che una exception ;-).

.m

author: Mauro Servienti | posted @ venerdì 19 giugno 2009 9.30 | Feedback (0)

*DataContext.Log –> log4net…


I vari flavour del DataContext offrono la possibilità di agganciare un “logger” per vedere ad esempio le query prodotte, ad esempio con Linq2Sql avete una cosa del tipo:

using( var dc = new MyDataContext() )
{
    dc.Log = Console.Out;
}

Questo, se avete un debugger attaccato, o siete in un’applicazione Console, scrive sulla Console (Output Window per il debugger) i messaggi di Log del DataContext, tra cui tutte le query T-Sql con i parametri etc etc…

Adesso supponiamo che vogliate scrivere quel log su un vostro sistema di Log, sia esso log4net, come nel mio caso, o il motore di Tracing di .net, poco importa quale sia la destinazione; in tutti i casi l’inghippo è che da una parte avete un TextWriter mentre dall’altra avete un metodo da chiamare tipicamente passando un messaggio sottoforma di stringa.

Per log4net ho trovato questa soluzione abbastanza complessa, a mio modo di vedere, che per inciso non funziona… ;-) o meglio se usate log4net in maniera basilare si, ma se cominciate a fare cose un po’ strane allora ciccia, non da errori ma non scrive nulla. All’inizio ci ho ragionato sopra un po’ cercando di capire quale fosse il problema… poi “blink” :-)

public sealed class ActionTextWriter : TextWriter
{
    readonly Action<String> logger;

    public ActionTextWriter( Action<String> logger )
    {
        Ensure.That( logger ).Named( "logger" ).IsNotNull();

        this.logger = logger;
    }

    public override void Write( string value )
    {
        this.logger( value );
    }

    public override void Write( char[] buffer, int index, int count )
    {
        if( buffer == null || index < 0 || count < 0 || buffer.Length - index < count )
        {
            //let base class to throw exception
            base.Write( buffer, index, count );
        }

        this.logger( new String( buffer, index, count ) );
    }

    Encoding _encoding;
    public override Encoding Encoding
    {
        get
        {
            if( this._encoding == null )
            {
                this._encoding = new UnicodeEncoding( false, false );
            }

            return this._encoding;
        }
    }
}

ActionTextWriter, di una semplicità disarmante: altro non fa che intercettare le chiamate a “Write” del TextWriter e redirigerle sul delegato di tipo Action<String> che gli passate nel costruttore.

Per usarlo quindi, nel mio caso con log4net, mi limito a fare:

static readonly ILog logger = LogManager.GetLogger( typeof( MyRepository ) );
using( var dc = new MyDataContext( this.connectionString ) )
{
    dc.Log = new ActionTextWriter( s => logger.Debug( s ) );
}

Semplice, funzionale e senza seg*e mentali di sorta ;-)

.m

author: Mauro Servienti | posted @ giovedì 18 giugno 2009 11.29 | Feedback (1)

Urka!


Workflow 4.0 –> Flowchart –> Hosting nelle nostre applicazioni –> Spettacolo :-)

.m

author: Mauro Servienti | posted @ giovedì 18 giugno 2009 6.33 | Feedback (2)

Log4PostSharp: note di redazione


Ieri ho parlato di Log4PostSharp come ottimo compagno di viaggio per la scrittura del tracing. Un paio di note per districarsi meglio nella giungla.

Magagna…

Se scaricate Log4PostSharp e cercate di usarlo non va, vi beccate un simpatico errore di compilazione… per qualche strano motivo l’autore ha compilato i suoi assembly utilizzando una reference ad una versione specifica di PostSharp, la 1.0, mentre tipicamente voi potreste avere la 1.0sp1. Nulla di grave:

  1. Scaricatevi i sorgenti dal repository svn di Google (io uso RapidSVN)
  2. Aprite la solution;
  3. Rimuovete le reference a PostSharp.*.dll;
  4. Rimettetele con quelle che avete voi, di default Visual Studio mette Specific Version “false”;
  5. Ricompilate e va tutto che è un piacere;

Mania compulsiva da Beta ;-)

Non fatevi prendere dalla tentazione di ricompilare il tutto per PostSharp 1.5 RC1 perchè compilare compila ma poi non va un bel nulla… causa cambi radicali nel modello di reflection utilizzato da PostSharp. PostSharp infatti utilizza un suo sistema di Reflection al fine di evitare di caricare l’assembly che sta analizzando.

Tip & Tricks

Una necessità a cui potreste andare incontro è quella di avere accesso allo stesso “logger” che state usando con Log4PostSharp ad esempio perchè durante l’esecuzione di un metodo avete bisogno di loggare informazioni in più.

Nulla di più facile, anche grazie a come funziona log4net, avete sempre il vostro bel metodo:

static void Main( string[] args )
{
    var p = new Person();
    p.FirstName = "Mauro";
    p.LastName = "Servienti";

    var x = p.Echo( p );

    Console.WriteLine( x );
    Console.Read();
}

e il prodotto della compilazione è:

image

Quello che potete fare è pressochè la stessa cosa che fa Log4PostSharp:

var logger = LogManager.GetLogger( typeof( Program ) );

var p = new Person();
p.FirstName = "Mauro";
p.LastName = "Servienti";

logger.Debug( "My message..." );

var x = p.Echo( p );

Console.WriteLine( x );
Console.Read();

Recuperate una reference allo stesso logger utilizzato da Log4PostSharp, con il risultato atteso:

image

.m

author: Mauro Servienti | posted @ martedì 16 giugno 2009 7.33 | Feedback (0)

Tracing… che barba che noia :-) <cit.>


Un paio di assiomi ;-):

  • Il Tracing è necessario;
  • Il Tracing è di una noia mortale;

Però… ci sono due macro categorie di Tracing in realtà, io divido tra:

  • Tracing: quello che fa il codice: il metodo tal dei tali è stato invocato con la lista di parametrei xyz;
  • Logging: quello che fa l’utente: l’utente ‘mauro’ alla tal ora del tal giorno ha salvato la tal anagrafica cliente;

Quello che più mi pesa è la prima categoria, facendo un esempio decisamente triviale di quello che siamo abituati a scrivere:

class Program
{
    static TraceSource tracer = new TraceSource( "Program" );

    static void Main( string[] args )
    {
        try
        {
            tracer.TraceEvent( TraceEventType.Verbose, 0, "Entering method..." );

            var p = new Person();
            p.FirstName = "Mauro";
            p.LastName = "Servienti";

            var x = p.Echo( p );

            Console.WriteLine( x );
        }
        catch( Exception e )
        {
            tracer.TraceEvent( TraceEventType.Critical, 0, "Unhandled Exception: {0}", e );

            throw;
        }
        finally
        {
            tracer.TraceEvent( TraceEventType.Verbose, 0, "Exiting method..." );
        }
    }
}

se pensiamo a quanto tempo investiamo nella scrittura, e manutenzione, di quel codice mi viene male, questo in generale a prescindere dallo strumento di Tracing che usiamo.

Introducing AOP with PostSharp

Il tracing è uno di quegli aspetti della programmazione in cui AOP potrebbe fare da padrone, alla fine della fiera quel codice è generalizzabilissimo e varrebbe proprio la pena di farlo.

Ho già parlato più di una volta di PostSharp: qui, qui, qui e qui. Oggi voglio approfondire alcuni concetti e far vedere come lo sto usando con soddisfazione, molta soddisfazione.

AOP: Compile Time Code Injection

PostSharp ragiona in maniera completamente diversa rispetto a tutti i framework che fanno policy/behavior injection, in generale siamo abituati ad un qualcosa fatto a runtime utilizzando il concetto di transparent proxy, viene cioè creato a runtime un proxy che wrappa il vostro tipo e inietta codice e comportamento, è evidente che questo ha un costo in termini di performance; ha anche interessanti vantaggi sia chiaro.

PostSharp invece interviene a compile time, PostSharp incorpora un post-compilatore che interviene dopo la compilazione fatta da MSBuild, disassembla il vostro compilato, inietta il codice e ricompila. Vediamo un esempio proprio in materia di Tracing:

[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry( MethodExecutionEventArgs eventArgs )
    {
        eventArgs.MethodExecutionTag = Guid.NewGuid();
        Console.WriteLine( "--> ctx: {1} - {0}", eventArgs.Method.Name, eventArgs.MethodExecutionTag );
    }

    public override void OnExit( MethodExecutionEventArgs eventArgs )
    {
        Console.WriteLine( "<-- ctx: {1} - {0}", eventArgs.Method.Name, eventArgs.MethodExecutionTag );
    }

    public override void OnException( MethodExecutionEventArgs eventArgs )
    {
        Console.WriteLine( "--- Exception at" );
        Console.WriteLine( "--- ctx: {1} - {0}", eventArgs.Method.Name, eventArgs.MethodExecutionTag );
        Console.WriteLine( "--- Begin of Stack Trace" );
        Console.WriteLine( eventArgs.Exception.StackTrace );
        Console.WriteLine( "--- End of Stack Trace" );
    }
}

Creiamo una classe che deriva da una classe base del framework di PostSharp, in questo caso OnMethodBoundaryAspect che, come lascia intuire il nome, è una sorta di wrapper intorno al codice di un metodo (ove per metodo vengono intesi anche costruttori, proprietà ed eventi).

Torniamo al codice di esempio da cui siamo partiti e trasformiamolo così:

[assembly: TraceAttribute( AttributeTargetMembers = "*", 
AttributeTargetAssemblies = "PostSharp Tracing" )] namespace PostSharp_Tracing { class Program { static void Main( string[] args ) { var p = new Person(); p.FirstName = "Mauro"; p.LastName = "Servienti"; var x = p.Echo( p ); Console.WriteLine( x ); Console.Read(); } } }

Se lo compiliamo e manidamo in esecuzione l’output è questo:

image

Urka :-) praticamente abbiamo “gratis” un trace di tutto quello che è successo nel codice, ma cosa è successo? Apriamo con Reflector l’assembly generato:

image

Il metodo Main() del nostro programma è diventato qualcosa di decisamente diverso, e così tutto il resto. PostSharp ha infatti iniettato una montagna di codice per far si che vengano effettuate le chiamate al codice del nostro attributo.

Non mi dilungo oltre perchè ho parlato a lungo di come funziona, tutto bello però c’è un problema. Se osserviamo bene il codice generato c’è un sacco di overhead che per quello che vogliamo fare è pressochè inutile (per altri usi di PostSharp è una manna ma per il tracing non serve proprio a nulla). L’overhead è in soldoni questo:

  • MSBuild compila il vostro codice;
  • PostSharp disassembla e deve iniettare le chiamate;
  • Quello che però deve fare non è chiamare il vostro codice perchè non ha idea di come farlo non conoscendolo… deve quindi creare un generico e flessibile ponte: programma –> infrastruttura di PostSharp –> codice di tracing –> infrastruttura di PostSharp –> programma;

E’ evidente che questo costa…

Ma non tutto è perso, anzi. PostSharp mette a disposizione anche un livello di intervento decisamente più basso, chiamato Weaver, che vi consete di inserirvi direttamente nel processo di Post-Compilazione al fine di emettere direttamente codice… IL…

Naturalmente lungi da me intraprendere questa impervia ed ardua strada, soprattutto se altri lo hanno già fatto ;-)

Log4PostSharp

Dopo aver seguito i passi per il setup di tutto l’ambaradan possiamo cambiare il nostro codice in questo modo:

[assembly: XmlConfigurator( Watch = true )]
[assembly: Log( AttributeTargetMembers = "*",
    AttributeTargetAssemblies = "PostSharp Tracing",
    EntryLevel = LogLevel.Debug,
    ExitLevel = LogLevel.Debug )]

namespace PostSharp_Tracing
{
    class Program
    {
        static void Main( string[] args )
        {
            var p = new Person();
            p.FirstName = "Mauro";
            p.LastName = "Servienti";

            var x = p.Echo( p );

            Console.WriteLine( x );
            Console.Read();
        }
    }
}

L’unica differenza evidente sono le dichiarazioni in testa, aggiungiamo l’attributo XmlConfiguration che istruisce log4net (utilizzato come framework di logging da Log4PostSharp) su come gestire la configurazione e rimpiazziamo il nostro attributo TraceAttribute con LogAttribute incluso nella librearia Log4PostSharp, ricordiamoci anche di aggiungere la configurazione di log4net nel file app.config:

<configSections>
  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>

<log4net>
  <appender name="consoleAppender" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" />
    </layout>
  </appender>

  <root>
    <level value="ALL" />
    <appender-ref ref="consoleAppender" />
  </root>
  
</log4net>

Ecco il nuovo metodo Main dopo la Post-Compilazione:

image

Le differenze sono evidenti, non c’è più traccia di tutta l’infrastruttura di PostSharp (che infatti non è più una dipendenza a runtime per il nostro programma) ma troviamo solo del sano codice di tracing molto simle (naming a parte) a quello che potremmo scrivere noi. Ed ecco il risultato a runtime con la configurazione di log4net di cui sopra:

image

Di nuovo urka ;-)

Un paio di note:

  1. il codice iniettato non interferisce in alcun modo con la debug-experience;
  2. Il codice di tracing dipende da log4net e vi obbliga all’uso di log4net; utilizzando la prima tecnica che abbiamo visto sarebbe abbastanza facile utilizzare IoC/DI nel TraceAttribute per iniettare a runtime il motore di tracing ma:
    1. IMVHO: non ne vale la pena neanche dipinti sui muri ;-)
    2. Generalizzare il sistema di Tracing vi porterebbe ad avere un’infrastruttura di Tracing veramente povera, vedasi come esempio quella di Castle Windsor, perchè le uniche feature che potreste esporre sono il minimo comun denominatore delle feature messe a disposizione dai motori di tracing che volete supportare;
    3. Generalizzare/cambiare il motore di tracing con la seconda tecnica ha invece un costo altissimo perchè dovete essere dei mezzi guru di IL e della generazione di codice a compile-time… quindi viva log4net ;-)

Quali sono i side effects, sempre che ce ne siano? in generale io per ora ne ho trovato uno solo: i tempi di build si allungano sensibilmente perchè la post-compilazione costa, ma se lo paragono ai benefici il caffè che mi bevo tra una build è l’altra è tempo molto ben speso ;-)

Una cosa che ho fatto è stata però ricompilare il plugin Log4PostSharp per la versione 1.5 di PostSharp, la versione originale è per la 1.0, perchè il post-compiler della 1.5 è mostruosamente più veloce.

Per quello che rigarda il Logging continuo a farlo a mano, ma quello ha anche aspetti interessanti e problematiche curiose che val la pena affrontare.

.m

Technorati Tags: ,,,

author: Mauro Servienti | posted @ lunedì 15 giugno 2009 10.55 | Feedback (2)

Spettacolo!


dopo quello che ho visto ieri in Moto GP per quel che mi riguarda la Formula 1 può tranquillamente chiudere i battenti.

Semplicemente fantastico

.m

author: Mauro Servienti | posted @ lunedì 15 giugno 2009 9.07 | Feedback (2)