Scommetto che tutti voi almeno una volta vi siete chiesti come funziona il meccanismo di Visual Studio 2005 che genera i file di codice per le risorse e per i file di configurazione in WindowsForms ma anche i DataSet. Vi confesso che a me ha sempre stuzzicato e spesso e volentieri ho immaginato i vantaggi che ne avrei potuto trarre se fossi riuscito a creare un generatore analogo.

La mia ricerca perciò è partita da quello che appariva essere la sorgente di questi file. Se aprite le proprietà di un qualsiasi file in Visual Studio (tutti tranne quelli di un progetto web...) vi renderete conto che c'è una voce sempre presente. Mi riferisco a "Custom Tool". Tale voce, nel caso dei file da cui viene generato un file sorgente contiene una stringa che a prima vista può apparire in qualche modo legata a .NET. Purtroppo dopo una ricerca approfondita con reflector non si riesce a trovare nulla che possa essere in qualche modo correlato. A questo punto la mia ricerca ha preso la via di Google e in breve sono riuscito a trovare che su gotdotnet esiste un esempio, riferito alle precedenti versioni di Visual Studio .NET 2002/2003. Questo esempio va sotto il nome di BaseCodeGeneratorWithSite. Si tratta di uno zip, che contiene i progetti per le due versioni di VS.NET.

Dovete sapere infatti che questa caratteristica è presente fin dalla prima versione dell'IDE. Addirittura nella versione 2002 le classi che si possono scaricare da gotdotnet erano dichiarate pubbliche negli assembly di Visual Studio ma poi sono state rese private nella versione successiva. Ecco il motivo per cui esse sono state pubblicate sotto forma di file sorgente nelle pagine di gotdotnet. Venendo alla versione 2005, dalle ricerche che ho effettuato ho scoperto che alcune delle interfacce presenti nel progetto di gotdotnet sono nuovamente esposte pubblicamente e si possono trovare nell'assembly Microsoft.VisualStudio.Shell.Interop.dll, che si trova nella GAC.

Tuttavia, il progetto scaricato da gotdotnet, nella versione 2003, e compilato con Visual Studio 2005 fa perfettamente il proprio dovere a testimonianza che il meccanismo di generazione non è affatto cambiato dalle versioni precedenti. Tale meccanismo è decisamente banale e piuttosto "grezzo" se mi passate il termine. Credo infatti che con un minimo di impegno se ne potrebbero trarre delle grandi soddisfazioni, ma attualmente si tratta di un sistema un po' limitato. Ma non è il caso di demoralizzarsi. Anche così com'è si riesce a combinare qualcosa di buono. Se vi scaricate lo zip che ho allegato troverete un Custom Tool, che poi vi spiegherò come installare, che consente qualora specificato su un file xml di generare le classi che operano la sua serializzazione/deserializzazione, alla stessa stregua di quello che si fa con xsd.exe.

Un Custom Tool, altro non è che un componente COM che implementa l'interfaccia IVsSingleFileGenerator, e in quanto tale può benissimo essere realizzato scrivendo un po' di codice in .NET; Questa interfaccia attualmente è esposta appunto dall'assembly che prima citavo, ma è indubbiamente molto più comodo utilizzare le classi BaseCodeGenerator e BaseCodeGeneratorWithSite. Alla fine realizzare un custom tool, a parte il codice necessario per convertire il file in ciò che vogliamo, si limita alle seguenti poche righe di codice:

[Guid("CE1B4057-D10A-4cd6-8E13-29B4699ACEAD")]
public class XmlSerializationCSharpGenerator : BaseCodeGenerator
{
    
public override string GetDefaultExtension()
    {
        
return ".cs";
    }

    
protected override byte[] GenerateCode(string inputFileName, string inputFileContent)
    {
        
// TODO: convertire il file qui
    
}
}

