Web Log di Lorenzo Melato

ASP.NET MVC, Castle, NHibernate e altre passioni...
posts - 43, comments - 168, trackbacks - 52

martedì 25 febbraio 2014

Aperte le iscrizioni per gli appuntamenti di TO, NA e BA del “AngularJS, CQRS ed Event Sourcing on tour”

Ciao a tutti,

sono aperte le iscrizioni per gli appuntamenti di Torino, Napoli e Bari del tour.

E’ possibile trovare tutte le informazioni a questo link nel blog di Ynnova.

Stiamo inoltre valutando alcune possibilità di “formazione finanziata” per agevolare le aziende o i professionisti che fossero interessati al tour con l’obiettivo di finanziare in parte o in toto i costi di partecipazione.

Per fare questo abbiamo bisogno di fare un piccolo censimento per “tastare” l’interesse e strutturale l’iniziativa con una azienda partner che ci supporterà con la burocrazia necessaria.

Prego tutti gli interessati di contattarci al più presto lasciando un commento a questo post o scrivendo a formazione AT ynnovahq DOT com.

Ciao!

Lorenzo

posted @ martedì 25 febbraio 2014 13:00 | Feedback (0) |

martedì 11 febbraio 2014

[ANN] AngularJS, CQRS and Event sourcing on tour (PD, TO, BA, NA)

Ciao a tutti,

con grande orgoglio comunico l’avvio del booking di “AngularJS, CQRS and Event sourcing on tour”.

Con questa iniziativa formativa, organizzata da Ynnova e Mauro Servienti di Managed Designs, racconteremo in 8 appuntamenti in giro per l’Italia i pro e contro di queste interessantissime tecnologie e come queste stesse possono aiutarci a sviluppare applicazione più belle, più robuste e perché no, anche in modo più veloce.

In due + due giorni, ci focalizzaremo nei dettagli più intimi, rispettivamente, di Angular e CQRS, scriveremo tanto codice e porteremo a casa una applicazione scritta da zero che potremmo utilizzare dal giorno dopo come base per sviluppare le nostre applicazioni.

Il booking è già aperto per gli appuntamenti di Padova, qui sotto i link per l’iscrizione:

Iscrizione al corso di AngularJS a Padova
Iscrizione al corso di CQRS a Padova

molto presto attiveremo anche le iscrizioni per gli appuntamenti di Torino, Napoli e Bari.

Qui sotto il link all’annuncio ufficiale nel blog di Ynnova:

http://ynnovahq.com/it/latest-news/cqrs-eventsourcing-e-angularjs-on-tour/

Che dire ancora…

Il docente lo conoscete, le tecnologie anche… non resta che iscriversi al tour!

Lorenzo

posted @ martedì 11 febbraio 2014 19:17 | Feedback (0) |

mercoledì 9 ottobre 2013

Manning Publications sponsor del corso di RavenDB a Padova il prossimo 28/29 Ottobre

Dettagli qui: http://ynnovahq.com/it/latest-news/it-manning-publications-sponsor-del-corso-di-ravendb-del-2829-ottobre-a-piove-di-sacco-pd/
C'è un ultimo posto disponibile per il corso. Chi si fa avanti e chiude il booking? ;-)

posted @ mercoledì 9 ottobre 2013 13:58 | Filed Under [ .NET Development ]

mercoledì 11 settembre 2013

Nuovi posti disponibili per il corso di RavenDB del 28/29 ottobre a Padova

Ciao a tutti,

si sono liberati alcuni posti per il corso di RavenDB del prossimo 28/29 Ottobre a Padova.
Il docente sarà Mauro Servienti. Dettagli qui:

http://ynnovahq.com/it/latest-news/it-annuncio-corso-di-ravendb-piove-di-sacco-pd-28-29-ottobre-2013/

Affrettatevi! E' una occasione da non perdere per approfondire questa meravigliosa tecnologia con un docente d'eccezione!

posted @ mercoledì 11 settembre 2013 13:23 | Filed Under [ Tools & Downloads ]

lunedì 29 luglio 2013

Pubblicata l'agenda del corso di RavenDB del prossimo Ottobre a Padova

La trovate qui. L.

posted @ lunedì 29 luglio 2013 16:13 | Filed Under [ .NET Development ]

giovedì 25 luglio 2013

Chi sarebbe interessato ad un corso su RavenDB a Padova?

In azienda stiamo cercando di organizzare un corso di due giorni su RavenDB a Padova, indicativamente nel corso del prossimo mese di Ottobre.

Il docente, d'eccezione, sarà un teacher ufficiale di RavenDB.
Il corso sarà probabilmente orientato all'ultima versione, la 2.5, e partirà dalle basi per arrivare fino alle funzionalità più avanzate.
C'è l'intenzione di riservare del tempo anche alle best practice per l'utilizzo con Windows Azure.

Chi fosse interessato mi può contattare attraverso il mio profilo linkedin o lasciando un commento qui sul blog.

Il corso si farà se riusciremo a trovare almeno dieci persone interessate.

Ciao!

posted @ giovedì 25 luglio 2013 10:06 | Filed Under [ .NET Development ]

lunedì 15 febbraio 2010

[OT] Vi presento Alberto Melato

Ieri mattina 14 febbraio alle ore 8.56, a distanza di esattamente 2 anni dalla sorellina Claudia è nato Alberto, che, come la sorellina, pesa esattamente 3300g!

Alberto Melato

Un enorme grazie a mia moglie Erika che è riuscita nella titanica impresa di cullare nel pancione questo bambolotto per 9 mesi e nello stesso a tempo tenere a bada e a non far mai mancare una coccola e una carezza al mio diavoletto:

Claudia Melato

Auguro a tutti voi le mie stesse soddisfazioni.


Technorati Tags: ,

posted @ lunedì 15 febbraio 2010 19:00 | Feedback (14) |

domenica 1 novembre 2009

Horn Web live!!!

E’ di qualche ora fa l’annuncio di Paul Cowan che la versione “live” di horn è online:

http://www.hornget.net/packages/

Se avete letto il mio post di qualche giorno fa sapete che horn è un software che permette di scaricare e installare in maniera totalmente automatizzata una svagonata di librerie e framework open source tra i più usati nel mondo .net.

Ora gli autori hanno fatto di più. Hanno messo a disposizione un sito che una volta al giorno si scarica tutti i sorgenti aggiornati dei pacchetti, li compila, e ce li mette a disposizione sotto forma di binari belli e pronti.

Complimenti a Paul e a tutti quelli che hanno collaborato a questa magia.

