Confessions of a Dangerous Mind

Brain.FlushBuffer()
posts - 91, comments - 166, trackbacks - 315

giovedì 27 novembre 2008

Distributed Dataset in uno scenario Multi-Tier [1]

Il .net Framework 3.5 e Visual Studio 2008 hanno portato una ventata di novità nel mondo dello sviluppo .net. Linq, Entity Framework, le novità di ASP.net e molte altre cose utilissime e capaci di rendere più "snello" il lavoro di tutti i giorni. Tutte queste novità hanno però messo in ombra una grossa innovazione che è stata introdotta nei Dataset Tipizzati: i Dataset Distribuiti.

NOOO! Io odio i Dataset!

Fermi tutti! Se siete arrivati fino a qui ci sono due possibilità: o amate i dataset, o li odiate! E' proprio così, il Dataset, questo amato/odiato oggetto, è da sempre al centro della diatriba tra puristi dell'architettura e pragmatici del risultato. Io non sono pro o contro Dataset; questo ci tengo a dirlo subito. Semplicemente scelgo lo strumento più adatto allo sviluppo che deve essere intrapreso, tenendo in considerazione il maggior numero di parametri che mi possono aiutare durante la scelta, senza preconcetti.

Per taluni progetti, soprattutto semplici applicazioni Client-Server, il dataset è stato ed è un'ottima soluzione. Uno dei problemi di cui soffriva il dataset tipizzato era quello di immagazzinare in un' unica classe i dati relativi alle "Entità" (Tabelle) e all'accesso ai dati (TableAdapter). Questo, unito al fatto che in uno scenario di applicazioni distribuite per utilizzare le stesse entità tra il client (solitamente uno SmartClient) e l'applicazione server (Web Service) doveva per forza essere condivisa l'intera classe del dataset attraverso i vari "Tiers" applicativi, ha da sempre limitato l'uso del Dataset quale strumento per la realizzazione di applicazioni distribuite.

Molti di noi (me compreso) hanno trovato delle soluzioni a questo problema, ad esempio condividendo gli schemi xsd del dataset attraverso gli strati applicativi. Il problema maggiore, comunque, è rappresentato dalla mancanza di un ambiente integrato per una gestione "ragionata ed organizzata" del Dataset Distribuito.

Distributed DataSet: to the rescue!

Ma cos'è un Dataset Distribuito? E soprattutto, che cosa lo distingue da un Dataset tipizzato tradizionale? La risposta è semplice:

Un dataset distribuito è molto simile ad un dataset tipizzato, tranne per il fatto che tutte le entità che modellano le tabelle del nostro DB vengono collocate e compilate in un progetto, e quindi in una dll, separata rispetto al progetto nel quale viene implementato l'accesso ai dati.

Per scendere nel pratico, se creiamo un progetto Northwind.DataAccess, dobbiamo creare anche un progetto Northwind.Entities che conterrà le classi relative alle entità. Questo progetto viene mantenuto sincronizzato rispetto al progetto Northwind.DataAccess, in modo che alla variazione di tabelle (aggiunta di colonne) o all'aggiunta di tabelle stesse, il progetto Entities non perda coerenza. Tutto l'accesso ai dati che consiste in query e stored procedures, rimane completamente all'interno del progetto DataAccess.

Quest'ultima osservazione ci può far intuire come la dll Entities possa agevolmente essere utilizzata attraverso i vari tiers applicativi, con ovvi pro:

  • in una applicazione SmartClient è possibile utilizzare, creando una referenza ad essa, la dll delle entità per sfruttare i meccanismi RAD di Visual Studio ed effettuare binding a design-time come se avessimo il Dataset disponibile localmente
  • è possibile utilizzare le entità attraverso i tiers in modo trasparente, in quanto il dataset mantiene lo stato delle modifiche ad esso apportate atttraverso i vari tiers
  • è possibile creare applicazioni completamente "tier-unaware", ovvero creando dei provider configurabili attraverso file di configurazione si riesce ad utilizzare lo stesso SmartClient in configurazione Client-Server o n-Tier senza dover modificare logiche di binding o dover riscrivere classi per effettuare lo stesso

