Identity ou UniqueIdentifier (Guid) ?

Publié par Fabrice Michellonet sous le(s) label(s) le 26 octobre 2010

Je dois être maudit ! Cela fait prés de 3 ans que sur tous les projets sur lesquels j’interviens, le sempiternel troll du Identity vs Guid revient me hanter.

Non, non, non… je ne suis pas un ayatollah de la base de donnée… je n’ai rien contre les GUID ! Mais pourtant j’ai quand même du mal à comprendre pourquoi on a tendance à en coller partout, même quand ca n’a aucun sens… et ca j’ai vraiment du mal…

Mettons notre casquette de dba (je sais… beurk !)

Le Guid c’est le mal (sauf pour la réplication ou l’on n’a pas le choix)… car :

  • en production, on a vu plus simple que d’écrire des jointures sur des choses aussi imbitables, et anti-mémorisable que B2F62BF0-5CE0-408c-B749-F37D76AF5629.

  • Les perfs sont juste pourries par rapports à celles que l’on obtiendrait avec un int. J’en entends déjà plus d’un ricaner et prêt à me soutenir le contraire….Bien ! Rendez-vous sur ce benchmark, et prenez même 10 minutes pour lancer le test chez vous… c’est flagrant !Ce qui est étonnant, c’est qu’un grand nombre de développeurs, y compris des gens très brillant, passent à côté de ce point… certain m’ont déjà soutenu le contraire… au secours !

Mettons notre casquette de développeur :

Le Guid c’est la meilleure invention depuis le garbage collector… ! Si si je fais mon gloubi-boulga et puis je referme le capot, ca marche à tout les coups… c’est génial le GUID.

Dans une architecture en couche, je peux générer des Id dans ma couche client, associer des entités entre elles… puis :

Si j’ai envie de les persister, pas de soucis et pas d’aller retour avec la le tiers de persistance (base de données), mes identifiants sont à coup sur uniques.

Si j’ai envie d’annuler tout ce que j’ai fais, bah je cache méthodiquement tout sous le tapis (lisez : je laisse travailler le garbage collector).

Tandis qu’un Int en tant qu’identifiant, qu’est ce que c’est embêtant… je crée une entité sur mon client mais tant que je n’ai pas fait d’aller retour avec ma base de donnée, je n’ai aucun moyen de savoir son identifiant…

Vous voulez associer un produit et sa catégorie de produit tout deux nouvellement crées ? Possible, mais on va devoir écrire un peu de code et faire des allers-retours avec la base.

Bref… vu d’en haut l’identity c’est chiant… on est d’accord.

PS : Pour ceux qui me diraient qu’on est pas obligé de faire des applications en couches séparées… bah…. ils ont raison, mais sur un projet un minimum important ca devient vite difficile à maintenir de tout coder dans la form (aussi bien web que win)… faut que vous jetiez un coup d’œil au TDD.

Voila, c’est la que commence à mon sens notre vrai travail. Il nous faut estimer les avantages et les inconvénients des deux approches, et faire un choix entre la performance pure de la base et grosso modo la vitesse de développement de l’application… en ces temps ou le mot d’agilité et dans la bouche de tous, le choix est vite fait… Promis m’sieur y’a quelques temps j’arrivais encore à faire le grand écart…

Bon tout ca c’est bien beau, mais alors quelqu’un pourrait m’expliquer pourquoi il m’arrive de tomber sur des bases qui sont truffées de GUID (seul type de donnée utilisé comme clé primaire des tables) lorsque celles-ci sont attaquées par une application en mode client-serveur ? Franchement, la, ca me dépasse !

Bon, aller pour ceux qui ont réussi à me lire jusqu’ici, voici quelques liens supplémentaires sur le sujet :

Les racines des problèmes que posent les GUID avec les index Clustered

la fonction SQL-SERVER NEWSEQUENTIALID() si on adore les GUID dans SQL et que l’on ne peut s’en passer.

Et le meilleur pour la fin, je vous laisse réfléchir sur la phrase suivante trouvée dans la MSDN :

Consider using the IDENTITY property when global uniqueness is not required, or when having a serially incrementing key is preferred.

Evidemment, si certain d’entre vous on envie de troller sur le sujet… les commentaires sont fait pour ca :)

JetBrains supporte l'Open Source

Publié par Fabrice Michellonet sous le(s) label(s) le 27 avril 2010

Comme vous le savez sûrement, la version 5 de Resharper est disponible depuis quelques temps, évidement pour supporter la version 2010 de Visual Studio; même si le produit est installable sur un Visual Studio 2008. Le but de ce post, n'est pas juste de vous annoncer la mise à dispo d'un soft et d'en faire la pub, c'est vraiment pas mon genre, et encore moins le but de ce blog.

Bon retour en arrière de quelques mois, je tombe (presque) par hasard sur le page de licensing de Resharper (à l'époque version 4.5) et je me disais que ca serait sûrement un bon investissement; Après tout, un code écrit plus vite, et avec moins de bugs (Modified Closure), c'est bon pour mes clients, ma boite et puis pour moi aussi au final. Bref, plusieurs type de licences sont listées sur le site, dont une Licence Open Source GRATUITE...

Ouarf ouarf ouaf, s'écrit mon côté pessimiste...

Ça c'est de la bonne pub gratuite.

J'approfondis un peu, il est dit qu'il faut présenter son projet Open Source, prouver sa participation dans le projet et une commission décidera si une licence gratuite sera attribuée etc...

Bon ok, en gros derrière dois y avoir une vieille boite mail que plus personne ne lit, et de toute façon ca m'étonnerait que les mecs aient le temps et l'envie de faire autre chose que coder pour leurs softs... alors de la à aller jeter un œil sur les projets Open Source soumis, puis faire une commission faudrait pas pousser quand même

Je vous l'accorde, ce jour la je devais être en mode Christophe... un peu beaucoup bougon! :)

Bon, pas très grave tout ca, car très peu de temps après je démarre une nouvelle mission (mon client actuel), et il se trouve que Resharper fait partie du toolkit de tout les développeurs... Ouf, j'vais pouvoir faire illusion, et faire croire que je sais un peu programmer.

Pas mal de temps passe, la question de l'acquisition de Resharper n'est plus trop d'actualité, jusqu'à ce que les betas de la version 5 ne commencent a être mise à dispo. Et puis lorsque la version finale sort, je ne peux m'empêcher de l'installer, pour 30 jours seulement en version demo... sniff.

Alors, il y a moins d'une semaine, je me lance, et soumet à la fameuse commission mon pet projet actuel (Claymore), sans trop de conviction. Et figurez vous qu'a peine 3 jours après (un dimanche exactement... bah oui les commissions de développeurs c'est en dehors des heures de travail) la bonne nouvelle tombe dans ma boite mail... j'ai le droit a une version Full de Resharper 5.0 pendant 1 an grâce à ce projet Open Source.

Donc déjà, je vous demande pardon mesdames et messieurs de chez JetBrains d'avoir douté de votre parole. Merci de cet effort que vous consentez pour améliorer la qualité du code Open Source. Et puis, j'suis sur que mes clients actuels et futures vous remercieront aussi... j'ferais moins de bugs grâce a vous.

Moralité, si vous avez un bout de code qui vaut le coup d'être mis à dispo des autres, et qui de toute façon ne vous rendra pas millionnaire, publiez-le, il vous permettra peut être d'avoir une licence gratuite de Resharper.

Update [28 Avril 2010] : Jérôme m'a fait remarquer que mon lien vers l'exemple de Modified Closure était erroné. C'est corrigé.

Overriding et Shadowing de méthodes en IL.

Publié par Fabrice Michellonet sous le(s) label(s) le 23 avril 2010

En ce moment je fais joujou avec les opcodes CIL qui se cachent sous notre bon vieux C#.

En voulant surcharger et cacher (shadow) successivement deux propriétés hérités, j'ai remarqué que le compilo générait une suite de metadata assez déroutante. Prenons l'exemple suivant :

public class BaseClass
    {
        public int Prop1 { get; set; }
        public virtual int Prop2 { get; set; }
        public virtual int Prop3 { get; set; }
    }

    public class DerivClass : BaseClass
    {
        public int Prop1 { get; set; }
        public new int Prop2 { get; set; }
        public new virtual int Prop3 { get; set; }
    }

Du coté de la classe de base on obtient les metadata suivantes sur le getter :

non virtual :

.method public hidebysig specialname instance int32 get_Prop1() cil managed
virtual :
.method public hidebysig specialname newslot virtual instance int32 get_Prop2() cil managed
remarquez l'utilisation conjointes des metadata virtual et newslot, je reviendrais dessus juste après.

Côté classe dérivée on obtient cela :

non virtual :

.method public hidebysig specialname instance int32 get_Prop1() cil managed
new :
.method public hidebysig specialname instance int32 get_Prop2() cil managed
virtual new :
.method public hidebysig specialname newslot virtual instance int32 get_Prop3() cil managed

Oulaaa... c'est la que ca se corse!! Dans la classe de base, comme je vous le faisait remarquer précédemment, le compilo utilise conjointement les metadata virtual et newslot. Logiquement, on aurait pu s'attendre a voir uniquement le virtual.

Dans la classe dérivée, le shadowing non virtuel

public new int Prop2 { get; set; }
produit des metadata token strictement identiques à une propriété normale; et le shadowing virtuel produit un IL identique à propriété virtuelle.

De ces constatation on peut en déduire que : Le token newslot, ne suffit pas à affirmer qu'il s'agit d'une shadowing methode (le getter non-virtuel de la classe de base et le getter new de la classe dérivée ayant les mêmes metadata).

Par contre, si une méthode contient le token virtual mais pas le newslot, alors c'est qu'il s'agit a coup sur d'un overriding et pas un shadowing.

Par déduction, on peut donc penser que si une méthode n'est pas un overriding (le token newslot est présent), alors il n'y a shadowing que si la signature [type de retour, nom et paramètres de la méthode] de la méthode existe également dans la classe de base.

Interagir avec les pages ASP.NET avant l'Init.

Publié par Fabrice Michellonet sous le(s) label(s) , le 21 avril 2010

Au cours du développement de Claymore, pour la partie ASP.NET plus précisément, j'ai eu besoin de trouver un hook me donnant la possibilité d'interagir avec les pages avant les events que l'on trouve sur l'objet Page.

J'ai tout d'abord pensé tripatouiller dans le fichier Global.asax... sans finalement avoir trouvé ce que je souhaitais. Par contre, en fouillant un peu du côté des HttpModule je suis arrivé à la solution suivante :

using System;
using System.Reflection;
using System.Web;
using System.Web.UI;

namespace Claymore.Web
{
    /// <summary>
    /// 
    /// </summary>
    public class ClaymoreHttpModule : IHttpModule
    {
        #region Fields

        private HttpApplication _application;

        #endregion

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="context"> </param>An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application
        public void Init(HttpApplication context)
        {
            if(context == null)
                throw  new ArgumentNullException("context");

            _application = context;

            context.PostMapRequestHandler += onPostMapRequestHandler;
        }


        /// <summary>
        /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
        /// </summary>
        public void Dispose(){}

        /// <summary>
        /// Handle PostMapRequest event.
        /// </summary>
        /// <param name="sender"> </param>The sender.
        /// <param name="e"> </param>The <see cref="System.EventArgs"/> instance containing the event data.
        private void onPostMapRequestHandler(object sender, EventArgs e)
        {
            Page pageHandler;
            if ((pageHandler = _application.Context.Handler as Page) != null)
                pageHandler.PreInit += HandlePreInit;
        }

        /// <summary>
        /// Handles the pre init event.
        /// </summary>
        /// <param name="sender"> </param>The sender.
        /// <param name="e"> </param>The <see cref="System.EventArgs"/> instance containing the event data.
        protected virtual void HandlePreInit(object sender, EventArgs e)
        {
            Page page = sender as Page;
            if (page != null){
                // Et voila, on a un pointeur sur une page, et l'on peut interagir avec elle avant l'événement Init.
                // Ajouter du code ici.
            }
        }
    }
}

L'un d'entre vous connaîtrait-il une solution équivalente à base de HttpHandler ou autre?

Benchmark WCF vs ASMX, Remoting, WSE, Enterprise Services.

Publié par Fabrice Michellonet sous le(s) label(s) le 5 avril 2010

Je relais assez peu souvent les infos glanées sur tel ou tel site, préférant vous montrer un peu de code :)

Ceci dit ce soir je fais une exception, en vous encourageant vivement a jeter un coup d'œil au benchmark des technos de mise en réseau que nous, développeurs .NET, avons à notre dispositions.

Le bench, étudie de manière approfondie chaque techno, et la compare dans un scenario viable et réaliste de leurs utilisations.

Je ne peux m'empêcher de vous donner une idée de ce qu'il en ressort :

To summarize the results, WCF is 25%—50% faster than ASP.NET Web Services, and approximately 25% faster than .NET Remoting. Comparison with .NET Enterprise Service is load dependant, as in one case WCF is nearly 100% faster but in another scenario it is nearly 25% slower. For WSE 2.0/3.0 implementations, migrating them to WCF will obviously provide the most significant performance gains of almost 4x.

Donc , lorsque vous entamerez un nouveau projet, sans contraintes techniques spécifiques sur la partie mise en réseau, il n'y a plus d'excuse... c'est WCF ou rien :p

Version 1.1.0.0 de Claymore

Publié par Fabrice Michellonet sous le(s) label(s) , le 31 mars 2010

Suite à la demande d'un utilisateur sur Codeplex de pouvoir utiliser Claymore avec le Compact Framework, j'ai ajouté cette feature dans la librairie; Plus précisément, il existe désormais une assembly qui vise spécifiquement cette version du Framework.

Les classes du Namespace Configuration n'existant pas dans le Compact Framework, j'ai donc du ajouter une API permettant de configurer par code, le fonctionnement de la librairie, tout comme il est possible de le faire en passant par une configuration dans le fichier app.config ou web.config.

J'en ai profité pour designer l'API de configuration en suivant les conventions des Fluent interfaces; Ce type d'écriture semblant être de plus en plus apprécié des développeurs que nous sommes.

Bon téléchargement, et n'hésitez pas à me dire ce que vous en pensez.

Claymore - Framework MVP

Publié par Fabrice Michellonet sous le(s) label(s) , le 19 février 2010

Non non non, vous ne rêvez pas... non non je ne suis pas mort! Ça faisait bien longtemps que je n'avais pas eu et pas pris le temps de mettre à jour ce blog... Qui as dit que les enfants n'était pas chronophages? :)

Depuis près de deux ans, les missions sur lesquelles j'interviens sont très souvent liées au développement Winform et malheureusement à chaque fois c'est le même constat; les forms et/ou usercontrol sont un joli mélange de code métier et de gestion d'interface graphique, sans parler des cas ou l'on retrouve même le code d'accès aux données fourré au beau milieu de ce jolie petit monde.

Pourtant, cela fait bien longtemps que l'on connait les patterns MVC, MVP et depuis quelques temps le MVVM qui prend son essor avec Silverlight.

En demandant aux architectes ou Lead techniques de ces projets, ce qui avait justifié de ne pas appliquer un des ces patterns, la réponse est presque toujours la même : L'implémentation de ces modèles dans les applications rallonge (parfois beaucoup) les temps de développement, demande des compétences un peu plus high level de la part des développeurs, et la montée en compétence sur les frameworks existants est parfois très lente.

Entre nous, avant de pouvoir appréhender et amortir le temps d'apprentissage d'un framework comme Smart Client - Composite UI Application Block de Microsoft, le projet à intérêt à s'étaler sur un an au minimum.

Afin de rester impartial, je ne m'étendrais pas sur les autres framework MVP qui peuvent se trouver sur la toile.

Bref, il me semblait qu'il serait intéressant d'avoir un framework MVP simple d'utilisation dans mon escarcelle pour les prochains projets. J'ai donc commencé à écrire ça dans mon coin; Aujourd'hui Claymore me semble assez mûre pour le mettre à disposition des autres, et je l'ai donc publié sur codeplex. Évidemment, Claymore fonctionne avec les projets Winform mais je n'ai pu m'empêcher d'ajouter aussi le support des projets ASP.NET.

J'espère que ce framework saura vous aider à découpler les couches métiers des couches UI...