Technorati Tags:

posted @ domenica 1 novembre 2009 23:53 | Feedback (3) |

Rhino commons e il giardinaggio

Chi di voi utilizza in qualche progetto l’ottimo framework Rhino commons sa bene che il progetto è fermo da un po’ di mesi e che Rhino commons fa (faceva) parte dell’ottima suite di strumenti Rhino tools sviluppati nel corso degli anni dall’iperproduttivo Ayende.

Qualcuno probabilmente si sarà accorto scaricando il trunk di Rhino tools che allo stato attuale non è possibile compilare Rhino Commons perchè Ayende, da qualche settimana, sta rimettendo a posto la solution estrapolando tutti i vari progetti e spostandoli su github. Qui trovate l’elenco completo:

http://github.com/ayende

Fatto sta che a me Rhino Commons mi serve per un progetto e mi serve che giri con il trunk di Castle e con NHibernate 2.1ga.

Così, d’accordo con Paul Cowan, leader del progetto horn, di cui vi ho già parlato qui, ho deciso di fare un po’ di giardinaggio alla solution di Rhino Commons: l’ho estrapolato dalla gigantesca solution di Rhino tools, ho sostituito le dipendenze dai progetti con dipendenze ai binari e ho sostituito lo script di build originale di nant con un nuovo script di build basato su psake, come ha già fatto Ayende per tutti gli altri progetti di Rhino tools.

Il risultato lo trovate qui:

http://github.com/lorenzomelato/rhino-commons

il progetto compila e i test passano tutti quanti.

Attualmente il codice è quello della revisione r2200 del repository svn originale, ma conto sul mio poco tempo disponibile e sull’aiuto della community per sistemarlo in modo da farlo girare con il trunk di Castle e NHibernate 2.1.

Paul Cowan promette che a breve sarà possibile installare il “nuovo” Rhino Commons anche da Horn.

Technorati Tags: ,

posted @ domenica 1 novembre 2009 23:44 | Feedback (1) |

mercoledì 21 ottobre 2009

Training kit per VS2010 e .NET framework 4

Se a qualcuno fosse sfuggito, vi segnalo che qui potete scaricare il training kit per VS2010 e .NET framework 4.

Sono una serie di Hand-on-labs, presentazioni e demo su questi argomenti:

C# 4.0
Visual Basic 10
F#
Parallel Extensions
Windows Communication Foundation
Windows Workflow
Windows Presentation Foundation
ASP.NET 4
Windows 7
Entity Framework
ADO.NET Data Services
Managed Extensibility Framework
Visual Studio Team System

Ho visto che c’è qualcosa anche su ASP.NET MVC 2.

Technorati Tag: ,,

posted @ mercoledì 21 ottobre 2009 17:28 | Feedback (1) |

venerdì 16 ottobre 2009

Segnalazione di un nuovo, interessante blog

Finalmente il mio collega, nonchè caro amico, Roberto Penzo si è deciso ad aprire un blog dove esprimere le sue illuminate e romantiche idee sul “vivere il lavoro”.

L’abstract:

“Lavorare. Come passare questo tempo? Quali occasioni per viverlo bene? Pensieri su ciò che concentra tante attese e impegna così tanta vita. Luce su aspetti belli e a volte entusiasmanti di questa esperienza solitamente definita grigia.”

e il link:

http://thedrop-lagoccia.blogspot.com

Technorati Tags:

posted @ venerdì 16 ottobre 2009 22:38 | Feedback (3) |

[OT] Avere un buco nero in tasca

No, non è la condizione tipica di qualche amico particolarmente spendaccione…

Un gruppo di ricercatori di una università cinese è riuscito a creare un dischetto delle dimensioni di 8 pollici e mezzo in grado di assorbire tutte le radiazioni elettromagnetiche nel suo intorno.

Sembra che uno dei possibili scenari applicativi possa essere la costruzione di nuove celle solari particolarmente efficienti.

Speriamo che sia un passetto in avanti verso l’indipendenza dall’ oro nero.

Fonte: http://www.popsci.com/technology/article/2009-10/black-hole-fits-your-pocket

posted @ venerdì 16 ottobre 2009 11:22 | Feedback (7) |

mercoledì 7 ottobre 2009

Il mio primo sito web

Era il lontano 2000 quando insieme a Diego e agli amici di Padus realizzai il sito del ViaVai, un opuscolo/giornaletto settimanale con gli eventi/spettacoli/cinema della provincia di Rovigo.

image


Classic ASP e Access. Tutto qua.
Semplice e spartano fin che vuoi, ma pur sempre un cms completo di gestione dei banner pubblicitari era.

E dopo 9 anni è ancora li, a servire i suoi affezionati… ehhhh, son soddisfazioni!

E voi? qual’è stato il vostro primo sito web?

Technorati Tags: ,

posted @ mercoledì 7 ottobre 2009 23:27 | Feedback (4) |

martedì 6 ottobre 2009

Horn: finirà l'incubo delle interdipendenze?


Qualcuno di voi si è mai trovato nella necessità di utilizzare nello stesso progetto Castle, NHibernate, Fluent NHibernate, Rhino tools, MVCContrib, ecc.?

Chiunque (e credo siano molti) si sia mai trovato in una situazione del genere sa bene a cosa il titolo del post si riferisce.
Tutti questi raffinati e fantastici strumenti hanno una serie di interdipendenze tali da rendere veramente difficile e tedioso l'aggiornarmento dei binari ad una nuova versione quando si ha la necessità di lavorare con l'intero stack di framework ALT.NET in un unico progetto.

L'obiettivo di Horn è di rendere estremamente semplici le operazioni di scaricamento e build dei framework open source di cui abbiamo bisogno nel nostro progetto. Si, ma semplici quanto?

Semplici quanto aprire la command line e digitare il comando seguente:

horn -install:nhibernate