Naturalmente, ci sono anche dei contro, peraltro abbastanza importanti:

  • condividere classi attraverso i vari tier può essere limitante. Una modifica della classe ci obbliga a riaggiornare ogni strato che fa uso della dll contente le classi, e non sempre questo è possibile o consigliabile
  • l'impiego dei Dataset non è "pulito" quanto l'impiego di un Domain Model (POCO)
  • la semplicità e la trasparenza del sistema può invogliare a trasferire troppi dati tramite il Dataset, occupando così troppa banda. Il problema può essere mitigato se si progettano con attenzione quelli che poi saranno i metodi di scambio dati tra i tiers.

Conclusioni

In questa prima overview abbiamo chiarito le differenze tra un Dataset Distribuito ed un normale Dataset TIpizzato. Ci sono moltissime altre particolarità da vedere, ma cercheremo di sondarle nel prossimo articolo, assieme con la nostra soluzione per l'impiego effettivo dei dataset distribuiti.

posted @ giovedì 27 novembre 2008 22.59 | Feedback (0) |

giovedì 20 novembre 2008

Natale, luminarie e sprechi

Stamattina sono uscito e ho fatto un giro nella zona commerciale della mia città. Ho visto in diversi centri commerciali un grande fermento per l'installazione delle luminarie di Natale.

Questa cosa mi fa letteralmente andare in bestia. Anche quest' anno, verranno sprecati migliaia e migliaia di Euro in energia per "fare natale". Ora, io AMO il Natale, ma non mi si venga a dire che in un periodo di crisi economica come quello che stiamo attraversando, c'è l'assoluto bisogno di sprecare energia, che per il nostro paese è uno dei beni di consumo con il costo più alto.

In TV passano le pubblicità che invitano a risparmiare, abbassando la temperatura dei radiatori, spegnendo le luci inutili, chiudendo l'acqua mentre ci si lava i denti... e queste luminarie? Perchè non le spegnamo per questo Natale? Perchè i centri commerciali non prendono il denaro che hanno a Budget per i costi delle luminarie e non lo devolvono in beneficenza alle associazioni per la lotta contro il cancro o le malattie rare, o per aiutare i bambini malati?

Non è buonismo il mio, si badi bene; chi mi conosce sa che sono tutto tranne che buonista. Il Natale o si sente o non si sente. Non saranno certo delle luminarie a farci sentire meglio, più buoni o meglio disposti verso il nostro prossimo.

Pensiamoci!

posted @ giovedì 20 novembre 2008 15.57 | Feedback (5) |

giovedì 13 novembre 2008

Inter-Process Communication Techniques: Message Queue

Riprendiamo lo scenario del post precedente: abbiamo un sistema di raccolta ordini formato da una applicazione web, un servizio che funge da "dispatcher" ed un sistema di terze parti che è fuori dal nostro controllo, ovvero non possiamo intervenire direttamente su di esso, bensì possiamo solamente usare delle primitive TCP/IP per accedervi.
La criticità del sistema consiste nella possibile congestione delle connessioni TCP/IP al sistema di terze parti, connessioni che risultano limitate da problematiche tecniche e di licensing.
Ovviamente le connessioni all'applicazione web sono fuori dal nostro controllo, nel senso che potrebbe connettersi un utente come mille.
L'utilizzo del servizio (broker) interposto tra l'applicazione web ed il sistema di terze parti rappresenta la soluzione del problema, in quanto esso permette di differire l'esecuzione delle funzionalità del sistema di terze parti, serializzando le richieste e comunicando in modo asincrono con l'utente dell'applicazione web.

