DotNetToscana e i buoni propositi per quest'anno

Con i ragazzi di DotNetToscana abbiamo definito l'agenda (ambiziosa) per quest'anno e devo ammettere che le prospettive sono assolutamente incoraggianti.
Gli eventi che abbiamo organizzato nell'anno precedente sono risultati, a nostro avviso, decisamente ben riusciti; alcuni di essi potrei definirli addirittura "coraggiosi"...

Il 17 Marzo toccherà al WP7 3D Game Lab, mentre il 19 di Aprile sarà la volta di Start Something! Tour – Windows 8 e Windows Phone 7.5, quest'ultimo con la gentilissima partecipazione di Lorenzo.

Come sempre, trattandosi di "laboratori", i posti sono piuttosto limitati. Chi è interessato farebbe quindi meglio ad iscriversi il prima possibile.

A ruota seguiranno altre interessanti iniziative, ma al momento non me la sento di anticipare niente!

C# operator constraints

Avevo questo post in cantiere da qualche tempo, da quando un paio di miei colleghi mi hanno esternato le loro perplessità su un particolare behavior di C# compiler.
Partiamo dal primo snippet:

   1:  Boolean AreEqual<T>(T a, T b)
   2:  {
   3:      return a == b;
   4:  }

Si noterà subito che il codice in oggetto non compila.
Limitandosi ad aggiungere il constraint "class", la compilazione va a buon fine.

   1:  Boolean AreEqual<T>(T a, T b) where T : class
   2:  {
   3:      return a == b;
   4:  }

Il motivo per il quale il primo snippet non viene compilato lo si può appurare consultando la documentazione MSDN e, nello specifico:
"For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings".

L'elemento sul quale dobbiamo spostare la nostra attenzione è ciò che la documentazione definisce come "predefined value type".
Personalmente, trovo che qualche Unit Test rappresenti la soluzione migliore per chiarirsi e fissarsi questi concetti. Vediamo quindi di condurre qualche test con la struttura Int32.

   1:  [TestMethod]
   2:  public Int32Equality()
   3:  {
   4:      var int1 = 2;
   5:      var int2 = 2;
   6:      Assert.AreEqual(int1, int2);
   7:      Assert.IsTrue(int1 == int2);
   8:  }

Il test compila e passa e la domanda, a questo punto, è legittima, soprattutto se si osserva la struttura System.Int32 con uno strumento quale "Reflector". Si può notare, infatti, che la medesima non offre gli overload per l'operatore Equals. Nella sua "bibbia", Jeffrey Ritcher aggiunge una breve nota su tale questione:
Note If you examine the core numeric types (Int32, Int64, UInt32, and so on) in the Framework Class Library (FCL), you’ll see that they don’t define any operator overload methods. The reason they don’t is that compilers look specifically for operations on these primitive types and emit IL instructions that directly manipulate instances of these types. If the types were to offer methods and if compilers were to emit code to call these methods, a run-time performance cost would be associated with the method call. Plus, the method would ultimately have to execute some IL instructions to perform the expected operation anyway. This is the reason why the core FCL types don’t define any operator overload methods. Here’s what this means to you: If the programming language you’re using doesn’t support one of the core FCL types, you won’t be able to perform any operations on instances of that type.

Giusto per esercizio, cerchiamo conferma di tutto ciò definendo uno "User-defined value type", analizzandolo nel medesimo contesto.

   1:  struct NonPredefinedValueType : IEquatable<NonPredefinedValueType>
   2:  {
   3:      public Int32 SomeValue;
   4:   
   5:      public override Boolean Equals(Object obj)
   6:      {
   7:          return obj is NonPredefinedValueType
   8:              ? Equals((NonPredefinedValueType) obj)
   9:              : base.Equals(obj);
  10:      }
  11:   
  12:      public Boolean Equals(NonPredefinedValueType other)
  13:      {
  14:          return other.SomeValue == SomeValue;
  15:      }
  16:   
  17:      public override Int32 GetHashCode()
  18:      {
  19:          return SomeValue;
  20:      }
  21:  }