questo(apparentemente) innoquo comando scatena una serie di operazioni tali che alla fine del processo ci si ritrova con una cartella da qualche parte con la build più recente (buildata dal trunk) di NHibernate completa anche delle librerie interdipendenti (anch'esse buildate dal proprio trunk).
Potrò, a questo punto, prendere i binari e copiarli nel mio progetto sicuro di non avere conflitti di versione tra le varie dipendenze.

Ma come funziona questa magia?


Horn introduce il concetto di build descriptor che altro non è che un file DSL scritto in boo che descrive da dove un determinato pacchetto deve essere scaricato (sono supportati svn e git), come il pacchetto deve essere buildato e quali sono le sue dipendenze.
Le dipendenze descritte puntano a loro volta al proprio build descriptor e possono quindi essere scaricate e buildate a loro volta.
In questo modo è possibile ottenere la build dell'intero albero di dipendenze del pacchetto desiderato.

Horn, di default, ha al suo interno una cartella package_tree che contiene i build descriptor della maggior parte (se non di tutti) dei framework e delle librerie più diffuse nella comunità .net. Ma è possibile costruire i propri build descriptor in maniera abbastanza semplice o contribuire al progetto inviando i build descriptor di librerie non ancora presenti nel package_tree.

image 

Come ottenere Horn?

Horn è hostato su google code qui: http://code.google.com/p/hornget/

E' possibile scaricare Horn con svn o TortoiseSVN da qui: http://hornget.googlecode.com/svn/trunk/

Una volta ottenuto il sorgente è possibile buildare horn in maniera molto semplice lanciando il comando hornbuild.bat nella cartella src.
Completato il build sarà possibile lanciare horn dalla cartella:

src\build\net-3.5\debug

e iniziare finalmente a buildare i nostri framework preferiti!

Horn è un progetto iniziato dal gruppo Scotland ALT.Net. Il progetto è tutt'altro che maturo (credo non sia ancora entrato nella sua fase beta) e la direzione di sviluppo futura è ancora incerta. Da questo post del suo autore sembra (speriamo) che horn sia destinato a diventare un bellissimo sito web in cui ogni build descriptor del package_tree diventa una pagina web dalla quale è possibile scaricare uno zip con i binari dell'ultima build disponibile. Certo, sarebbe un bel boost per la nostra produttività…

L'autore, nel suo ultimo post datato 17 Settembre 2009 chiede aiuto alla community per la manutenzione e lo sviluppo del progetto, lamentando la recente tendenza di molti project leader di cambiare scm passando da svn a git o altro. Infatti, ad oggi, molti build descriptor di horn non sono aggiornati ai recenti cambiamenti di scm, rendendo di fatto inutilizzabili gli stessi (per esempio rhino, mvccontrib, sharparchitecture passati di recente su github.com).

Vogliamo contribuire allo sviluppo di questo meraviglioso progetto?

Qualche link sparso sull'argomento:

http://jasondentler.com/blog/2009/08/first-impression-horn/
http://thesoftwaresimpleton.blogspot.com/2009/07/breaching-castle-walls.html
http://thesoftwaresimpleton.blogspot.com/2009/04/horn-package-manager-introduction.html


Technorati Tags: ,

posted @ martedì 6 ottobre 2009 22:50 | Feedback (7) |

sabato 3 ottobre 2009

File batch e sostituzione dei parametri


Ho pochissima esperienza con i vecchi batch file del dos ma mi rendo conto che sono spesso utilissimi per automatizzare piccoli (e grandi) task.

E’ possibile passare parametri a riga di comando ad un file batch come a qualsiasi altro eseguibile.

Il file batch può accedere ai parametri passati a riga di comando attraverso la sintassi:

%n

dove n è un numero che indica la posizione del parametro sulla riga di comando.

%0 si riferisce al comando batch stesso, da %1 in poi ci si riferisce ai suoi parametri.

E’ possibile applicare particolari “trasformazioni” ai parametri passati dette “sostituzioni”.
E’ possibile ottenere l’elenco delle sostituzioni con il comando:

call /?

Di seguito un riassunto delle sostituzioni possibili:

%~1 sostituisce il parametro %1 rimuovendo le virgolette;
%~f1 sostituisce il parametro %1 con il percorso completo;
%~d1 sostituisce il parametro %1 con la lettera di unità;
%~p1 sostituisce il parametro %1 con il solo percorso;
%~n1 sostituisce il parametro %1 con il nome del file;
%~x1 sostituisce il parametro %1 con la sola estensione del file;
%~s1 sostituisce il parametro %1 con i nomi brevi;
%~a1 sostituisce il parametro %1 con gli attributi del file;
%~t1 sostituisce il parametro %1 con la data e ora del file;
%~z1 sostituisce il parametro %1 con la dimensione del file;


E’ possibile combinare i modificatori per ottenere risultati composti, qualche esempio:

%~dp0 sostituisce il comando con la sua lettera di unità e il suo percorso;
%~dp1 sostituisce il primo parametro con la sua lettera di unità e il suo percorso;
%~nx0 estrae il nome del comando batch completo di estensione;
%~snx1 sostituisce il primo parametro con il nome nel formato breve;

Potete scaricare da qui un file batch di esempio che riassume le varie sostituzioni possibili.

Fonte: http://www.sgart.it/Page/default.asp?id=30&e=207

 

Technorati Tag: ,

posted @ sabato 3 ottobre 2009 16:31 | Feedback (4) | Filed Under [ Tools & Downloads ]

Problema in debug con Step Into e breakpoint in Visual Studio 2008 SP1

In questi giorni, per saziare la mia patologica curiosità, sto studiando i sorgenti di Castle, in particolar modo della parte di Ioc (Castle.Windsor e Castle.Microkernel).

Ho creato una piccola applicazione Web con ASP.NET MVC, ho preparato alcuni componenti di prova, ho preparato i file di configurazione, ecc… solite cose.

Poi ho scaricato una build di debug dell’intero stack di Castle e ho iniziato ad analizzarne i sorgenti e a colpi di debugger e Step into…

Tutto bene fino ad un certo punto del sorgente (sempre lo stesso), quando il debugger ha iniziato a dare di matto e il comando Step into e alcuni breakpoint hanno iniziato a non funzionare:

Metto il breakpoint, F5(Go), il debugger lo becca, F11(Step into) e niente… Step into mi salta a piè pari alcuni pezzi di sorgente e si ferma un po’ più avanti. Oltre a questo capita che alcuni breakpoint non vengano neanche considerati dal debugger.

Penso: “Non è che per caso i file binari non sono allineati con i file PDB o roba del genere?”. Riscarico tutto e riprovo. Stessa cosa.

Penso: “Non è che inavvertitamente (mmha…) ho cambiato qualche impostazione del debugger?”. Verifico e niente, tutto a posto.

Inizio a Googlare… e finalmente, dopo una mezzoretta trovo questo post nel forum di MSDN:

Visual Studio 2008 SP1 Stepping and Breakpoint Issues

che parla proprio di questo problema. In sostanza di tratterebbe di un bug che esce solo in situazioni molto particolari quando si lavora con codice multithread su macchine multi-core.

Prima di installare la patch indicata provo il workaround manuale. OK. Funziona.
Installo la patch indicata poco sotto tra i commenti:

http://code.msdn.microsoft.com/KB957912/Release/ProjectReleases.aspx?ReleaseId=1796

Posso continuare a studiare Castle.

Technorati Tags: ,,,

posted @ sabato 3 ottobre 2009 16:09 | Feedback (4) |

sabato 23 febbraio 2008

[OT] E' nata Claudia!

Ciao a tutti! Solo oggi trovo il tempo per dare questo grandissimo annuncio:

Il 14 Febbraio scorso alle 21.31, è nata la mia stella Claudia, una bella moretta di 3300 grammi!

Un grazie alla mamma Erika, per averla cullata per 9 mesi dentro il suo pancione, per la sua forza e per il suo coraggio in questi primi giorni così felici e difficili...

 

Auguro a tutti di vivere almeno una volta nella vita questa straordinaria esperienza.

Technorati Tags:

posted @ sabato 23 febbraio 2008 20:57 | Feedback (19) |

mercoledì 25 luglio 2007

Aggiornato il post sull'implementazione del Singleton

Ho appena finito di sistemare alcuni aggiornamenti al mio precedente post sull'implementazione del pattern Singleton. Un grazie particolare a Michele Bersani per le indicazioni di alcuni preziosi link sull'argomento.

Attendo i vostri feedback!

posted @ mercoledì 25 luglio 2007 22:30 | Feedback (3) |

domenica 8 luglio 2007

Il punto su Singleton

Proprio in questi giorni mi è capitato di leggere un interessante articolo sull'integrazione di NHibernate con ASP.NET (che trovate qui). Analizzando il codice allegato all'articolo in questione mi è caduto l'occhio su una particolare implementazione del pattern Singleton in C#. Tra i commenti, l'autore citava un link ad un articolo che avevo già letto di sfuggita un po' di tempo fa al quale solo ora sono riuscito a dare il peso che merita.

Ricalco di seguito qualche concetto e qualche riga di approfondimento, giusto a pro memoria e per reference in italiano.

In sostanza un Singleton è una classe che permette la creazione di una singola istanza di se stessa (requisito di resource management [1]) e fornisce un unico, semplice accesso pubblico a detta istanza (requisito di accessibilità [1]).

Obiettivo del Singleton è spostare la responsabilità dell'esistenza di una ed una sola istanza di una determinata classe dallo sviluppatore alla classe stessa.

Un tipico requisito di un Singleton è che l'istanza non sia creata finchè non ce n'è reale necessità, che sia cioè "lazy-created".

Tutte le implementazioni del Singleton condividono alcune caratteristiche:

  • Un unico costruttore, privato e senza parametri. Per non permettere ad altre classi di instanziarlo direttamente e per non permetterne l'uso come classe base in una gerarchia di ereditarietà. Tipicamente il Singleton è sealed, anche se non servirebbe, per il motivo che abbiamo appena citato, ma sembra che segnare la classe sealed aiuti il compilatore a ottimizzare meglio [2];
  • Un campo statico che mantiene un riferimento alla singola istanza del Singleton;
  • Un metodo o una proprietà pubblici per ottenere il riferimento all'istanza del Singleton ed eventualmente crearla, se non ancora creata;

Vediamo di seguito qualche implementazione del pattern Singleton con un occhio di riguardo alla "thread-safety" e alla "lazyness", come consigliato in [2].

 

L'implementazione classica... non thread safe

   1:  public sealed class Singleton1
   2:  {
   3:      private static Singleton1 _instance = null;
   4:   
   5:      private Singleton1() { }
   6:   
   7:      public static Singleton1 Instance
   8:      {
   9:          get
  10:          {
  11:              if (_instance == null)
  12:              {
  13:                  _instance = new Singleton1();
  14:              }
  15:              return _instance;
  16:          }
  17:      }
  18:  }
 

L'implementazione proposta è la classica descritta in [3], semplicemente tradotta da C++ a C#.

La proprietà Instance alla riga 7 garantisce il requisito di accessibilità, è infatti l'unico punto di accesso pubblico all'istanza. Il codice all'interno della proprietà garantisce il requisito di resource management definito e cioè che esista una sola istanza della classe, il getter controlla infatti la preventiva esistenza dell'istanza e la crea solo ed esclusivamente se non è già stata creata, altrimenti restituisce l'istanza già esistente.

In uno scenario single-thread il codice in questione funziona ed è perfettamente legale. In scenari multi-thread iniziano i problemi... questa implementazione non è thread safe, due o più thread potrebbero contemporaneamente valutare il test alla riga 11 come vero e creare più istanze della classe, violando il requisito di resource management.

Rigirando la frittata, anche se a mio parere non ci sono forti motivazioni (ad esempio straordinari aumenti di performance) per un approccio del genere, nel tipico caso di Singleton immutabile e nel caso in cui la costruzione del Singleton sia poco onerosa, è possibile chiudere un occhio riguardo la violazione del requisito di resource management, lasciando al garbage collector l'onore e l'onere di eliminare una eventuale "altra istanza" lasciata orfana di riferimento dalla fortuita costruzione di una seconda istanza e utilizzare, quindi, questa implementazione.

 

Un passo avanti, garantiamo la thread-safety

   1:  public sealed class Singleton2
   2:  {
   3:      private static Singleton2 _instance = null;
   4:      private static readonly Object syncObject = new Object();
   5:   
   6:      private Singleton2() { }
   7:   
   8:      public static Singleton2 Instance
   9:      {
  10:          get
  11:          {
  12:              lock (syncObject)
  13:              {
  14:                  if (_instance == null)
  15:                  {
  16:                      _instance = new Singleton2();
  17:                  }
  18:                  return _instance;
  19:              }
  20:          }
  21:      }
  22:  }
 

L'implementazione è effettivamente thread safe, due o più thread non possono accedere contemporaneamente all'area protetta da lock quindi solo il primo thread che entrerà nel lock potrà creare l'istanza del singleton.

Il codice soffre però un problema di performance, è infatti richiesto un lock per ogni richiesta dell'istanza, anche nel caso in cui l'istanza sia già stata creata.

 

Thread safety, lock, performance, volatile e MemoryBarrier()

   1:  public sealed class Singleton3
   2:  {
   3:      private static volatile Singleton3 _instance = null;
   4:      private static readonly Object syncObject = new Object();
   5:   
   6:      private Singleton3() { }
   7:   
   8:      public static Singleton3 Instance
   9:      {
  10:          get
  11:          {
  12:              if (_instance == null)
  13:              {
  14:                  lock (syncObject)
  15:                  {
  16:                      if (_instance == null)
  17:                      {
  18:                          _instance = new Singleton3();
  19:                      }
  20:                  }
  21:              }
  22:              return _instance;
  23:          }
  24:      }
  25:  }

A differenza dell'esempio precedente, il lock viene eseguito solo la prima volta che viene richiesta l'istanza. Infatti l'if più esterno (alla riga 12) serve proprio a verificare che l'istanza sia già stata creata ed in tal caso l'ingresso nel lock introdurrebbe solo un inutile overhead. Questa semplice modifica rispetto all'esempio precendente ha un chiaro impatto sulle performance, l'utilizzo di lock è utile in effetti solo nella fase iniziale in cui l'istanza non è ancora stata creata, quando cioè è indispensabile la sincronizzazione, e di conseguenza è un inutile spreco di tempo per tutto il resto del ciclo di vita del singleton in cui viene semplicemente restituita l'istanza già creata. 

Merita particolare attenzione in questa implementazione l'utilizzo di volatile nella dichiarazione di _instance (riga 3)... ma prima di entrare nel merito forse vale la pena di ricordare le 3 regole fondamentali a cui i modelli di memoria (anche quello del .NET Framework) devono sottostare:

  • Una lettura o una scrittura da un determinato thread ad una determinata locazione di memoria non può essere spostata temporalmente più avanti di una scrittura dallo stesso thread alla stessa locazione;
  • Le letture non possono essere spostate temporalmente più indietro dell'acquisizione di un lock;
  • Le scritture non possono essere spostate temporalmente più avanti del rilascio di un lock;

Il modello di memoria del .NET Framework, oltre alle 3 regole citate, suddivide le tipologie di accesso alla memoria in "accessi ordinari" e "accessi volatile". Per gli accessi volatile sono definite le due regole seguenti:

  • Letture e scritture non possono essere spostate temporalmente più indietro di una lettura volatile;
  • Letture e scritture non possono essere spostate temporalmente più avanti di una scrittura volatile.

Conseguenza di queste regole è, di fatto, l'inibizione del riordino degli accessi alla memoria, una particolare ottimizzazione applicata dai compilatori e dalle CPU non x86 per ottimizzare l'esecuzione del codice.
Altra conseguenza è che viene forzato l'aggiornamento della variabile dichiarata volatile al valore più recente prima che questa venga applicata all'interno di un particolare contesto.

Ora... cosa sarebbe potuto succedere se _instance non fosse stata dichiarata volatile?

Dal punto di vista del rispetto dei requisiti di accessibilità e di resource management assolutamente niente. Infatti, il requisito di resource management è garantito dalla presenza del secondo check su _instance (riga 16) e dal rispetto da parte del memory model della seconda regola fondamentale. Si supponga di avere 2 thread:

  • Il thread 1 passa il primo if (riga 12), l'esecuzione viene interrotta e passa al thread 2;
  • Il thread 2 passa il primo if, entra nel lock, passa il secondo if e crea l'istanza;
  • Il thread 1 riprende l'esecuzione ed entra nel lock. La seconda regola fondamentale dei modelli di memoria dice che: "le letture non possono essere spostate temporalmente più indietro dell'acquisizione di un lock" e di conseguenza che _instance avrà sicuramente, a questo punto, l'ultimo valore pubblicato dal thread 2 prima di rilasciare il lock. L'if alla riga 16 verificherà che _instance è diverso da null e il thread 1 proseguirà l'esecuzione restituendo l'istanza precedentemente creata da thread 2.

In realtà, un problema subdolo si nasconde nel corpo dell'if alla riga 16 e precisamente nel codice che va a creare l'istanza di Singleton3... ed è proprio in questo caso che volatile ci viene in aiuto. Si supponga di avere il codice seguente:

   1:  public sealed class Singleton3
   2:  {
   3:      private static volatile Singleton3 _instance = null;
   4:      private static readonly Object syncObject = new Object();
   5:      private String _message;
   6:   
   7:      private Singleton3() { _message = "Hello World!"; }
   8:   
   9:      public static Singleton3 Instance
   10:      {
  11:          get
  12:          {
  13:              if (_instance == null)
  14:              {
  15:                  lock (syncObject)
  16:                  {
  17:                      if (_instance == null)
  18:                      {
  19:                          _instance = new Singleton3();
  20:                      }
  21:                  }
  22:              }
  23:              return _instance;
  24:          }
  25:      }
  26:  }

Su architetture IA64, che permettono il riordino delle scritture in memoria, potrebbe accadere che, all'interno del corpo dell'if alla riga 19, le scritture vengano riordinate in maniera tale che la scrittura di _message all'interno del costruttore possa essere spostata temporalmente più avanti della scrittura di _instance. La lettura di _instance (alla riga 13) non è protetta da lock, potrebbe quindi accadere che un secondo thread possa accedere all'istanza di Singleton3 prima che il costruttore abbia concluso l'inizializzazione.
L'utilizzo di volatile su _instance ci mette al riparo da questo problema in virtù della regola introdotta dal memory model del .NET Framework che dice: "Letture e scritture non possono essere spostate temporalmente più avanti di una scrittura volatile", garantendo, di conseguenza, la sequenzialità delle scritture nel blocco di costruzione dell'istanza, viene garantita la corretta inizializzazione di Singleton3 anche in scenari multi-thread.

L'implementazione precedente è thread-safe, è lazy-load ed è performante... ma possiamo fare ancora un pochino di più!

Quello che possiamo fare è rimuovere il modificatore volatile dalla dichiarazione di _instance e utilizzare una MemoryBarrier esplicita subito prima della pubblicazione dell'istanza di Singleton3 come nell'esempio seguente:

   1:  public sealed class Singleton3
   2:  {
   3:      private static Singleton3 _instance = null;
   4:      private static readonly Object syncObject = new Object();
   5:      private String _message;
   6:   
   7:      private Singleton3() { _message = "Hello World!"; }
   8:   
   9:      public static Singleton3 Instance
   10:      {
  11:          get
  12:          {
  13:              if (_instance == null)
  14:              {
  15:                  lock (syncObject)
  16:                  {
  17:                      if (_instance == null)
  18:                      {
  19:                          Singleton3 newValue = new Singleton3();
  20:                          System.Threading.Thread.MemoryBarrier();
  21:                          _instance = newValue;
  22:                      }
  23:                  }
  24:              }
  25:              return _instance;
  26:          }
  27:      }
  28:  }

Questo approccio è molto più efficiente dell'ultilizzo del modificatore volatile perchè, in realtà, ogni scrittura o lettura volatile è una memory barrier! anche dove non ne abbiamo bisogno!
Nel nostro caso l'obiettivo è soltanto avere la sicurezza che le scritture all'interno del costruttore vengano eseguite prima della pubblicazione dell'istanza agli altri thread (e processori). MemoryBarrier() ci assicura che "nessuna scrittura possa essere spostata temporalmente più avanti della chiamata a MemoryBarrier()" e ci permette quindi di garantire la consistenza dell'istanza risparmiando la dichiazione volatile di _instance.

E se utilizziamo il .NET Framework 2.0?

Con l'introduzione del .NET Framework 2.0 il modello di memoria è stato riveduto e corretto al fine si supportare gli sviluppatori nel passaggio alle nuove architetture IA64. Rimangono buone tutte le precedenti regole e alcune di nuove sono state introdotte tra cui una in particolare:

  • Le scritture non possono essere spostate temporalmente più avanti di altre scritture dallo stesso thread.

Questa regola ci permette di evitare sia la dichiarazione volatile di _instance sia la chamata a MemoryBarrier(), risolvendo a livello di memory model la corretta serializzazione delle scritture del costruttore rispetto alla pubblicazione dell'istanza.

 

Thread safe senza lock. Lazyness (con riserva)

   1:  public sealed class Singleton4
   2:  {
   3:      private static readonly Singleton4 _instance = new Singleton4();
   4:   
   5:      private static Singleton4() { }
   6:   
   7:      private Singleton4() { }
   8:   
   9:      public static Singleton4 Instance
  10:      {
  11:          get
  12:          {
  13:              return _instance;
  14:          }
  15:      }
  16:  }

Il singleton dell'esempio qui sopra è thread safe e lazy-created (con riserva).

La lazyness è supportata da una funzionalità del CLR che garantisce che il type initializer venga eseguito "prima" dell'accesso ad un qualsiasi membro statico della classe. Nel nostro caso, subito prima del primo accesso alla proprietà statica Instance, il type initializer verrà eseguito e il campo statico _instance verrà inizializzato con una istanza di Singleton4. Il type initializer verrà eseguito però anche nel caso si acceda ad un qualsiasi altro campo o proprietà statica denifito nella classe violando (da qui la riserva), di fatto, la lazyness di Instance... Attenzione! potrebbe non essere il comportamento desiderato in fase di design.

Altra importante questione riguardante la lazyness di Singleton4 è la presenza del costruttore statico (riga 5, costruttore esplicito). La presenza del costruttore esplicito garantisce che la classe non venga decorata con il flag beforefieldinit in fase di compilazione. Il flag beforefiledinit abilita il runtime ad ottimizzare l'esecuzione del type initializer scegliendo autonomamente il momento migliore per eseguirlo, garantendone comunque l'esecuzione prima dell'accesso ad un qualunque campo statico della classe. Noi non abbiamo quindi modo di determinare precisamente il momento in cui il type initializer viene eseguito, di conseguenza la lazyness è violata. Senza il flag beforefieldinit il runtime DEVE eseguire il type initializer immediatamente prima dell'accesso ad un qualunque campo statico della classe [6].

La thread safety è supportata da una specifica del CLR che garantisce il fatto che il type initializer venga eseguito una ed una sola volta, anche in ambienti multithreaded. Il runtime, infatti, acquisisce un lock PRIMA di eseguire il type initializer, rendendo l'inizializzazione di _instance sincronizzata [6].

 

Thread safe senza lock. Lazy-created (garantito)

   1:  class Singleton5
   2:  {
   3:      private Singleton5() { }
   4:   
   5:      public static Singleton5 Instance
   6:      {
   7:          get
   8:          {
   9:              return Nested._instance;
  10:          }
  11:      }
  12:   
  13:      class Nested
  14:      {
  15:          static Nested() { }
  16:   
  17:          internal static readonly Singleton5 _instance = new Singleton5();
  18:      }
  19:  }
Il singleton dell'esempio qui sopra è thread safe (vedi le stesse motivazioni del precedente esempio) e lazy-created in ogni circostanza.

La lazyness è infatti garantita dal fatto che il type initializer di _instance viene eseguito solo ed esclusivamente prima del primo accesso ai membri statici della classe Nested (che può essere fatto solo dallo stesso Singleton5), costruita solo per questo scopo e invisibile all'esterno di Singleton5. L'accesso ad una qualsiasi altro membro statico di Singleton5 non influenza l'inizializzazione di _instance.

 

Note

Nel caso di decida di utilizzare l'implementazione Singleton4 o Singleton5 bisogna fare particolarmente attenzione alla particolare gestione delle eccezioni dei type initializer statici:

  • Qualsiasi eccezione sollevata all'interno del costruttore statico viene automaticamente wrappata da una eccezione di tipo TypeInitializationException, l'eccezione originale è comunque disponibile attraverso la proprietà InnerException di TypeInitializationException;
  • Il runtime, nel caso venga sollevata una eccezione nel costruttore statico, non tenterà di invocare una seconda volta il costruttore statico, rendendo, probabilmente, la stessa eccezione fatale per l'intera applicazione [6].

 

Potete scaricare i sorgenti d'esempio del post qui.

 

Bibliografia

[1] Adrian Florea - L'individuazione via reflection delle classi singleton all'interno del Framework .NET
[2] Jon Skeet - Implementing the Singleton Pattern in C#
[3] Gamma, Helm, Johnson, Vlissides - Design Patters, Elementi per il riuso di software a oggetti
[4] Alessandro Marotta Rizzo - Implementare Singleton con Volatile
[5] Eric Gunnerson - A programmer's introduction to C# 2.0
[6] K. Scott Allen -  Get a Charge From Statics with Seven Essential Programming Tips
[7] Microsoft -  ECMA C# and Common Language Infrastructure Standards
[8] Vance Morrison -  Understand the Impact of Low-Lock Techniques in Multithreaded Apps

 

posted @ domenica 8 luglio 2007 13:15 | Feedback (26) | Filed Under [ .NET Development ]

giovedì 5 luglio 2007

Visualizzare linee guida nell'editor di testo di Visual studio

Interessante funzionalità di Visual Studio 2002, 2003 e 2005 della quale non ero a conoscenza, ma molto molto comoda... E' possibile visualizzare una o più guideline nell'editor di testo di visual studio aggiungendo una semplice stringa ad una chiave di registro, chissà poi perchè non l'hanno messa tra le opzioni dell'editor...

Aprite regedit e navigate alla chiave seguente:

[HKEY_CURRENT_USER]\Software\Microsoft\VisualStudio\8.0\Text Editor

create ora una nuova stringa REG_SZ e chiamatela Guides, doppio click sulla stringa appena creata e aggiungete:

RGB(230,230,230) 80, 120

con RGB(...) si sceglie il colore della o delle linee. 80 e 120 aggiungono 2 guidelines rispettivamente alla colonna 80 e 120 dell'editor di testo.

Un consiglio, scegliete un colore molto chiaro (se lo sfondo è bianco) o comunque un colore che non dia troppo fastidio.

Technorati Tag:

posted @ giovedì 5 luglio 2007 20:52 | Feedback (1) | Filed Under [ .NET Development ]

sabato 8 luglio 2006

[OT] Il terzo incontro di XE.NET

Ieri sera, come molti sapranno, si è svolto in quel di Marghera il terzo incontro della community .NET veneta XE.NET.

Beh, che dire, i primi due incontri sono stati molto interessanti ma ieri sera è stato veramente il massimo. Un po' per l'argomento OR-Mapping, che mi interessa molto, un po' per i relatori, veramente in gambissima ai quali faccio pubblicamente i miei complimenti.

La serata è iniziata con uno scoppiettante Giancarlo Sudano, del quale già da tempo seguivo l'interessantissimo blog, che ci ha introdotto durante, ahimè, il poco tempo a disposizione, al framework NHibernate. Devo dire che l'argomento era abbastanza complesso ma Giancarlo è riuscito a trasmettere in maniera efficace, grazie alla sua preparazione ed entusiasmo, i concetti di base e la filosofia che sta alla base di Hibernate, il tutto condito da un bell'esempio che non vedo l'ora di scaricare e rivedere.

Ottimo anche l'intervento di Davide Senatore. E' stato molto interessante il confronto tra i diversi tipi di approccio: un Giancarlo forse un po' più accademico e purista (e al quale, per la verità, mi sento molto vicino) con il suo approccio alla soluzione Top-Down, con i cenni ai pattern architetturali di Fowler... un Davide invece più pragmatico e orientato ai problemi "real world" (vedi el casolin sotto casa ("alimentari" per il resto del mondo)) con il suo approccio dal "basso" e ORM.Net che genera le classi di business a partire dalle tabelle e dalle relazioni del DB.

Alla fine, comunque, il buon Marco Trova ha riportato tutti con i piedi per terra con una sessione che tra una battuta e l'altra raccontava la vita reale dello sviluppatore senior medio che si trova a barcamenarsi tra inutili competizioni con gli "architetti" e clienti ai quali, ahinoi, non può fregare di meno di architetture, framework, interfaccie utente spettacolari... Forse un aneddoto in meno e due parole in più sulle applicazioni "real world" degli ORM ci sarebbero state, ma va bene così.

Tirando le somme... una serata sicuramente azzeccata, che ha colto in pieno l'obiettivo di dare una panoramica generale delle tecnologie utili a risparmiarci un po' di tedioso lavoro.

Un ringraziamento su tutti va ad Andrea Boschin , e alla passione spesa per queste belle iniziative.

powered by IMHO 1.3

posted @ sabato 8 luglio 2006 15:58 | Feedback (2) |

giovedì 27 aprile 2006

[OTMNT] AMOS The Creator

L'altro giorno il buon Igor mi ricordato in un commento al mio post di un linguaggio/capolavoro opera di un geniale programmatore francese di nome François Lionet, AMOS the Creator, il creatore di videogiochi.

Ma cos'era AMOS The Creator? AMOS era un linguaggio per la piattaforma AMIGA, un basic molto dotato, evoluzione di un precedente prodotto chiamato STOS per ATARI ST. Con AMOS era possibile, con relativamente poco sforzo, creare applicazioni (tipicamente videogiochi) sfruttando le enormi (per l'epoca) potenzialità dell'hardware dell'AMIGA.