Il meccanismo che può essere utilizzato per comunicare tra l'applicazione web ed il servizio di windows è MSMQ (Microsoft Message Queue).
MSMQ, integrato nel sistema operatvo, è un server per la gestione di code di messaggi. Esso consente di creare code, immagazzinarvi messaggi, ritornare messaggi di
acknowledge alle applicazioni che lo impiegano. Il tutto è perfettamente integrato in .net grazie al namespace System.Messaging.
Nel codice seguente si può vedere come venga configurato il codice per la creazione della coda e la ricezione dei messaggi all'interno del servizio.

   1: using System.Messaging;
   2:  
   3: private MessageQueue _ordersQueue;
   4:  
   5: public void Start()
   6: {
   7:     string _ordersQueuePath = @".\private$\Orders";
   8:     //Creo o inizializzo la coda di ricezione
   9:     if (MessageQueue.Exists(_ordersQueuePath))
  10:     {
  11:         _ordersQueue = new MessageQueue(_ordersQueuePath);                
  12:     }
  13:     else
  14:     {
  15:         _ordersQueue = MessageQueue.Create(_ordersQueuePath);                 
  16:     }            
  17:     _ordersQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(CodeSapiens.Business.Order) });
  18:     _ordersQueue.MessageReadPropertyFilter.CorrelationId = true;
  19:     //Bind del gestore dell'evento ReceiveCompleted
  20:     _ordersQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(ReceiveCompletedHandler);
  21:     _ordersQueue.BeginReceive();
  22: }
  23:  
  24: private void ReceiveCompletedHandler(Object source, ReceiveCompletedEventArgs asyncResult)
  25: {
  26:     Message m = _ordersQueue.EndReceive(asyncResult.AsyncResult);
  27:     //=====================================
  28:     // Elaboro il messaggio...
  29:     //=====================================                
  30:     CodeSapiens.Business.Order _order = (CodeSapiens.Business.Order)m.Body;
  31:     OrderProcessor _processor = new OrderProcessor();
  32:     _processor.ProcessOrder(_order);
  33:     //Riavvio la ricezione
  34:     _ordersQueue.BeginReceive();
  35: }

L'oggetto OrderProcessor consentirà di elaborare, tramite il sistema di terze parti, l'ordine immagazzinato nella coda, proveniente dall'applicazione web.

La coda andrà configurata impostando Full Control per l'utente NETWORK SERVICE che fa girare il servizio w3wp.exe. Con l'utente NETWORK SERVICE si farà girare anche il servizio "Broker" in modo da uniformare i permessi di accesso alla coda.

Le classi "Order" e "OrderDetail" verranno utilizzate come corpo dei messaggi della coda:

   1: namespace CodeSapiens.Business
   2: {
   3:     [Serializable()]
   4:     class Order
   5:     {
   6:         public Order()
   7:         {    
   8:             this.Details = new List<OrderDetail>();
   9:         }
  10:         public Guid Id { get; set; }
  11:         public int CustomerId { get; set; }
  12:         public string Address { get; set; }
  13:         public string CustomerEMail { get; set; }
  14:         public DateTime OrderDate { get; set; }
  15:         public List<OrderDetail> Details { get; set; }
  16:     }
  17:  
  18:     [Serializable()]
  19:     class OrderDetail
  20:     {
  21:         public OrderDetail(string productId, decimal quantity, decimal price, decimal tax)
  22:         {
  23:             this.ProductId = productId;
  24:             this.Quantity = quantity;
  25:             this.Price = price;
  26:             this.Tax = tax;
  27:         }
  28:         public string ProductId { get; set; }
  29:         public decimal Quantity { get; set; }
  30:         public decimal Price { get; set; }
  31:         public decimal Tax { get; set; }
  32:     }
  33: }

Le Classi saranno serializzabili e dovranno essere immagazzinate nella nostra coda per essere smistate dal servizio. Vediamo dunque il codice utilizzato per indirizzare la coda dalla web application e per immagazzinarvi il messaggio per l'elaborazione differita.

   1: private void SendMessage()
   2: {
   3:     string _ordersQueuePath = @".\private$\Orders";
   4:  
   5:     MessageQueue _ordersQueue = new MessageQueue(_ordersQueuePath);
   6:  
   7:     //Creo l'oggetto Ordine da immagazzinare nella coda
   8:     //Verrà in seguito elaborato dal servizio
   9:     CodeSapiens.Business.Order _order = new CodeSapiens.Business.Order();
  10:     _order.Id = Guid.NewGuid();
  11:     _order.CustomerId = "1";
  12:     _order.Address = "One Microsoft Way";
  13:     _order.CustomerEMail="info@customer.net"
  14:     _order.OrderDate = DateTime.Parse(txtReserveFrom.Text);
  15:     _order.Details.Add(new OrderDetail("ABX12", 2, 20, 10));
  16:     _order.Details.Add(new OrderDetail("XYP51", 2, 20, 10));
  17:     _order.Details.Add(new OrderDetail("ZVB11", 3, 10, 20));
  18:  
  19:     Message _message = new Message();
  20:     _message.Body = _order;            
  21:     _ordersQueue.Send(_message);
  22: }