Scriviamo dunque il test:

   1:  [TestMethod]
   2:  public NonPredefinedValueTypeEquality()
   3:  {
   4:      var value1 = new NonPredefinedValueType { SomeValue = 2 };
   5:      var value2 = new NonPredefinedValueType { SomeValue = 2 };
   6:      Assert.AreEqual(value1, value2);
   7:      Assert.IsTrue(value1 == value2);
   8:  }

Come si può notare, l'ultimo statement non compila, indicando che non è possibile applicare l'operatore "==" tra i due operandi. Alla luce di quanto emerso in precedenza, questo errore non dovrebbe coglierci di sorpresa. Difatti, stiamo operando con una struttura non-primitiva e, come si è visto, non abbiamo a disposizione alcun overload di operatore "preconfezionato".
Proviamo quindi ad aggiungere alla nostra struttura l'overload per l'operatore "==":

   1:  struct NonPredefinedValueType : IEquatable<NonPredefinedValueType>
   2:  {
   3:      public Int32 SomeValue;
   4:   
   5:      public override Boolean Equals(Object obj)
   6:      {
   7:          return obj is NonPredefinedValueType
   8:              ? Equals((NonPredefinedValueType) obj)
   9:              : base.Equals(obj);
  10:      }
  11:   
  12:      public Boolean Equals(NonPredefinedValueType other)
  13:      {
  14:          return other.SomeValue == SomeValue;
  15:      }
  16:   
  17:      public override Int32 GetHashCode()
  18:      {
  19:          return SomeValue;
  20:      }
  21:   
  22:      public static Boolean operator ==(NonPredefinedValueType a, NonPredefinedValueType b)
  23:      {
  24:          return a.Equals(b);
  25:      }
  26:   
  27:      public static Boolean operator !=(NonPredefinedValueType a, NonPredefinedValueType b)
  28:      {
  29:          return !(a == b);
  30:      }
  31:  }

Come si può notare, il test questa volta compila e passa.

   1:  [TestMethod]
   2:  public void NonPredefinedValueTypeEquality()
   3:  {
   4:      var value1 = new NonPredefinedValueType { SomeValue = 2 };
   5:      var value2 = new NonPredefinedValueType { SomeValue = 2 };
   6:      var value3 = new NonPredefinedValueType { SomeValue = 3 };
   7:      Assert.AreEqual(value1, value2);
   8:      Assert.AreNotEqual(value1, value3);
   9:      Assert.IsTrue(value1 == value2);
  10:      Assert.IsTrue(value1 != value3);
  11:  }

Ok, niente di così trascendentale, ma eseguiamo una callback al primo snippet e chiediamoci se è possibile, in qualche modo, evitare il constraint a "class" senza rinunciare ai generics. Beh, la prima idea che ti può venire in mente è che il ricorso a DLR "sposti" il problema dalla fase di compilazione a quella di runtime. In sostanza:

   1:  Boolean AreEqual<T>(T a, T b)
   2:  {
   3:      return (dynamic)a == b;
   4:  }

Ne ho discusso con i miei amici di DotNetToscana e i pareri sono piuttosto discordanti. Personalmente, trovo che il prezzo che si paga per garantire un maggior grado di astrazione in qualche contesto possa essere accettabile. Ma sono curioso di sentire altri pareri! :-)

UPDATE:
Spaccabit aggiunge un interessante elemento che ci porta ad ampliare ulteriormente la discussione.
Sostanzialmente, a.Equals(b) va sempre a chiamare il metodo con la firma "Boolean Equals(Object obj)". Quindi, indipendentemente dal fatto che il tipo del parametro generico T implementi o meno IEquitable<T>, la chiamata va sempre al metodo in oggetto.
A questo punto, c'è da dire che se il tipo è disegnato "male" ciò può rappresentare un problema piuttosto serio.
Al contrario, "EqualityComparer<T>.Default.Equals(a, b)" verifica in prima istanza che T implementi IEquitable<T>. In tal caso, esegue l'implementazione di IEquitable<T>.
Mi viene da dire, quindi, che "EqualityComparer<T>.Default.Equals(a, b)" possa fungere un pò da "salvagente", come giustamente fa notare Spaccabit.
Quello che volevo aggiungere è che:

  • Se si vuole essere scrupolosissimi, EqualityComparer<T>.Default potremmo considerarla una dipendenza. Anche se, così su due piedi, direi proprio che si tratta proprio di cercare "il pelo nell'uovo".
  • Il discorso che volevo fare aveva uno spettro leggermente pò più ampio.
    Ad esempio:
       1:  static T Sum<T>(T a, T b)
       2:  {
       3:      return a + b;
       4:  }