Ricordo ancora l'emozione che provai la prima volta che riuscii ad aprire uno schermo grafico e a muovere qualche sprite o qualche BOB in giro per lo schermo... o a suonare qualche MOD di SoundTracker. Allora muovevo i primi passi nel magico mondo della programmazione, anche se in realtà già qualcosina avevo fatto con il BASIC del Commodore 64, e c'era molto fermento tra gli amici tanto che la competizione si tagliava con il coltello sul chi era più bravo a comprimere un file IFF o a muovere più BOB in 1/50 di secondo...

Ricordo che avevo avuto anche la grandissima soddisfazione di veder pubblicate su The games machine, che allora aveva una rubrica chiamata Talent scout, un paio di screen shot e una recensione di una conversione di Tetris che avevo fatto, ovviamente in AMOS, nei pomeriggi dopo scuola.

Ho assegnato al post l'attributo [OTMNT](Off Topic Ma Non Troppo) convinto del fatto che probabilmente molti dei professionisti che quotidianamente scrivono o leggono post su questo blog o sviluppano software gestionali, piuttosto che applicazioni WEB con .NET, conoscono AMOS e hanno mosso i primi passi proprio in quegli anni di grande fermento e me ne accorgo per la grande sensazione di community che si respira e per la grande attenzione all'innovazione che emerge dai post che ogni giorno riempiono il muro di UgiDotNet.

Chissà se François Lionet ha mai pensato di riproporre una versione di AMOS the Creator conforme al CLS...

powered by IMHO 1.3

posted @ giovedì 27 aprile 2006 20:47 | Feedback (11) |

[MDX2.1] Cominciamo a fare un po' di ordine?

Allora... di seguito una manciata di link ad articoli e tutorial utili per cominciare a capirci qualcosa:

cominciamo da casa nostra... http://www.ugidotnet.org/articles/articles_read.aspx?ID=115
un bell'articolo di Antonio Ganci che introduce in maniera chiara e limpida alcuni concetti di base, come il main loop, Device e Vertex Buffer.

http://www.thezbuffer.com/ : una fonte inesauribile di informazioni sulle Managed DirectX, aggiornate quasi quotidianamente. Il sito contiene anche tutta una serie di link alle risorse in rete sull'argomento.

http://blogs.msdn.com/tmiller/ : il blog del project leader di Managed DirectX. Cliccando sui link segnalati si arriva ai blog di diversi personaggi, alcuni dei quali membri dello stesso team.

http://www.c-unit.com/ : un sito stracolmo di tutorials su MDX2, dagli argomenti più semplici ai più avanzati. Una cosa molto importante è che i tutorial fanno riferimento attualmente alla versione di Febbraio 2006 del DirectX SDK, sono quindi molto recenti,  e che l'autore li aggiorna periodicamente alle versioni più aggiornate rilasciate da Microsoft.

http://www.mdxinfo.com/ : un altro sito con diversi tutorial, questa volta abbastanza avanzati, ma sicuramente meritevoli di uno sguardo, anche solo per capire a colpo d'occhio le possibilità dello strumento.

http://www.rocketcommander.com/ : è il sito "istituzionale" di un videogame molto carino e divertente disponibile in sorgente e realizzato con MDX2. Interessante perchè l'autore Benjamin Nitschke oltre a fornire il sorgente ha erogato nelle scorse settimane un tutorial con allegati una serie di Webcast in inglese per il sito Coding4Fun e disponibili qui. Il tutorial racconta con parole, immagini e una decina di video l'intero processo di sviluppo di un videogame con MDX2, di seguito la scaletta tratta direttamente da un suo post:

  • Tutorial #1. How do I setup Visual Studio for our project?
  • Tutorial #2. Design and Concept
  • Tutorial #3. Helper classes
  • Tutorial #4. Graphic classes
  • Tutorial #5. Music and Sound
  • Tutorial #6. Shader Introduction (TangentVertex class and FxComposer)
  • Tutorial #7. Shaders (Parallax, Instancing)
  • Tutorial #8. Post Screen Shaders
  • Tutorial #9. Input and Interface
  • Tutorial #10. Game logic and the Flower Commander Mod

Chiaramente gli argomenti sono talmente vasti da non potersi esaurire in poche decine di minuti di video, ma sono comunque una vera manna per cominciare a capirci qualcosa.

Volevo infine segnalare il libro di Tom Miller che farà un po' da ossatura per questa serie di post:

http://www.amazon.com/gp/product/0672325969/102-8048306-1060165?n=283155

E' un libro fatto molto bene, l'unico problema è che tutti gli esempi fanno riferimento al MDX 1 per il framework 1.1. Comunque si possono scaricare tutti gli esempi del libro aggiornati all'MDX SDK August 2005 da http://www.thezbuffer.com/downloads/MDXKickstartCSAug05.zip.

Qualcuno ha detto (ma non ricordo chi), ed io sono francamente d'accordo, che cercare di far funzionare gli esempi del libro con il più recente SDK sia una bella esperienza didattica. Quindi armatevi di tanta tanta pazienza e del buon vecchio Reflector e buon lavoro. Alla prossima!

powered by IMHO 1.2

posted @ giovedì 27 aprile 2006 15:33 | Feedback (5) | Filed Under [ MDX2 ]

martedì 25 aprile 2006

[MDX2.0] Un numero zero pieno di buoni propositi

Come qualcuno forse si è accorto che il sottotitolo del mio blog è cambiato in "something about... C# & Managed DirectX". Sempre questo qualcuno si domanderà come mai di questo cambiamento e come mai lo faccio proprio oggi martedi 25 Aprile invece di fare qualcosa un po' più adatto ad un giorno di festa. Beh in realtà è una cosa che già volevo fare da un po' di tempo e complice un'oretta di tempo libero di ritorno da una bellissima giornata al mare in quel di Rosolina Mare eccomi qua a pubblicare, come cita il titolo, il numero zero di una serie di post... pieno zeppo di buoni propositi.

Riguardo al cambio del sottotitolo... il motivo è sostanzialmente un adeguamento agli argomenti di mio attuale interesse, in ambito .NET s'intende. Quando un paio d'anni fa pubblicai il primo post su questo blog da poco mi ero avvicinato a .NET provenendo da una forte esperienza con Visual Basic 6 e decisi di affrontare lo studio di questa affascinante tecnologia passando, naturalmente, da VB.NET senza dover ricominciare da zero con un nuovo linguaggio. Così, a suo tempo, decisi di intitolare il blog "VB.NET WindowsForms e altro...".

Oggi, sarà il fascino della parentesi graffa... studio e utilizzo C# 2.0, mi interesso ancora di sviluppo Windows Forms... ma ultimamente mi sono lasciato sopraffare da una mia vecchia passione per la programmazione di grafica e videogiochi e così mi ritrovo a studiare quella cosa chiamata Managed DirectX che altro non è che un grosso wrapper Managed attorno al framework DirectX, conosciuto molto bene agli sviluppatori C++ che hanno a che fare con videogiochi e applicazioni multimediali e da un po' di tempo disponibile direttamente anche per i nostri amati linguaggi managed. Certo... il mondo è cambiato dai tempi dell'Amiga... ma prometto che farò del mio meglio per adeguarmi al cambiamento .

L'obiettivo del cambio di rotta del blog e di questa serie di post è, per quanto mi riguarda, creare una sorta di blocco di appunti ove annotare e riassumere i concetti che pian piano emergeranno dallo studio di MDX e dall'approfondimento di C# 2.0, annotare i link a documenti, post o quant'altro possa servire a districare la matassa di questa affascinante ma estremamente vasta e complessa tecnologia. Spero possa essere, per i lettori, con molta modestia, un piccolo aiuto per colmare la mancanza di informazioni sull'argomento disponibili in rete, in italiano.

Un saluto a tutti e... stay tuned!

powered by IMHO 1.3

posted @ martedì 25 aprile 2006 22:12 | Feedback (16) | Filed Under [ MDX2 ]

mercoledì 8 marzo 2006

Un augurio a tutte le donne

a tutte le donne che... tutte le mattine si alzano alle 6, lavorano in casa, portano il bambino all'asilo, lavorano tutto il giorno, vanno a prendere il bambino e poi tornano a casa... a lavorare...

a tutte le donne che... quando hanno un aumento, gielo danno "fuori busta" così poi quando vanno in maternità gli danno lo stipendio al minimo sindacale...

a tutte le donne che... al ritorno della maternità, sono costrette a fare un lavoro di m***a solo per ripicca...

Auguro a queste grandi donne 365 giorni all'anno di successi.

e per noi uomini... una riflessione... come sarebbe la nostra vita, la nostra carriera senza una grande donna al nostro fianco?

powered by IMHO 1.2

posted @ mercoledì 8 marzo 2006 16:32 | Feedback (4) |

Powered by:
Powered By Subtext Powered By ASP.NET