L'uso della coda ha delle implicazioni positive che possono essere identificate nei punti seguenti:

  • non c'è connessione diretta tra la web application e il database/sistema di terze parti;
  • la sicurezza della coda è controllata dalle ACL del sistema operativo, per cui possiamo decidere che in una coda un processo possa solo leggere o solo scrivere
  • Se, per qualche motivo, il servizio va offline, la coda funge da buffer e non è necessario bloccare la web application. Non appena il servizio ritorna on-line, esso elaborerà i messaggi immagazzinati nella coda durante il periodo di mancato funzionamento
  • non si incorre nel problema della "resource starvation", in quanto un numero di utenti concorrenti potenzialmente molto elevato non va ad attingere direttamente alla risorsa critica (la connessione al sistema di terze parti) bensì alla coda, che ai nostri fini può essere considerata a capacità infinita
  • è possibile implementare meccanismi di elaborazione del messaggio anche molto complessi (validazione ordine) senza irritare l'utente, che non è costretto ad attendere on line l'esecuzione di una pagina web
  • Utilizzando le proprietà di acknowledge dei messaggi inviati e ricevuti ed una cosa amministraiva, è possibile avere la certezza che la cosa di destinazione abbia ricevuto il messaggio inviato dalla nostra applicazione

Concludendo, l'uso di MessageQueue consente di aggiungere un grado di libertà che permette di accoppiare sistemi in modo "lasco"; ulteriori integrazioni saranno possibili in tempi successivi, proprio grazie alla libertà e alla robustezza messa a disposizione dall'infrastruttura MSMQ. Ovviamente sarà nostra cura aggiungere una gestione del logging degli errori e una gestione esaustiva delle eccezioni.

posted @ giovedì 13 novembre 2008 21.41 | Feedback (3) |

mercoledì 29 ottobre 2008

Inter-Process Communication Techniques

Con la sigla IPC (Inter-Process Communication) si intendono tutte le tecniche che permettono di effettuare comunicazione intra-thread o intra processo.

Queste tecniche sono particolarmente utili in ambienti di integrazione, dove è necessario far comunicare sistemi eterogenei in modo da preservare l'utilizzo di risorse o mitigare eventuali rallentamenti dovuti a congestioni dei sistemi.

Tra queste tecniche, su piattaforma Microsoft, possiamo individuare:

Ognuna di queste tecniche presenta i suoi pro e i suoi contro, ma grazie alla perfetta integrazione con il .net Framework e con WCF, MSMQ è una tecnologia testata, robusta, e rappresenta un'ottima scelta per una implementazione di una comunicazione Inter-Processo.

Vediamo in concreto con uno scenario reale l'impiego di una tecnica IPC. Abbiamo un sistema di terze parti cui è possibile accedere tramite protocollo proprietario attraverso socket, ma le connessioni disponibili per l'accesso a questo sistema sono limitate. Si vuole implementare un'applicazione web che dialoghi con questo sistema, senza che questa applicazione abbia accesso diretto (via socket) al sistema di terze parti onde evitare problematiche di starving della risorsa connessione via socket, disponibile in quantità limitata.

La strategia da impiegare è quella di impiegare un broker, rappresentato in concreto da un servizio di windows, che si occupi si formare la connessione al sistema di terze parti, mentre alla nostra applicazione web non resterà che comunicare con il broker.

Qui entra in gioco la tecnica di comunicazione inter processo. Come prima cosa, vediamo un semplice approccio al problema, lasciando ad un successivo post la soluzione basata sul messaging.

Come sappiamo, un'applicazione web può comunicare con un servizio che abbia sovrascritto il metodo OnCustomCommand, in un modo molto semplice, ovvero mediante l'invocazione di un comando, come possiamo vedere negli snippet seguenti. Per primo, il servizio:

   1: namespace CodeSapiens.Services
   2: {
   3:     partial class IPCService : ServiceBase
   4:     {
   5:  
   6:         public IPCService()
   7:         {
   8:             InitializeComponent();
   9:         }
  10:  
  11:         protected override void OnCustomCommand(int command)
  12:         {
  13:             switch (command)
  14:             {
  15:                 case 150: //Identificativo del comando
  16:                     //Esecuzione del comando...
  17:                     break;
  18:                 default:
  19:                     break;
  20:             }
  21:         }        
  22:     }
  23: }

Per finire, il consumer (web application, win application, web service...):

   1: _sc = new ServiceController("IPCService");
   2: //...
   3: public void MyExecuteCommand() 
   4: {
   5:     if (_sc.Status == ServiceControllerStatus.Stopped)
   6:     {
   7:         _sc.Start();
   8:     }
   9:     //Esegue il comando 150
  10:     _sc.ExecuteCommand(150);
  11: }