What's the state of object oriented programming?

Riprendo il post di Gian Maria per aggiungere qualche risorsa interessante.
La prima, che mi ha segnalato Matteo, è un breve, ma significativo, contributo di Robert C. Martn.

  • Java, c++, c# are just interpretations of OO [...]
  • I'm thinking dynamic polymorphism, that's really what OO is all about [...]
Ed ecco il link:
Oh oh! What is it?

C'è poi il contributo di Alan Kay:
Dr. Alan Kay on the Meaning of "Object-Oriented Programming"
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them.

Infine, è la volta di Dave Thomas:
Dave Thomas - On Modern Application Development
What's the state of object oriented programming? Commercially imensely succesful but practical is a disaster since it is difficult for people to do abstractions


Comunicazione di servizio
I ragazzi di dotnettoscana, del cui staff ho l'onore di fare parte, non stanno certo dormendo sugli allori!
Continua, difatti, la nostra "sperimentazione", che trova il suo naturale proseguimento con il prossimo evento.
So già che avremo molto di cui discutere e... molto codice da scrivere! :-)

Cross-cutting concerns and Microsoft guidelines

"MSDN Architecture Center"... un nome, una garanzia.
Volevo solo segnalare che il solito Ayende ha pubblicato una serie di post su quelle che, secondo Microsoft, sono le best pratices nello sviluppo di una "Domain Oriented N-Layered App".
I più coraggiosi, possono avventurarsi nella minuziosa review del celebre blogger.
Per quello che mi riguarda, vi segnalo solo il passaggio sui Cross-cutting concerns, perchè davvero merita:
Cross Cutting is a fine line

Vi lascio con una citazione dalla pagina principale di codeplex:

[...]Also, this sample goes along with our Architecture Guidance, and there are aspects in the guidance that are not covered by this sample, and viceversa.[...]

Che dite, ci dobbiamo preoccupare?

Microsoft compra Skype?

I rumors, a questo punto, sono sempre più assordanti.
Per noi sviluppatori che dedichiamo risorse ad una piattaforma come Windows Phone 7, questa manovra potrebbe rappresentare un'autentica manna dal cielo.
E' un pò quello di cui discutevo recentemente con i miei "colleghi" di dotnettoscana, ovvero che a WP7 serviva un "plus" che ne "giustificasse" l'acquisto. Ovviamente, gli sviluppatori Microsoft già da tempo si lasciano "cullare" dagli ozi della piattaforma di sviluppo basata su Silverlight/XNA, ma questo non era sufficiente a garantire la diffusione che questo dispositivo, a mio avviso, merita (gli ultimi dati di vendita sono piuttosto imbarazzanti).
Ecco, questa operazione potrebbe davvero rappresentare il definitivo "colpo di reni".

A quanto sembra, dovrebbero ufficializzare la notizia entro un paio di giorni.
Mi auguro che vada tutto in porto.

MVVM: is it always the right way?

In azienda abbiamo deciso di realizzare la nuova applicazione che ci hanno "committato" avvalendoci del pattern architetturale MVVM (o Presentation Model, o come diamine vogliate chiamarlo).
Da tantissimo tempo, oramai, sviluppo le applicazioni web con MVC.
Pensavo quindi che passare a MVVM sarebbe stato quasi "automatico".
Ebbene, mi sbagliavo.
Dopo una settimana trascorsa a discutere i dettagli con il mio collega Bruno ("come dici tu, non funzionerà mai..." ndBuyer :-P), siamo arrivati a manifestare i primi sintomi derivanti da frustrazione (insonnia, sguardo fisso nel vuoto, ecc).

Insomma, la mia esperienza, seppur breve, è piuttosto negativa.
Attenzione, non voglio dire che si tratti di un approccio non valido. Tutt'altro...
Sono fermamente convinto che sia la strada giusta da percorrere, ma ci sono ancora, sempre a mio avviso, degli aspetti oscuri, da valutare con attenzione.

Proprio ieri sera, mi è capitata sottomano una dicsussione risalente ad un pò di tempo fa.

MVVM, an Overcomplication or Incorrectly Used?

E' piuttosto lunga, ma vi assicuro che vale la pena leggerla.
Credo di aver maturato qualche certezza in più.
Nel corso della progettazione e dello sviluppo, ho intenzione di scrivere qualche post che descriva quello che è stato il nostro approccio alle problematiche che si ponevano di fronte a noi.

Alla prossima.

EL5: una dipendenza inutile

Ok, visto che sono quì, non vedo perchè dovrei privarmi del piacere di bloggare ancora per un pò.
A dire il vero, mi piacerebbe scrivere qualcosa su MEF, che ho cominciato a scoprire da poco e del quale mi sonosubito innamorato. In realtà, per motivi di tempo, mi voglio limitare a segnalare quella che, a mio avviso, è una piccola anomalia che ho riscontrato in Enterprise Library.
Sto seguendo un progetto piuttosto interessante e diciamo pure che ho accolto da subito con entusiasmo la sfida che mi è stata proposta.
Il problema è che mi trovo a che fare con dei database legacy della peggior specie. Anzi, devo chiaramente dire che è la peggior infrastruttura con la quale abbia mai avuto a che fare.
Sono innegabilmente un fan di NHibernate e la mia prima idea è stata quella di avvalermi di tale strumento per cercare di rendermi la vita un pò più semplice.
Niente da fare. E' probabile che ciò sia in qualche modo frutto della mia scarsa esperienza con il software legacy, ma applicare anche una primitiva forma di O/R Mapping a ciò che ho fra le mani è, secondo la mia modestissima opinione, una "Mission Impossible" per chiunque.
Mi sono quindi chiesto se non fosse il caso di utilizzare il Data Access Block di EL, giusto per alleviare un pò il dolore. E devo dire che l'impresa è riuscita egregiamente.
Mentre eseguivo i test, però, mi sono trovato a che fare con un'eccezione all'interno della quale mi veniva segnalato che, sostanzialmente, il componente in oggetto necessitava dell'assembly "Microsoft.Practices.Unity".
E perchè mai dovrei aggiungere un riferimento ad un componente come "Unity" se, ad esempio, risolvo le mie dipendenze con Castle Windsor?
Mi è sembrato tutto molto illogico.
L'analisi dello stack chiamava chiaramente in causa il costruttore di Microsoft.Practices.EnterpriseLibrary.Data.RefCountingDataReader.
Ecco cosa viene fuori dai sorgenti:

public RefCountingDataReader(DatabaseConnectionWrapper connection, IDataReader innerReader) : base(innerReader)
{
Guard.ArgumentNotNull(connection, "connection");
Guard.ArgumentNotNull(innerReader, "innerReader");
this.connectionWrapper = connection;
this.connectionWrapper.AddRef();
}