Il primo metodo comunica a VisualStudio l'estensione che dovrà essere usata per il file generato. Tale file avrà lo stesso nome di quello sorgente, salvo che l'estensione sarà cambiata e apparirà come nidificato all'interno del file sorgente stesso. Il secondo metodo invece, ricevuti in input il nome del file e il suo contenuto, si occupa di generare il codice e di restituirlo sotto forma di un array di bytes che Visual Studio si occuperà di salvare nella posizione opportuna. Ecco cosa intendo per "limitato". in effetti con questo meccanismo è possibile creare solo un file per ogni sorgente, e lo si può fare avendo in input esclusivamente il file sorgente. Se si volessero passare dei parametri per customizzare l'output ad esempio, questa possibilità ci sarà negata.

L'ultima cosa da notare nel sorgente che ho riportato è la presenza di un GUID generato casualmente con l'apposito strumento di Visual Studio. Tale GUID è quello che poi dovremmo utilizzare per registrare il Custom Tool nell'IDE di VS2005. Ecco di seguito come operare per l'installazione:

1) innanzitutto occorre compilare il progetto in versione release, ricordando di firmare tutti gli assembly con sn.exe altrimenti non saremmo in grado di registrarlo.

2) ora occorre copiare  gli assembly generati nella posizione in cui desideriamo tenerli. In seguito accederemo a questa directory mediante il prompt di Visual Studio 2005 e lanceremo il seguente comando:

regasm /codebase Elite.VisualStudio.CustomTools.dll

In questo modo avremo registrato i componenti dichiarati nell'assembly in questione che per inciso sono due; Uno per CSharp e uno per vb.net

3) a questo punto occorre aprire regedit e raggiungere questo nodo:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Generators\{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}

4) All'interno di questo nodo occorrerà inserire una chiave il cui nome sarà quello da utilizzare nell'apposita proprietà di un file per applicarvi il nostro Custom Tool.

5) Concludiamo creando i seguenti due valori:

CLSID (String) in cui specificare i guid dei due componenti racchiusi tra graffe

{CE1B4057-D10A-4cd6-8E13-29B4699ACEAD} per XmlSerializationCSharpGenerator
{7CDAAE56-B3A5-4514-9B0E-8BC1E80B1C68} per XmlSerializationVBGenerator

GeneratesDesignTimeSource (DWORD) contenete il valore "1".

A questo punto, senza nemmeno dover chiudere Visual Studio se nel frattempo lo avete lasciato aperto, specificando una delle due stringhe otterrete immediatamente il file cs o vb contenente il codice generato. Per ulteriore chiarimento dovete sapere che la generazione del codice avviene utilizzando lo stesso meccanismo di cui fa uso xsd.exe, con i limiti conosciuti cui bisogna stare attenti. A tali classi vengono aggiunti alcuni metodi statici per facilitare la deserializazione.

Giusto per darvi un'idea delle possibilità che questo strumento mette a disposizione sappiate che nell'esempio allegato ho semplicemente scaricato con ie il feed rss del mio weblog. Poi ho aggiunto questo file ad un progetto e impostato il custom tool mi sono ritrovato tutte le classi necessarie per deserializzarlo e visualizzarli in una piccola applicazione windowsform.

Download: Elite.VisualStudio.CustomTools.zip (301 KB) 

powered by IMHO 1.3


Ho appena concluso con successo un'operazione che consideravo pressochè disperata. Ho fatto il merge di due progetti di Visual Studio in una soluzione che ne contiene ben 64, udite udite, senza l'ausilio di alcuno strumento di Refactoring.

Lo so, sono un temerario. Ma se è stato possibile realizzare questo "extreme refactoring" in un lasso di tempo di 15 minuti, allora non ci sono più scuse. Il refactoring va fatto sempre e comunque, con o senza tools!

powered by IMHO 1.2


Stamane ho avuto una rivelazione. Ero in riunione con un cliente, a proposito di un progetto piuttosto importante, quando quest'ultimo ha fatto un'affermazione che a prima vista potrebbe sembrare banale, ma che ragionandoci sopra mi ha dato una sottile soddisfazione.

L'affermazione è la seguente: "All'inizio abbiamo scritto un documento, poi il modulo è stato realizzato, e ora stiamo riscrivendo il documento per adeguarlo al risultato". Questa frase, buttata li come una battuta, mi è rimasta in testa per tutta la giornata, e rimuginandoci sopra sono arrivato alla conclusione di poter essere contento di quanto è avvenuto.

Infatti, lo sviluppo di questo modulo applicativo, si è svolto proprio come sintetizzato dalla frase. Il documento iniziale era nulla di più che una semplice traccia sulla quale lavorare. Nello scrivere il codice perciò ho scelto di implementare il minimo possibile delle funzionalità e poi di rilasciare una prima versione che a quel punto è diventata il canovaccio sul quale il cliente ha cominciato a provare e a richiedere modifiche.

Così alla fine, il risultato rispetta solo in minima parte ciò che è stato definito nel documento iniziale, ma il feedback del cliente mi fa capire che egli è indubbiamente molto soddisfatto del risultato ottenuto che va molto aldilà delle sue aspettative.

Occorre però segnalare una caso. Il procedere in questo modo ha indubbiamente dilatato i tempi di sviluppo. Questa però è stata una scelta del cliente, che volendo avere l'applicazione il più possibile soddisfacente e completa ha scelto di non considerare il tempo una variabile importante e di posporre così la consegna del modulo.

Meglio non poteva andare: il cliente è contento, l'azienda anche e io ne ho ottenuto una buona dose di soddisfazione. Se questo si può chiamare Agile, allora non c'è dubbio che questa volta si è dimostrato vincente.

powered by IMHO


Segnalo che in questo gruppo di discussione vengono affrontati i temi dell'XP programming con un moderatore di eccellenza. A quanto vedo infatti le risposte sono di Kent Beck in persona. Direi che vale la pena di iscriversi al feed perlomeno.

Fonte: Yahoo! Groups : xpbookdiscussiongroup

Nel gruppo Kent Beck affronta una delle pratiche dell'XP ad ogni settimana, con riferimento alla seconda edizione del suo libro che Marco Abis ci ha segnalato in un suo post.

powered by IMHO 1.2


Sono un po' di giorni che penso a questo post, ma fino ad ora non ero riuscito a trovare i 30 minuti consecutivi necessari per poterlo redarre. L'intento è quello di presentare un caso reale in cui il Refactoring mi è stato di aiuto nella realizzazione di una delle ultime features di IMHO, per l'appunto il sistema di upload dei file verso l'ftp.

Quando ho iniziato il lavoro, le uniche cose che realmente avevo chiare in testa erano i seguenti presupposti:

  1. L'unico modo veramente valido per implementare la feature era di usare il protocollo FTP. Svariate ricerche in rete mi avevano confermato che l'eterogeneità dei motori di blogging lasciava poco spazio a soluzioni più sfiziose.
  2. In secondo luogo era necessario comunque lasciare aperta la possibilità, in futuro di creare soluzioni ad-hoc per ogni motore di blogging.

Armato di pazienza e di queste labili certezze, il primo passo è stato quello di cercare una libreria per l'FTP. Di certo una cosa da escludere subito era la realizzazione ex-novo di tale libreria, non perchè impossibile, ma perchè la sua implementazione avrebbe fatto lievitare inutilmente i tempi di realizzazione. La libreria trovata come sapete è la' edtFTPnet, che alcuni test comparativi mi hanno confermato essere la più affidabile.

A questo punto avrei potuto mettermi davanti ad un foglio di carta e disegnare la soluzione del problema così come sarebbe dovuta nascere, tuttavia dato il tempo scarso, e la mia ormai grande fiducia nel refactoring, ho invece aperto Visual Studio e cercato il punto migliore per innestare il nuovo codice. Alla fine la scelta è caduta sull'aggiunta di un bel metodo virtuale alla classe base degli adapter con i parametri che sembravano più adeguati e nel farne l'override in un solo engine, cosciente del fatto che il codice che avrei scritto al limite andava copiato in tutti gli altri engine.

Questa era una soluzione evidentemente temporanea, non sia mai che io cada nella trappola mortale del cut&paste, ma che mi permetteva innanzitutto di approfondire la problematica facendo funzionare il sistema velocemente. Inoltre, evidenziava una bella questione, ovvero come fare in modo, dovendo fornire a tutti gli engine il medesimo protocollo, di astrarre l'implementazione del protocollo dall'engine stesso.

Ma tutto ciò era materia per i posteri. Innanzitutto occorreva scrivere il metodo che trasferiva i file. E già questa questione apriva altri problemi. Al termine del lavoro, quando l'engine di .TEXT già pubblicava i post mi sono reso conto che lo faceva in modo logicamente errato. Infatti l'engine apriva e chiudeva la connessione ad ogni file inviato. Con un protocollo come l'FTP questo era un problema dannatamente grave, perchè l'handshake iniziale causava un overhead eccessivo. Ovviamente pensandoci bene avrei anche potuto trovarmi in futuro con protocolli diversi (si pensi ad esempio ad un webservice) che non richiedessero una apertura e chiusura della connessione. A questo punto i metodi da uno sono divenuti tre. Due responsabile di aprire e chiudere la connessione, e il terzo che trasferiva i file uno per uno. Un protocollo non connesso, semplicemente poteva lasciare vuoti i metodi Open() e Close().

Risolto questo problema era giunto il momento di estendere il funzionamento agli altri engine. Escluso a priori il cut&paste, in buona ottica oop non rimaneva che separare le responsabilità e creare una classe che si occupasse del trasferimento. E così è stato ed è nata la classe FtpPublisher. A questo punto tutti gli engine trasferivano immagini per mezzo dell'FTP. Il problema a prima vista era risolto. Ma ancora il requisito di cui al punto 2 non era del tutto soddisfatto. E' vero che è sempre possibile riscrivere un metodo, ma è anche vero che è di gran lunga meglio se non lo si fa. Inoltre, era evidente una duplicazione delle funzionalità. GLi engine così come il publisher ftp aveevano entrambi i metodi Open(), Close() e SendFile().

Quindi l'idea è stata quella di estrapolare completamente la logica di trasferimento dall'engine e semplicemente di consentire ad esso di fornire l'istanza di publisher da utilizzare per la pubblicazione. Perciò ho creato la classe astratta Publisher, e ho migrato i metodi Open(), Close() e SendFile() verso il publisher, in particolare l'ftp. A questo punto non rimaneva altro che fare in modo che l'engine creasse l'istanza di publisher e perciò ho creato una proprietà che lo restituisse a chi lo chiedeva. Tutto ciò adeguando poco a poco anche la logica che usava il publisher.

La soluzione era veramente buona. Ma ancora gli mancava qualcosa. Anche i questo caso, sostituire il publisher costringeva a ricompilare. E' stata la reflection alla fine che mi è corsa in aiuto. Modificare la proprietà degli engine per fare in modo che leggessero la classe publisher da file di configurazione è stato un gioco da ragazzi. E a questo punto ero veramente soddisfatto.

Ecco, a conclusione di questo post, vorrei rilevare come, partendo con poche certezze e armati della affilate spade dell'object-orientation e del refactoring si possa ottenere una soluzione ben congegnata, risparmiando di spremere le meningi su problemi che per ovvie ragioni all'inizio sfuggono. Ovviamente questo è il mio modo di procedere, suppongo che altri avrebbero ottenuto soluzioni differenti, ma ritengo che il succo del discorso sia davvero importante: non conta che riusciate a smontare il problema pezzo per pezzo da subito, è molto più probabile che, comportandovi come le onde del mare sulla roccia, riusciate più facilmente ad eroderlo mano a mano che esso presenta le sue parti più friabili.

powered by IMHO


C'è un dubbio che mi rode da un po' di tempo, sullo sviluppo con metodologie agili. Probabilmente deriva dal fatto che mi sfugge qualcosa oppure che proprio non ho capito, ma mi sento di renderlo pubblico, perchè potrebbe essere l'ultima barriera che mi separa dal provare veramente ad applicare queste metodologie anche in campo lavorativo.

Ritengo corretto questo tipo di metodologia perchè può certamente risolvere al meglio i problemi di sviluppo e consente di fornire un prodotto migliore e più adeguato alle esigenze del cliente, ma mi chiedo: come convincere di questo anche il cliente?

Mi spiego meglio. Normalmente quando si inizia una trattativa con un cliente per la realizzazione di un progetto, si lavora per preparare un preventivo. Il preventivo per essere attendibile deve considerare la quantità di lavoro da svolgere, le persone da impiegare e di conseguenza il tempo necessario allo sviluppo. Ma è proprio questo il punto: come produrre un preventivo attendibile adottando una metodologia agile? In realtà non dovrei essere in grado di esprimere all'inizio la quantità di lavoro da compiere e di conseguenza non sarò nemmeno in grado di stabilire il tempo necessario alla sua realizzazione.

Trovo improbabile che un cliente accetti di farmi realizzare un progetto senza sapere con esattezza che cosa spenderà alla fine. Trovo anche scorretto azzardare un prezzo ad occhio, perchè i miei costi potrebbero superare la cifra che ho stabilito e di conseguenza mi troverei nella necessità di abbassare la qualità del software allo scopo di non sforare con i costi.

La risposta a questa domanda è vitale. Spero che qualcuno mi sappia rispondere.

powered by IMHO


Avete presente quei cucchiai di legno che usava la nonna? Ci avete mai fatto caso, che quelli più usati hanno sempre la tendenza ad assumere la medesima forma? Di solito, a causa dell'attrito del fondo della pentola, si consumano e tendono ad appiattirsi da un lato, perchè in realtà il giro che fanno è sempre lo stesso. E, cosa curiosa, alla fine sono quelli che funzionano meglio, perchè è l'uso che ha determinato la loro forma è così essi si sono adeguati e nonostante siano vecchi e consunti fanno il loro lavoro meglio di quelli nuovi.

Ho letto questa osservazione anni fa, non mi chiedete in quale libro, non lo ricordo, però oggi mi è tornata in mente leggendo il post di Lorenzo, che suggerisce, oltre agli orribili "bottoni 3d", di migliorare la possibilità di interazione con i formatter, che in questo momento è certamente ostica, soprattutto nell'uso del formatter per le emoticone che ha creato il buon Simone. Ci lavorerò su, lo prometto, e vedremo se riuscirò a limare un po' il cucchiaio di imho, per fare si che gratti meglio il fondo dela pentola.

Credo che questo debba far pensare un po' alla positività di un approccio di sviluppo agile. Alla fine, se ci pensate, dare la possibilità all'utente di usare quasi da subito il proprio "cucchiaio-software" può fare in modo che quell'antiestetico ma funzionale "scanso", appaia prima che il software sia finito, e così consenta di farlo funzionare al meglio delle sue possibilità già dai primi cicli di elaborazione.

Questa è una opportunità cui credo nessun cliente dovrebbe rinunciare. Partecipare attivamente allo sviluppo del proprio software, gli consentirà di adeguarlo mano a mano alle proprie esigenze, rendendosi conto sul campo delle minuscole modifiche di cui esso ha bisogno, e di come queste modifiche potrebbero addirittura rendere inutili alcune funzionalità che inizialmente sembravano indispensabili.

powered by IMHO