Questa tecnica, apparentemente banale, è estremamente utile, ma solo nel caso in cui non si debbano passare parametri al servizio, ovvero il comando che viene eseguito sia indipendente da parametri. La tecnica sopradescritta puà essere utilizzata per richiamare un comando da applicazioni web o da web services in modo totalmente trasparente.

Nel prossimo post vedremo come far comunicare in modo espressivamente più "ricco" sistemi indipendenti mediante l'uso di MSMQ.

posted @ mercoledì 29 ottobre 2008 0.54 | Feedback (1) |

martedì 28 ottobre 2008

TimeZoneInfo, una classe molto utile

Nel FW 3.5 è presente una nuova classe per la gestione delle "zone temporali", la classe TimeZoneInfo.

Personalmente ritengo molto utile questa classe, che permette di manipolare efficacemente le date/ore provenienti da diversi server collocati in varie parti del mondo.

Un esempio molto carino può essere ben inquadrato dal seguente scenario: avete un server in California, e questo server deve marcare dei file con una data ben precisa, che deve essere espressa in "tempo italiano" (badate, tempo, non formato!!). Chiaramente, se in un web Service installato su questo server si invoca la DateTime.Now, si ottiene la data/ora espressa nella timezone in cui si trova il server. Ora, volendo riportare tale orario all'orario italiano, andremo incontro ad una serie di criticità:

  • Ora legale/solare: essendo la data in un fuso diverso dal nostro, dovremmo conoscere come l'ora legale venga gestita in quella zona
  • Intervallo temporale tra il fuso di destinazione e quello estero: dovremmo dare per scontato, o meglio, impostare nel file di configurazione, l'intervallo (in ore) che separa il fuso di destinazione e quello estero; in questo caso il problema nasce se in un secondo tempo si vuole spostare il server in una altra zona (cambio fuso)