Ebbene, Guard è una classe (tra l'altro, pubblica) definita all'interno dell'assembly "Microsoft.Practices.Unity".
Perchè è stata compiuta questa scelta?
Non potevano, ad esempio, definirla all'interno di un assembly come, non so, "Microsoft.Practices.EnterpriseLibrary.Common"?
Insomma, stiamo parlando di una classe statica buttata nel mezzo senza il benchè minimo criterio.
C'è forse qualcuno che conviene con il sottoscritto?

RG .NET Reflector

Come vedete, non ho molto tempo per bloggare.
Oggi, però, un'eccezione devo pur concedermela.
Sono infatti venuto a conoscenza che .NET Reflector non è più uno strumento gratuito.
L'annuncio lo trovate quì.

Onestamente, ci sono rimasto male e la natura del mio malessere non deriva certo da quei 35 dollari.
Io  a colpi di reflector ci sono cresciuto, e ammetto di dover molto a questo strumento.
Proprio per questo motivo mi chiedo se non vi fossero effettivamente altre strade da percorrere.
Insomma, a mio avviso non è stata una mossa molto trasparente.

Ovviamente, è subito pronta l'alternativa (ILSpy).

Considerazioni su XNA 4.0

A tempo perso, o meglio, nei pochi attimi di tempo libero che ho a disposizione, mi diverto con XNA.
Saranno un paio di anni che tento di portare a termine un piccolo progettino e che spero vedrà la luce entro la fine dell'anno. Il punto è che nel corso di questo lasso di tempo si sono succeduti due rilasci per la piattaforma in questione e, ciascuno dei quali, diciamo pure che ha avuto un certo impatto. L'ultimo, poi, è stato semplicemente devastante.
Tanto per essere chiari, compilare un vecchio progetto XNA con la versione 4.0 produce un numero di errori di compilazione tale da farti quasi tremare le gambe. I famigerati Breaking changes, per intendersi.
Premetto che con l'ultima release di XNA ci viene consegnata, finalmente, un'ottima piattaforma, ma una piccola riflessione dobbiamo comunque farla.
Nel post di Shawn Hargreaves si fa riferimento al sentimento della comunità che l'autore del post ha riassunto con "If you break it, break it good".
Ecco, indipendentemente da quelle che sono le necessità che ti possono portare a tale conclusione, è proprio la condizione nella quale arrivi a trovarti il problema principale.
Parliamoci chiaramente, senza troppi rigiri, XNA è stato affetto sin dall'inizio da alcune scelte di design quantomeno discutibili e trovo che sia proprio questo il motivo per il quale i breaking changes sono in numero così copioso.
Le best pratice non incoraggiano certo a perseguire strade di questo tipo e Microsoft stessa ricorre spesso all'attributo "Obsolete" al fine di garantire una certa retrocompatibilità (tendo a farlo anch'io, nei limiti del possibile).
Certo, per quanto se ne dica, io resto sempre dell'idea che XNA, alla fine, rappresenti poco più che un wrapper su DirectX, ma questo non è sufficiente ad eludere un deficit di design che è apparso evidente a tutti.
Leggevo qualche giorno fa un post di Andrea (non vorrei mai essere suo nemico! :-)). Certo, ha ragione, niente da dire, ma cerchiamo di vedere, per una volta, anche il rovescio della medaglia, ovvero che alla prudenza deve essere riconosciuto comunque un certo valore. Al progetto XNA, magari è mancata proprio quest'ultima.
Ora, non vorrei essere frainteso, perchè trovo che Shawn ed il suo gruppo abbiano fatto davvero un gran lavoro, e con una roadmap molto rigida in termini di tempistica, come lui stesso sembra ammettere.
Comunque, e scadiamo nella retorica, tutto è bene quel che finisce bene!
Forse, e dico "forse", qualche noia agli sviluppatori poteva essere evitata, con un pò più di avvedutezza.
Tutto lì. :-P

Entity matching - sei sicuro? l'accendiamo?

Mi vergogno quasi ad ammetterlo, ma effettivamente non ci avevo mai pensato.
Questo fine settimana ho navigato un pò in internet, al fine di trovare qualche idea per arricchire ulteriormente il Domain Model dell'applicazione alla quale sto lavorando e, in particolar modo, definire il più elegantemente possibile un criterio per la comparazione delle entità. La parte che, tendenzialmente, tenevo meno in considerazione era quella relativa all'hashing dell'istanza. Il punto è che, in linea del tutto teorica, il metodo GetHashCode per due tipi differenti può restituire il medesimo valore.
public override Int32 GetHashCode()
{
    IEnumerable<PropertyInfo> signatureProperties = GetSignatureProperties();
    Int32 hashCode = GetType().GetHashCode();

    foreach (PropertyInfo property in signatureProperties)
    {
        Object value = property.GetValue(this, null);

        if (value != null)
            hashCode = hashCode ^ value.GetHashCode();
    }

    return signatureProperties.Any() ? hashCode : base.GetHashCode();
}
Il metodo GetSignatureProperties fornisce la collezione degli elementi a partire dai quali si determina l'hash.
Quest'ultimo, per le considerazioni di cui sopra, deve tenere conto anche del tipo dell'oggetto.
Insomma, io credo che la questione sia tutt'altro che banale, e questo post rappresenta a mio avviso un'autentica miniera di best-pratices.
Giusto a titolo di esempio, qualcuno si è mai posto il problema di valutare l'equivalenza tra una entity POCO e il suo proxy?
«settembre»
domlunmarmergiovensab
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678