Impiegando questa classe, è possibile esprimere gli orari in modo assolutamente automatico, usando l'accortezza di lavorare con la data/ora in formato UTC. In questo piccolo esempio possiamo vedere come la classe possa essere utilizzata per enumerare le timezone del sistema e come possa essere impiegata per convertire la data/ora in formato UTC in una data/ora nel formato della timezone desiderata.

   1: namespace TimeZoneTest
   2: {
   3:     class Program
   4:     {
   5:         static void Main(string[] args)
   6:         {            
   7:             foreach (TimeZoneInfo _tzi in TimeZoneInfo.GetSystemTimeZones())
   8:             {            
   9:                 Console.WriteLine(string.Format("{0} {1}", _tzi.StandardName,TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,_tzi)));
  10:             }
  11:             Console.WriteLine();

12: Console.WriteLine(string.Format("West Europe Time: {0}",TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,

TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"))));

13: Console.WriteLine( string.Format("Pacific Time: {0}",TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,

TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"))));

  14:             Console.ReadLine();
  15:         }
  16:     }
  17: }

Ovviamente, nel nostro caso, potremmo avere un metodo nella nostra Web Application che converte la data ora del server nella TimeZone desiderata a prescindere da dove questo si trovi, permettendo di fatto lo spostamento dell'applicazione su server collocati in qualunque parte del mondo.

posted @ martedì 28 ottobre 2008 8.45 | Feedback (0) |

mercoledì 22 ottobre 2008

Application Settings: perchè usarli?

La risposta è molto semplice: perchè rappresentano il modo corretto di memorizzare le informazioni di configurazione delle nostre applicazioni client.

Molti di noi, memori delle applicazioni sviluppate nel passato, dove si faceva un estensivo uso dei file .ini, considerano il file <miaapp>.exe.config alla stregua di questo file ini. In parte è proprio così, perchè alcune impostazioni della nostra applicazione stanno bene all'interno di quel file. Alle volte, però, mi sento chiedere se è possibile scrivere quel file per immagazzinare delle altre impostazioni, magari selezionate dall'utente durante l'utilizzo dell'applicazione. Ovviamente la risposta è sì, si può scrivere quel file, ma è ALTAMENTE sconsigliato. Il perchè è dovuto al fatto che non possiamo sapere dove la nostra applicazione verrà installata, nè possiamo imporre al nostro cliente particolari configurazioni o impostazioni di sicurezza che permettano, ad esempio, ad un utente di scrivere all'interno della directory Program Files.

Sviluppare tutta un'applicazione per poi scoprire che non è compatibile con Vista (ad esempio) solo perchè abbiamo dato per scontato di poter scrivere il file di configurazione nella stessa cartella dove si trova l'eseguibile non è molto bello...

Gli application settings, quindi, vengono in nostro aiuto, in quanto ci permettono di operare una netta separazione tra impostazioni "immutabili" della nostra applicazione, che verranno memorizzate nel file app.config, e le impostazioni utente, che verranno memorizzate all'interno di un file nella directory AppData relativa al nostro utente.

In quella posizione, l'utente corrente può sempre scrivere; sono così scongiurati problemi di sicurezza. Inoltre, questo pattern deve essere applicato sempre nel caso in cui si vogliano distribuire le applicazioni con tecnologia Click-Once, in modo che l'utente possa effettuare le proprie impostazioni liberamente, tanto più che esso non può decidere il percorso di installazione di una applicazione Click-Once.

posted @ mercoledì 22 ottobre 2008 19.03 | Feedback (0) |

mercoledì 1 ottobre 2008

Pubblicare Reports di Reporting Services: RSPublisher

La piattaforma Reporting Services permette di automatizzare moltissime attività di amministrazione: creazione di cartelle, copia e modifica di reports, rendering on-demand dei reports. Essendo un assiduo utilizzatore di RS ho sempre trovato piuttosto scomodo generare gli script per installare i reports presso i clienti, tanto più che spesso le installazioni si fanno in remoto e molte volte non è possibile utilizzare Visual Studio per pubblicare i Report. Il tool a riga di comando RS costringe lo sviluppatore a rimaneggiare lo script di installazione ogni volta che un report viene aggiunto o ne viene modificato il nome.

Per ovviare al problema ho creato un semplice tool, RSPublisher, che permette di generare dei progetti di deployment di Reports, sotto forma di file XML. Sarà poi sufficiente portare il tool, il file di progetto ed i file RDL con sè per pubblicare tutto all'interno del server del nostro cliente. L'interfaccia è molto semplice e permette di configurare in pochi secondi server di destinazione, cartelle, se sovrascrivere o meno i Reports già presenti e creare dinamicamente i datasource condivisi. Inoltre il tool fa una scansione automatica della directory contenente i reports, sollevandoci così dall'onere di scrivere i nomi dei reports da pubblicare.

Se qualcuno di voi vuole provarlo, lo può trovare a questo indirizzo. Critiche, migliorie e richieste sono le benvenute!!!

posted @ mercoledì 1 ottobre 2008 19.08 | Feedback (4) |

martedì 30 settembre 2008

Reporting Services: Formattazione dei Subtotali in un controllo Matrix

Sempre più spesso mi sento porre la seguente domanda: si possono formattare i subtotali in una Matrix all'interno di un Report di Reporting Services?

La risposta è ovviamente si, e senza neppure far uso di intricate formule InScope(...) o IIF(...). La maggior parte degli utenti di Reporting Services sembra non sapere che cliccando il piccolo triangolino verde in alto a destra all'interno della cella relativa al subtotale, nella finestra delle proprietà appariranno una serie di proprietà relative all'oggetto SubTotal, le quali permetteranno di formattare con colori, font e quant'altro il nostro subtotale, rendendo di fatto molto più leggibile il nostro report. Notate che è necessario cliccare esattamente il triangolino verde, e nessun altro punto della cella, pena la selezione dell'oggetto textbox che contiene l'espressione che contraddistingue il subtotale.

posted @ martedì 30 settembre 2008 14.28 | Feedback (2) |

mercoledì 27 agosto 2008

Grazie Lutz Roeder...

La notizia che Lutz Roeder, creatore di Reflector, non si occuperà più del tool PIU' IMPORTANTE per uno sviluppatore .net (Reflector, appunto)  mi dispiace, ma del resto comprendo benissimo che non si può rimanere legati allo sviluppo di uno strumento per troppo tempo, pena una certa "fossilizzazione". Vorrei poter ringraziare pubblicamente Lutz per il lavoro che ha fatto in questi anni, per averci dato uno strumento potente, che ci permette di apprendere e comprendere il funzionamento del Framework .net.

Probabilmente ognuno di noi sarebbe uno sviluppatore meno capace, se non ci fosse stato .net Reflector. Grazie Lutz!

posted @ mercoledì 27 agosto 2008 12.01 | Feedback (2) |

giovedì 24 luglio 2008

How I Got Started in Software Development

Ok, ok... Il buon Andrea Boschin mi ha taggato... e quindi non posso esimermi dal tediarvi con un pò di storia della mia vita "programmativa".

How old were you when you started programming?
A quale età hai cominciato a programmare?

Ho cominciato a programmare a 12 anni. Dopo aver pregato in turco i miei genitori di comprarmi un computer "perchè mi serviva per studiare" (alzino la mano quanti hanno usato questa sporchissima scusa per farsi regalare il computer solo per giocare, esattamente come avevo fatto io), ho ottenuto per natale un Commodore 128.

How did you get started in programming?
Come hai cominciato a programmare?

Lo stimolo, ancora una volta, furono i videogiochi. Da sempre appassionato di video games "da sala", ero un divoratore di Pac-Man, Ghosts'n'Goblins e Space Harrier, per cui volevo emulare le gesta dei programmatori dell'epoca, veri pionieri che facevano stare in 64 miseri Kb delle autentiche perle. Ricordo ancora con nostalgia il racconto dello sviluppo di un videogioco di Andrew Braybrook, su Zzap! (chi se lo ricorda?)

What was your first language?
Qual’è stato il tuo primo linguaggio di programmazione?

Ovviamente il Basic, anzi, il GW-Basic. Ricordo ancora un programma scritto in terza media che calcolava aree e perimetri di tutte le figure geometriche, dati in input i parametri di base della figura.

What was the first real program you wrote?
Qual’è stato il primo programma vero che hai scritto?

Probabilmente un programmino il cui listato era contenuto nel manuale del Commodore 128. Mi sembra di ricordare disegnasse dei cerchi di vari colori sullo schermo.

What languages have you used since you started programming?
Quali linguaggi hai usato da quando hai cominciato a programmare?

Mhhh... troppi per ricordarli tutti... GW-Basic, Logo, Quick-Basic, COBOL, C, C++, VB (dalla versione 1.0), VB.net, C# sono solo alcuni, senza contare quelli accessori (SQL, T-SQL, XML...)

What was your first professional programming gig?
Quando è stato il tuo primo vero lavoro da programmatore?

Ah... bellissima domanda! Ho scritto in Quick Basic e BTrieve (per i più giovani: Btrieve è un ISAM che poteva essere integrato con vari linguaggi) un software per un mio carissimo amico radioamatore per registrare le frequenze radio. Utilizzato tutt'oggi funziona che è un piacere! Il mio primo lavoro "pagato" però (500.000 lire!!) fu un sistema di catalogazione di Fotografie scritto con database Access e VB 5.0.

If you knew then what you know now, would you have started programming?
Con il senno di poi, rifaresti lo stesso il programmatore? Ricominceresti a programmare?

Penso che sviluppare software sia uno dei lavori più belli del mondo, soprattutto per chi, come me, ama creare. Devo però aggiungere anche che non è un lavoro che viene tenuto in considerazione, almeno non nel nostro paese. Un pò di rispetto in più per tutti i "programmatori" (che sono sempre un pò di più di semplici "scrittori di codice") non guasterebbe...

If there is one thing you learned along the way that you would tell new developers, what would it be?

Pensa prima di scrivere! La soluzione migliore è sempre la più semplice...

Se ci fosse una cosa che hai imparato nella tua carriera e che vorresti dire ai giovani programmatori, cosa diresti?

Non scriverti addosso per amore di soluzioni perfette e infinitamente flessibili. Ricorda che una soluzione infinitamente flessibile richiederà tempo infinito per essere implementata... quindi in una parola: concretezza!

What's the most fun you've ever had ... programming?
Qual’è la cosa più divertente che hai programmato?

Ce ne sono tante, ne scelgo due: un Tetris in QB 45 nel 1991, fatto per scommessa con in mio Prof di Informatica; SilverPacMan, scritto in Silverlight 1.1 a distanza di 18 anni dal Tetris, ma che tradisce ancora una volta il mio grande amore per i videogiochi.

Now, let’s tag someone else...
Adesso è l’ora di taggare qualcun’altro...

Andrea Dottor

Marco Trova

posted @ giovedì 24 luglio 2008 19.00 | Feedback (2) |

Powered by: