Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Article ! Le Binding Xaml, sa syntaxe, éviter ses pièges… (WPF/Silverlight)

imagePromis dans mon dernier billet, le voici enfin ! Ce nouvel article dédié au binding Xaml pèse 77 pages (le record était tenu jusqu’à lors par mon article M-V-VM avec Silverlight avec 70 pages) et se présente sous la forme d’un PDF et de 9 projets exemples.

Le binding cet inconnu … J’en parlais dans mon billet Le retour du spaghetti vengeur, le binding avec sa syntaxe pleine d’accolades et de chaînes de caractères non contrôlées à la compilation est un piège à bugs et la porte ouverte au code spaghetti.

Plutôt que de me lamenter et vous laisser vous embourber dans la sauce de ces spaghetti là, j’ai pris ma plume, et voici le résultat : 77 pages sur le binding Xaml, son fonctionnement, ses différentes syntaxes le tout illustré par des exemples clairs. L’article aborde aussi le débogue du binding assez délicat puisque Xaml échappe au débogueur de Visual Studio, et que le binding n’est que partiellement couvert par Intellisense.

Des conseils, du vécu, beaucoup d’exemples, voilà ce que vous trouverez dans cet article à télécharger en suivant le lien suivant :

Le Binding Xaml – Maîtriser sa syntaxe et éviter ses pièges (WPF/Silverlight)

(Attention, avant de cliquer sur le bouton “télécharger” attendez que la fiche détail de l’article soit bien affichée, sinon le site pensera que vous tentez un accès à une ressource non publique et vous demandera un login… Je reçois tous les jours des demandes d’ouverture de compte provenant de lecteurs trop impatients qui cliquent trop vite sur le bouton ! La prochaine version du site en Silverlight est en préparation et corrigera ce petit problème, mais d’ici là : slow down cowboy !).

Pour vous aider à vous faire une idée du contenu de l’article voici son sommaire :

Sommaire

  • Références    5
  • Code Source    6
  • Préambule    7
  • Le Binding Xaml : Ange ou Démon ?    7
    • Le Binding    8
    • Définition    8
    • Utilisations    9
    • Schéma du principe    9
    • Déclaration    10
      • Par code    10
      • En Xaml    11
  • Les modes de binding    13
    • Le mode OneTime    13
    • Le mode OneWay    13
    • Le mode TwoWay    14
      • Gestion du timing    14
    • Le mode Default    16
    • Le mode OneWayToSource    16
  • Hiérarchie de valeur    18
    • Règles de précédences    19
  • La notion de  DataContext    20
  • Les convertisseurs de valeur    21
    • Définition    21
    • Scénario    21
    • Implémentation    22
    • Utilisation    23
      • Instanciation    23
      • Invocation    23
      • Bonnes pratiques    24
      • Pour résumer    26
  • Les dangers du Binding    27
    • Des chaînes non contrôlées    27
    • Un langage dans le langage    28
  • On fait quoi ?    28
  • Déboguer le Binding    28
    • Vigilance    28
    • Une code Xaml court    29
    • Refactoring sous contrôle    29
    • Utiliser des outils intelligents    29
    • Utiliser Expression Blend    29
    • Vérifier les erreurs de binding dans la fenêtre de sortie    30
    • Créer un fichier des erreurs de Binding    30
    • La feinte du convertisseur inutile    32
    • Quelques outils supplémentaires    33
      • Spy++    33
      • ManagedSpy    33
      • Snoop    34
      • Mole    34
      • Reflector    34
      • Vos neurones    34
  • Les syntaxes du Binding    34
    • Le binding simple    34
      • Binding direct    35
      • Binding sur une propriété    35
      • Binding sur une sous-propriété du contexte    36
      • L’Element Binding    37
      • Convertisseurs de valeur    37
        • Paramètres de conversion    38
      • StringFormat    40
        • Injection de culture    41
        • Le ContentStringFormat    42
        • Gérer les nuls    43
    • Le Binding Multiple    44
      • La classe Personne    44
      • Le code du multi convertisseur    45
      • Le code Xaml    46
    • Le Binding XML    47
      • Binding sur une source Web    47
      • Binding sur une source XML en ressource    48
      • Binding sur une requête Linq To XML    49
    • Le Binding Relatif    52
      • Binding to Self    52
      • Le TemplatedParent Binding    53
      • Le Binding sur recherche d’ancêtre    54
      • Le Binding PreviousData    56
        • La source de données    58
        • La visibilité des flèches : la magie de PreviousData et du Binding Multiple    58
        • Le contenu des textes    61
      • Le Template binding    61
        • Utilité    61
      • Le Collection Binding    67
      • Le Priority Binding    69
  • Les propriétés de tous les bindings    74
  • Conclusion    76

Avril est froid et pluvieux mais les soirées rallongent, c’est le printemps même si cela n’y ressemble pas encore beaucoup, grâce à moi vous savez maintenant comment occuper vos soirées et vos weekend au lieu de faire l’idiot dans les embouteillages des vacances : Lisez cet article !

Et Stay Tuned !

Article: M-V-VM avec Silverlight

Model-View-ViewModel, je vous en parlais il y a très peu de temps (MVVM, Unity, Prism, Inversion of Control…) et je vous avais promis un exemple pour rendre tout cela plus concret. C’est fait ! Et même mieux, un article de 70 pages l’accompagne !

Vous saurez tout (ou presque) sur cette design pattern absolument incontournable pour développer sérieusement sous Silverlight.

Après des explications sur la pattern elle-même l’article vous présente une application exemple entièrement réalisée avec ce qu’il y a “out of the box”. J’ai fait le choix de n’utiliser aucun Framework existant (Prism, Cinch, Silverlight.FX, MVVM Light…) pour vous montrer que M-V-VM peut entièrement être mis en œuvre “à la main” sans aide extérieure.

Cela ne veut pas dire que tous ces Frameworks (dont l’article parle aussi) ne sont pas intéressants, au contraire ! Mais comment choisir une librairie facilitant M-V-VM si vous ne savez pas comment mettre en œuvre cette pattern et si vous ne connaissez pas les difficultés qu’elle soulève autant que ses avantages ?

Cet article vous permettra de faire le point sur M-V-VM et de pouvoir ensuite choisir le Framework qu’il vous plaira en toute connaissance de cause ou bien cela vous aidera à développer votre propre solution. Après tout, l’application exemple fonctionne parfaitement sans aucun de ces Frameworks….

Le code source du projet est fourni. En raison de l’énorme avantage de la gestion des commandes introduites dans Silverlight 4 (toujours en beta) l’article utilise cette version qui sera bientôt disponible. Tout est expliqué pour savoir comment faire fonctionner le code exemple à l’aide de VS 2010 ou Blend 4 (en beta aussi).

L’article peut être lu sans faire tourner le code si vous ne souhaitez pas installer la beta de SL4, et la première partie théorique s’applique aussi bien à M-V-VM sous SL3.

Bonne lecture !

(PS: n'oubliez pas que depuiis août 2012 les articles sont regroupés sur la page publications).

Téléchargement ici : M-V-VM avec Silverlight, de la théorie à la pratique.

 

 

 

 

MVVM, Unity, Prism, Inversion of Control…

Dans la série, presque culte, que je diffuse régulièrement et dont le titre serait “comment ne pas passer pour un idiot à la machine à café” la belle brochette de termes que je vous propose aujourd’hui a de quoi plonger le non initié dans une profonde perplexité !

Tous ces termes sont plus ou moins liés entre eux, les uns renvoyant aux autres ou les autres utilisant les uns.

MVVM ou plutôt M-V-VM

“Ah oui ! avec les tirets on comprend tout de suite mieux !” (Jean Sérien, lecteur assidu).

Model-View-ViewModel. Ca bégaye un peu mais c’est pourtant ça.

En réalité vous connaissez certainement le principe qui vient de M-V-C, Model-View-Controler, Modèle-Vue-Contrôleur. Une stratégie de développement visant à découpler le plus possible les données de leurs représentations. Sinon je vous laisse vous faire une idée, depuis dix ans au moins le Web est plein de pages présentant cette approche. Le billet du jour n’est pas d’aller dans les détails, juste de planter le décor avant d’aller plus loin dans d’autres billets.

Alors pourquoi MVVM plutôt que MVC ? C’est en tout cas le premier terme qui devient de plus en plus à la mode dans le monde WPF / Silverlight. Une réponse un peu courte je l’avoue… Mais même Prism (j’en parle plus loin) dans sa version 2 et qui, entre autres choses, présente cette stratégie ne l’évoque pas sous ce nom mais sous diverses autres formes. Autant dire que terminologiquement parlant, savoir ce que veut dire MVVM est un must de l’instant !

Donc M-V-VM est un modèle de développement, une façon de structurer l’écriture du code dont le but ultime est de séparer le Modèle (les données) des Vues (l’IHM ou l’UI), le tout en passant par un intermédiaire, le contrôleur qui s’appelle dans cette variante ViewModel (et pour lequel je ne trouve pas de traduction vraiment limpide).

La vraie question, légitime est : ce changement d’appellation cache-t-il un changement de rôle ? Les puristes vous diront bien entendu que oui, sinon ils n’auraient pas inventé un nouveau nom… Les pragmatiques dont je suis vous diront que lorsqu’on veut relancer un produit un peu trop connu mais toujours valable, on change son nom ce qui permet de communiquer à nouveau dessus plus facilement… Les méthodologistes sont des futés… Certains vont jusqu’à parler de parenté avec la pattern Presentation-Model, un peu comme d’autres vous expliquent que C# vient de C++ plutôt que de dire qu’il vient de Delphi. S’inventer des origines plus ou moins nobles (ou du moins qui le paraissent) est un jeu finalement très humain qui nous intéresse que peu ici.

Mais pour être totalement juste j’ajouterais qu’il y a en fait une véritable évolution de point de vue entre M-V-C, dont on parlait déjà du temps de Delphi Win32 et C++, et M-V-VM qu’on applique à WPF ou Silverlight. Par force le temps passe, les outils se sophistiquent et les pensées s’aiguisent. Donc, bien sûr, il y a quelques variations entre ce qu’on entendait par “contrôleur” dans MVC et ce qu’on entend par ViewModel dans MVVM. Mais, à mon sens, cela est mineur. D’ailleurs de nombreux forums proposent des threads à rallonge où des tas d’experts (autoproclamés) se déchirent sur ces nuances. Dépassons ces débats stériles.

Pourquoi MVVM est-il en train de s’imposer sous WPF / Silverlight ? Simplement parce que “out-of-the-box” Visual Studio et Blend ne permettent pas directement de vraiment séparer le travail entre les développeurs et les designers. Volonté pourtant clairement affichée de ces produits. Les outils eux-mêmes mélangent un peu des deux compétences (un peu plus de design dans Blend, un peu plus de développement dans VS).

Mais lorsqu’il faut écrire de vraies applications avec WPF ou Silverlight et qu’on a de vraies équipes à gérer, c’est à dire des informaticiens d’un côté et un ou plusieurs infographistes de l’autre, il faut bien convenir que sans une approche appropriée ça coince. Non pas que techniquement les outils (Blend, VS) ne sont pas à la hauteur, ni même que les langages (Xaml, C#, VB) ne sont pas bien étudiés. Au contraire. La faille est ici humaine et méthodologique.

En réalité tous les outils du monde, aussi bien faits soient-ils, ne peuvent permettre aux informaticiens l’économie d’une méthodologie bien pensée… Ce que Microsoft propose avec WPF / Silverlight, Xaml et le Framework .NET est très nouveau et il faut du temps pour maîtriser ces outils qui évoluent beaucoup en peu de temps. Dégager des stratégies de développement pertinentes est plus long que de créer un nouveau compilateur.

Or, si on regarde une fenêtre WPF ou une page Silverlight, on voit immédiatement qu’il existe du code-behind joint au fichier Xaml selon un modèle vieux de 15 ans (le couple de fichiers DFM/PAS des TForm de Delphi 1 en 1995 par exemple). La tentation est alors bien grande de coder l’action d’un click sur un bouton directement dans ce code puisqu’il est là pour ça ! Si c’est autorisé, c’est utilisé. Et malgré une séparation forte du code métier (ce qui suppose d’avoir fait cet effort) on se retrouve au final avec une interface qui contient du code qui en appelle d’autres (le code métier ou les données) voire pire, qui contient des petits bouts de traitement ! Autant dire que certains codes Silverlight ou WPF que j’ai audités récemment ressemblent comme deux gouttes d’eau au code spaghetti Delphi que j’ai audité dans les 15 dernières années… La vie n’est qu’un éternellement recommencement disent certains. Je n’ai pas cette vision nihiliste de l’existence, mais en informatique, hélas, cela se confirme !

Vade Retro, Satana !

En dehors de l’imbroglio qui résulte de cette situation, le code final de l’application est donc difficilement maintenable, intestable de façon cloisonnée (donc obligeant à des tests depuis l’interface par des testeurs ou des outils simulant un humain qui clique sur les boutons) et, comble du comble, il est en réalité presque impossible de séparer proprement le travail des informaticiens et des designers ! L’enfer brûlant s’ouvre alors sous les pieds des infortunés développeurs qui croyaient pourtant avoir “tout fait comme il faut”. Bad luck. On est loin du compte.

M-V-VM permet ainsi de régler plusieurs problèmes d’un coup : meilleure maintenabilité du code, vraie séparation entre code et interface, tests unitaires du code possibles sans même qu’il existe encore d’interface (ou totalement indépendamment de celle-ci), et enfin vraie séparation entre infographistes et informaticiens.

En pratique le fichier de code-behind ne sert plus à rien et reste vide. Les Vues (interface utilisateur) utilisent leur DataContext pour se lier à une instance du ViewModel qui lui sait utiliser le Model (les données). Grâce à cette notion de DataContext et au puissant Data Binding de Xaml on peut mettre en place une séparation bien nette avec, au final, peu de code en plus.

Reste le problème des événements de l’UI comme le simple clic sur un bouton. Comment le programmer sans code-behind ? Sous WPF la réponse est simple puisqu’il existe une gestion des commandes complète (le CommandManager et d’autres classes). L’interface ICommand est la base de ce mécanisme, les contrôles qui ont des propriétés de ce type peuvent donc être bindées au code des actions se trouvant alors placé dans le ViewModel, comme n’importe quelle autre propriété peut être liée via le binding.

Ce modèle est d’une grande élégance il faut l’avouer. J’aime plaisanter et je joke souvent dans mes billets, mais il ne faudrait pas croire que je passerais du temps à écrire un long billet sur un sujet futile ou une simple réinvention stérile de vieux procédés. M-V-VM est “la” façon de coder proprement sous WPF et Silverlight. Il n’y en a pas d’autres (d’aussi abouties pour l’instant en tout cas). Tout le reste ne peut que créer du code spaghetti. Cela peut choquer, vous paraître extrême dit comme ça, mais pourtant c’est la vérité…

C’est pourquoi je vous proposerais bientôt un autre billet abordant par l’exemple la stratégie M-V-VM.

Mais pour l’instant revenons deux secondes sur cette fameuse gestion des commandes de WPF. Et Silverlight ? Hélas malgré l’enthousiasme que vous me connaissez pour ce dernier et sa convergence avec WPF, il faut reconnaître que cette dernière n’est pas terminée. On le dit souvent, Silverlight est un sous ensemble de WPF, même si ce n’est plus tout à fait vrai. On avance aussi que le plugin est trop petit pour contenir tout ce qui fait WPF. C’est vrai. Mais comme je le disais dans un autre billet, avec une installation personnalisée du Framework ce dernier peut tenir dans 30 Mo. C’est bien plus gros que le plugin SL actuel. Mais j’ai joué pas plus tard qu’hier avec une application écrite en Adobe Air, et justement le download de Air fait environ 30 Mo. Pour un résultat tellement navrant que j’ai tout désintallé d’ailleurs. Alors d’ici quelques versions de SL, peut-être Microsoft (et les utilisateurs) accepteront-ils l’idée qu’un produit aussi bien ficelé puisse justifier les 10 ou 20 Mo de plus à télécharger (une fois) pour avoir enfin un équivalent absolu de WPF… Mais ce n’est pas encore le cas, force est de le constater.

Donc Silverlight pour le moment propose ICommand, l’interface, mais pas tout le reste qui fait la gestion des commandes sous WPF. De fait, dans Silverlight il faut ajouter un peu de code pour recréer cette dernière. C’est le but d’un petit framework comme “MVVM Light” qui se base sur les principes édictés dans Prism. Mais on peut inventer d’autres solutions.

Donc pour faire du M-V-VM avec WPF, tout est dans la boîte, avec Silverlight il faut ajouter une simulation, même minimaliste, de la gestion des commandes afin que ces dernières puissent être intégrées au ViewModel et que la Vue puisse être liée aux actions du ViewModel par un binding sur des propriétés de type ICommand.

Prism 2

Cela nous amène à évoquer Prism “patterns and practices : Composite WPF and Silverlight”.

Il s’agit d’une réflexion méthodologique dont les fruits se présentent sous la forme de conseils et d’applications exemples. Prism couvre de nombreux champs et propose des solutions élégantes.

Cela ne serait pas fairplay d’en parler en quelques lignes, c’est un travail d’une grande qualité qui ne se résume pas en trois phrases. Je vous conseille vivement sa lecture, rien ne peut remplacer cet investissement personnel.

Mais puisqu’aujourd’hui le but est de planter le décors, il aurait été tout aussi impardonnable de “zapper” Prism, surtout que certaines solutions permettant d’implémenter M-V-VM sous Silverlight y sont présentées.

Je reviendrai certainement un jour sur Prism, c’est d’une telle richesse que j’ai vraiment envie de vous en parler plus. Prism est incontournable, mais ne peut se résumer dans un billet. Si je trouve le moyen d’un tel tour de force alors je vous en reparlerai en détails. Mais le meilleur conseil c’est encore que vous le lisiez vous-mêmes…

Unity Application Block

Unity est un framework Microsoft qu’on trouve dans la série “patterns & practices”. Une mine d’or de la méthodologie sous .NET d’où provient aussi Prism dont je parlais ci-dessus.

Il faut noter que MS fait d’immenses efforts pour ouvrir la réflexion sur les méthodologies tout en tentant le tour de force de rendre ces cogitations tangibles. Lorsqu’on connaît un peu les méthodologistes pour les avoir fréquentés, toujours perdus dans leurs hautes sphères et rebutant à se “salir” les mains avec du code, on imagine à quel point l’effort de Microsoft est louable et tellement remarquable que cela mérite d’insister un peu sur la valeur de patterns & practices.

Ainsi, Unity, tout comme Prism, ne se contente pas d’être un gros pavé d’explications qui seraient réservées à une certaine élite. Unity se sont bien entendu des explications mais aussi du code qui permet d’ajouter l’action à la réflexion. Du bon code même. Des librairies utilisables pour simplifier le développement d’applications qui se conforment aux best practices. Je n’irais pas jusqu’à dire que les travaux présentés dans patterns & practices sont d’abord aisés, les cogitations méthodologiques réclament toujours un minimum d’attention, mais la volonté assumée de joindre la pratique et l’usage à la réflexion rend tout cela accessible à qui se donne un peu de temps pour lire et expérimenter.

Pour ce qui est de Unity, ce bloc se concentre sur la conception d’un conteneur “léger” et extensible permettant de faire de l’injection de dépendances (dependency injection).

De quoi s’agit-il ?

Comme indiqué en introduction de ce billet, tout ce dont je vous parle aujourd’hui tourne autour des mêmes besoins, de concepts proches ou qui se font écho les uns aux autres. L’injection de dépendances est une réponse à une série de problèmes qui se posent lorsqu’on désire séparer proprement des blocs de code tout en évitant de construire une “usine à gaz”.

Séparation de code, M-V-VM, Prism, ce sont autant de caméras placées autour d’une même scène. Des angles de vue différents, des manières d’entrer dans le sujet différentes, mais au final un but qui, s’il n’est pas commun, vise une même finalité. La conception d’applications souples, maintenables et extensibles.

Grâce à Unity vous disposez à la fois d’explications claires et d’une librairie permettant de gérer convenablement les injections de dépendances. Encore une terminologie “savante” pour des choses finalement pas si compliquées que cela. Mais pour en rajouter une couche disons que l’injection de dépendances n’est qu’une façon de gérer l’ “inversion de contrôle”.

Inversion of Control

“Pitié ! Arrêtez-le !” (Jean Peuplus, lecteur parisien)

On peut comprendre ce lecteur. Une telle avalanche ne risque-t-elle pas de tout emporter sur son passage, au risque de rendre ce billet contre-productif ?

La question mérite d’être posée, mais je fais le pari que vous tiendrez jusqu’au bout (qui est proche je vous rassure).

Le problème à résoudre

Pour info : j’utilise ci-après des parties de la documentation de Prism version octobre 2009

Vous avez une classe dont le fonctionnement dépend de services ou de composants dont les implémentations réelles sont spécifiées lors du design de l’application.

image

Les problèmes suivants se posent

  • Pour remplacer ou mettre à jour les dépendances vous devez faire des changements dans le code de la classe (classe A dans le schéma ci-dessus)
  • Les implémentations des services doivent exister et être disponibles à la compilation de la classe
  • La classe est difficile à tester de façon isolée car elle a des références “en dur” vers les services. Cela signifie que ces dépendances ne peuvent être remplacées par des mocks ou des stubs (maquette d’interface ou squelette non fonctionnel de code).
  • La classe contient du code répétitif pour créer, localiser et gérer ses dépendances.

Les conditions qui forcent à utiliser la pattern d’inversion de contrôle

  • Vous voulez découpler vos classes de leurs dépendances de telle façon à ce que ces dernières puissent être remplacées ou mises à jour avec le minimum de changement dans votre code, voire aucune modification.
  • Vous désirez construire vos classes de telle façon à ce qu’elles puissent dépendre d’implémentations inconnues ou indisponibles lors de la compilation.
  • Vous voulez pouvoir tester vos classes de façon isolée, sans faire usage des dépendances.
  • Vous voulez découpler la responsabilité de la localisation et de la gestion des dépendances de vos classes.

La solution

Il faut déléguer la fonction qui sélectionne le type de l’implémentation concrète des classes de services (les dépendances) à un composant ou une source externe à votre code.

Les implémentations

Il y a plusieurs façons d’implémenter la pattern d’inversion de contrôle. Prism en utilise deux qui sont l’Injection de dépendances (Dependency Injection) et le Localisateur de service (Service Locator).

image 

Injection de dépendances

L'injection de dépendances est un mécanisme qui permet d'implanter le principe de l'Inversion de contrôle. Il consiste à créer dynamiquement (injecter) les dépendances entre les différentes classes en s'appuyant généralement sur une description (fichier de configuration). Ainsi les dépendances entre composants logiciels ne sont plus exprimée dans le code de manière statique mais déterminées dynamiquement à l'exécution.

Le localisateur de services

Le localisateur de services est un mécanisme qui recense les dépendances (les services) et qui encapsule la logique permettant de les retrouver. Le localisateur de services n’instancie pas les services, il ne fait que les trouver, généralement à partir d’une clé (qui éviter les références aux classes réelles et permet ainsi de modifier les implémentations réelles). Le localisateur de services propose un procédé d’enregistrement qui liste les services disponibles ainsi qu’un service de recherche utilisé par les classes devant utiliser les dépendances et qui se chargent de les instancier.

Exemples

Même si les choses sont certainement plus claires maintenant (je l’espère en tout cas) il est certain que des exemples de code aideraient à visualiser tout cela. J’en ai bien conscience et j’ai prévu d’illustrer concrètement les principes expliqués dans ce billet. Toutefois en raison de la longueur de chaque exemple (nous parlons ici de techniques de découplement donc de nombreux fichiers et projets pour un seul exemple) il ne me semble pas raisonnable d’aller plus loin immédiatement. Laissons ce billet se terminer, et toutes ces notions tourner dans vos têtes avant de les appliquer !

Conclusion

Une terminologie ésotérique ne cache pas forcément des choses complexes. Le but de ce billet était de vous donner quelques clés pour mieux comprendre un ensemble de notions différentes mais participant toutes à une même finalité.

J’aborderai des exemples sous Silverlight très bientôt. Donc pour en savoir plus :

Stay Tuned !

Prism v2 (guidance and patterns for WPF and Silverlight)

Construire des applications modulaires offre de nombreux avantages : maintenabilité et évolutivité sont les premières qui viennent à l'esprit mais il en existe d'autres comme la meilleure séparation des tâches (travail parallèle d'équipes de développement sur des modules différents) par exemple.

Créer une architecture assurant la modularité d'une application n'est pas chose aisée. Bricoler "sa" solution dans "son" coin donne l'impression de gagner du temps (pas besoin d'apprendre un framework existant) mais montre souvent ses limites et ce, au pire moment, c'est à dire trop tard...

Microsoft ne fait pas que du soft pour micro... Depuis l'avènement de .NET il faut saluer les efforts importants qui sont fournis par MS pour fournir aussi de la matière grise. Labos de recherche, groupes de travail très indépendants, cette nouvelle orientation du management des équipes à permis l'éclosion d'un tas de bonnes idées. Tout ce travail est gracieusement délivré aux communautés de développeurs qui se donnent la peine de s'y intéresser...

Qui plus est, il ne s'agit pas d'élucubrations fumeuses. Les guides de bonnes pratiques, les conseils méthodologiques sont malgré tout le fruit d'un énorme travail collaboratif "au sommet" avec aux commandes des gens comme JD Meier, qui ne sont pas petites pointures !

Pour en revenir aux applications modulaires, il est essentiel de prendre connaissance de la V2 de PRISM, un recueil de codes, de documentations et de bonnes pratiques d'une qualité exceptionnelle.

Prism V2 c'est :

  • Une librairie pour la création d'applications composites
  • Une application de référence comme modèle d'implémentation (gestion de porte feuille boursier)
  • 9 "quick start" pour entrer dans le vif du sujet rapidement
  • 26 "how-to's" pour se former efficacement
  • Une documentation à la fois claire et riche

Prism supporte les applications WPF et Silverlight dans une même logique permettant de partager encore plus de code entre les deux types d'application.

Bref, je vous invite à vous pencher très sérieusement sur Prism si vous ne connaissez pas, pour tout projet d'une certaine envergure cela vous fera gagner beaucoup de temps, de productivité et le tout dans un cadre validé ne risquant pas de vous envoyer au mur.

Télécharger les éléments de Prism v2

Le site de Prism sur CodePlex

Bonne lecture !

Les guides de bonnes pratiques

Unit Testing et Silverlight 2

Les applications Silverlight ont le même besoin que les autres d'être testées ! Et même s'il reste possible de tester de façon séparée tous les objets métiers (en utilisant le Unit Testing de Visual Studio), tester une application Silverlight en cours de fonctionnement ne s'avérait pas tout aussi simple.

Unit Test Framework for Silverlight

Ce Framework est une solution construite par des développeurs pour des développeurs, pour les aider à construire des applications riches et des composants pour Microsoft Silverlight 2. Le Framework est actuellement disponible en tant que binaires téléchargeables à utiliser dans vos propres applications. Microsoft avait d'abord sorti ce Framework avec le code source et les tests unitaires pour les contrôles Silverlight lors de la conférence MIX'08 à Las Vegas.

Compatibilité

Le Framework de tests unitaires est compatible avec Microsoft Silverlight 2. Il est utilisable sous Windows et Mac. Et il tourne sous les navigateurs suivants: Safari, Mozilla Firefox, et Internet Explorer.
Que demander de plus ? !

Simple, puissant et extensible

Le Framework permet :
  • d'exécuter des tests unitaires à l'intérieur du navigateur Web
  • de tester les contrôles riches et l'ensemble de la plate-forme Silverlight
  • de faire des tests asynchrones

 

sample application screenshot

Plus d'information

Téléchargements

Le code source du Framework est maintenant intégré au Silverlight Toolkit.
Aussi: de nouveaux templates à télécharger, et à lire, les breaking changes.

Visual NDepend un outil d'analyse de code original et puissant

A partir d'une certaine taille le code d'une application devient difficile à maintenir même s'il est bien conçu. De même, la maintenance évolutive oblige souvent à mettre les mains dans un code écrit par d'autres (si ce code est assez ancien, on peut s'y perdre même en en étant l'auteur d'ailleurs !). Auditer un code est ainsi un besoin fréquent dans le travail de tous les jours d'un développeur. Si on effectue des missions d'audit ce besoin devient alors impérieux car il est nécessaire d'entrer rapidement dans un code "étranger" et toujours complexe (je n'ai jamais été appelé en audit pour des logiciels de 20 lignes...).

Les outils d'analyse de code sont ainsi des compagnons indispensables. Hélas ils ne sont pas si nombreux que ça et comme tout ce qui touche la qualité, ils sont un peu "oubliés".

Je voulais ainsi vous présenter un excellent outil : Visual NDepend.

NDepend est puissant, il permet de construire et visualiser des comparaisons, d'auditer la qualité du code, et surtout de mieux visualiser la structure d'une application. Le tout quantitavement (métriques), qualitativement (l'information est pertinente) et graphiquement (le logiciel propose de nombreux diagrammes et schémas permettant de visualiser ce qui est invisible en lisant le code source : structures, dépendances, ...).

NDepend ne se limite pas seulement à l'audit de code, c'est aussi un excellent outil de refactoring.

On notera aussi, côté puissance, l'intégration d'un langage d'interrogation, le CQL (Code Query Language), permettant à la façon de SQL de "questionner" un projet et son code comme s'il s'agissait d'une base de données. La comparaison s'arrête là avec SQL car CQL "comprend" le code alors que SQL ne comprend pas le sens des données qu'il manipule. Cette grande différence confère à NDepend une très grande souplesse et beaucoup d'intelligence.

Par exemple il est très simple de faire des requêtes du type "montre moi toutes les méthodes privées dont le nombre de lignes de code est supérieur à 20", très utile pour repérer rapidement dans un projet les lourdeurs ou la nécessité de refactoring. Une telle interrogation se formule en la requête CQL suivante "SELECT METHODS WHERE NbLinesOfCode > 20 AND IsPrivate".
On peut bien entendu créer des requêtes plus sophistiquées comme rechercher toutes les types qui sont une définition de classe et qui implémentent telle ou telle autre interface !

NDepend est ainsi un outil de grande qualité dont on ne peut que conseiller l'utilisation. Réalisé par Patrick Smacchia, un acteur connu de la scène .NET et Microsoft MVP C#, NDepend est vendu 299 euros en licence 1 utilisateur, c'est à dire pas grand chose au regard des immenses services qu'il peut rendre.

Il y a beaucoup de choses à dire sur cet outil et surtout à voir. Le mieux si vous êtes intéressés est de vous rendre sur le site du logiciel www.ndepend.com où vous pourrez visionner de nombreuses petites vidéos qui vaudront mieux que de longs discours.

Bon refactoring !

 

Patterns & Practices : les guides de bonnes pratiques à connaître par coeur !

Dans la jungle du Framework et de tous ses projets satellites qui sortent au rythme d'une rafale d'AK47 comment un pauvre développeur isolé peut-il intégrer et digérer en quelques heures (en plus de son travail quotidien) des centaines, voire des milliers d'années-homme de librairies, technologies, outils et langages produits par Microsoft ?

C'est une véritable question. Dans mon propre travail de conseil je m'oblige à une réserve de 30% de mon temps uniquement dédié à la veille technologique, c'est à dire qu'un tiers de mon temps n'est jamais vendu, je me le réserve pour apprendre, un luxe indispensable mais coûteux en chiffre d'affaire potentiel perdu. De plus c'est un mode de fonctionnement que seul un dirigeant d'entreprise ou un indépendant peut s'offrir. Et malgré ce privilège tous les jours je mesure l'étendue de mon ignorance sur certains aspects du Framework avec la désagréable impression que plus je rame plus la côte s'éloigne ... Je suis certain de n'être pas le seul à ressentir cette sensation !

Il y a ceux qui ont d'emblée choisi de se spécialiser. Ils connaissent tout ou presque de Windows Forms, de WPF, ou de Silverlight mais ignore tout des dizaines d'autres éléments du Framework. Impasse sur ASP.NET, Ajax, MVC, Entity Framework, etc, etc. Chacun fait alors son petit marché n'ayant au final qu'une vue très restreinte sur le Framework, et, de fait, loupant souvent d'excellentes choses. Hélas une journée n'a que 24h, et pour avoir essayer par tous les moyens de contourner sans succès cette terrible réalité, je peux affirmer que travailler, même beaucoup, même trop, n'est pas forcément la solution. Seule Zenon d'Elée arrivait dans son paradoxe à faire gagner une tortue face à Achille ! Quand l'adversaire est en supériorité, la force brute est inutile, il faut ruser...

Microsoft a conscience de ce problème. Qu'il s'agisse des petites vidéo "how do I", des multiples conférences qui se tiennent régulièrement, de la documentation très fournie de MSDN, de l'excellent magazine MSDN toujours riche d'articles de haute tenue technique, et de bien d'autres actions en faveur de la diffusion de la connaissance sur ses produits, Microsoft fait beaucoup pour nous aider à appréhender l'étendue de sa gamme.

Si cet effort louable est important, on peut toujours en réclamer plus. Par exemple une certaine décentralisation de toutes ces informations fait que peu de gens connaissent tous les "points d'entrée" utiles de ces informations. Gageons que Microsoft en a aussi conscience et que des efforts supplémentaires seront réalisés pour aider le développeur "à s'y retrouver dans les informations qui permettent de s'y retrouver" dans les produits...

Patterns & Practices

Tout cela pour vous parler aujourd'hui des Patterns & Practices. Il s'agit d'un ensemble de recommandations et de code mis à disposition gratuitement sur CodePlex. Bien connaître ces "patrons et pratiques" peut vous aider à mieux tirer partie du Framework sans pour autant y consacrer vos nuits.

Pour obtenir la liste de tous les projets gravitant autour de ce concept de "patterns & practices" allez sur CodePlex et chercher cette expression. Vous pouvez aussi directement accéder à tous les projets pertinents par le tag du même nom (colonne de droite sur CodePlex).

Les projets clé

Il est bien entendu très difficile de créer un ordre de priorité dans tous les projets "patterns & practices", selon ce que vous développez, l'urgence de regarder tel ou tel projet sera plus ou moins grande. Mais je vais tenter une petite sélection de ceux qui, à mon sens, sont à connaître absolument.

App Arch Guide 2.0 Knowledge base

http://www.codeplex.com/AppArch 

Ce projet initié par JD Meier, Jason Taylor et Prashant Bansode regroupe de nombreux documents et vidéos dont le but est d'expliquer "How to put the legos together", ce dont je parlais plus haut : savoir comment utiliser correctement toutes les briques de constructions du Framework pour en faire quelque chose.

The purpose of the Application Architecture Guide 2.0 is to improve your effectiveness building applications on the Microsoft platform. The primary audience is solution architects and developer leads. The guide will provide design-level guidance for the architecture and design of applications built on the .NET Framework. It focuses on the most common types of applications, partitioning application functionality into layers, components, and services, and walks through their key design characteristics.

Ce projet est certainement le premier point d'entrée que vous devez connaître. Sa vision globale de l'architecture des applications vous aidera à prendre de meilleures décisions.

Application Architecture Guide 2.0 (le livre)

http://www.codeplex.com/AppArchGuide

Ce guide fournit des guides architecturaux pour la création d'applications .NET. Les principaux types d'applications sont étudiés et de nombreuses solutions sont proposées.

Le livre complète la "App Arch Guide 2.0 Knowledge base" décrite ci-dessus.

Enterprise Library

http://www.codeplex.com/entlib

http://msdn.microsoft.com/fr-fr/library/cc467894(en-us).aspx

L'Enterprise Library est une collection de blocs applicatifs qui ont été conçus pour assister le développeur dans son travail. Il s'agit de code mais d'une certaine façon ce code constitue un guide des bonnes pratiques.

Le code source est fourni avec une documentation. EL peut être utilisé tel quel ou bien modifié ou étendu.

Constitué de plusieurs "blocs", EL est une vraie mine d'or. Gestion du caching, cryptographie, accès aux données, gestion des exceptions, logging, sécurité, des solutions pratiques, génériques et éprouvées sont apportées à chacun de ses sujets.

Un "must have" donc. (et surtout un "must understand" !).

Web Client Software Factory

http://www.codeplex.com/websf

le WCSF fournit un ensemble de directives pour les architectes et les développeurs d'applications Web. La factory inclue des exemples, du code réutilisable et un ensemble de guidlines pour automatiser les tâches clé du développement sous Visual Studio. Pour ceux qui connaissaient, WCSF remplace UIP (User Interface Process Application Block). WCSF supporte bien entendu les nouveautés du Framework comme ASP.NET, Ajax ou Workflow Foundation.

A connaître dès lors qu'on veut développer des applications Web...

Composite WPF and Silverlight

http://www.codeplex.com/CompositeWPF

Ce bloc des patterns & practices fait partie du top 5 à connaître et maîtriser. Il intègre code et guidelines nécessaires à la mise en place d'architectures suivant les best practices pour les projets de type WPF et Silverlight. Tout est bon, il faut absolument le connaître !

A noter: ce projet est aussi connu sous le nom de "Prism" (info primordiale surtout pour faire le cador à la machine à café :-) ).

Smart Client Guidance

http://www.codeplex.com/smartclient

http://msdn.microsoft.com/en-us/library/aa480482.aspx

Le Smart Client Software Factory (SCSF) est une autre guide essentiel. Guidelines et code forment un ensemble de composants réutilisables sous Windows Forms autant que WPF ou ASP.NET pour mettre en place une architecture de client intelligents composites.

Je n'ai pas eu encore le temps de plonger dans ce guide, mais du survol que j'en ai fait, il faut très certainement le regarder de plus près, les solutions proposées semblent tout aussi indispensables à connaître que les autres guides de la série "patterns & practices".

Unity

http://www.codeplex.com/unity

Encore un guide que je n'ai pas eu le temps de lire... Les longues soirées d'hiver sont un mythe : il fait nuit plus tôt mais les journées ne comptent toujours pas plus de 24h, cette expression est donc une escroquerie ! :-)

The Unity Application Block (Unity) is a lightweight extensible dependency injection container with support for constructor, property, and method call injection.

Dit comme ça, c'est un peu confus... pour tout savoir le mieux c'est de lire (le conseil vaut pour moi aussi) !

WCF Security Guidance

http://www.codeplex.com/WCFSecurity

La mise en place de services via WCF peut se faire de façon très naïve... ou de façon professionnelle, c'est à dire en gérant correctement la sécurité ! Ce guide fait le tour de la question et propose des guidelines autant que du code pour mieux sécuriser les applications communiquantes et gérer correctement les authentifications, les autorisations et toutes ces choses indispensables pour des applications mises en production.

Web Service Software Factory

http://www.codeplex.com/servicefactory

Il s'agit d'une collection d'outils, de patterns, de code source et de guidelines destinés à vous aider à construire des Web services WCF et ASMX rapidement mais en garantissant la meilleure fiabilité possible.

Indispensable comme le reste...

Guidance Explorer

http://www.codeplex.com/guidanceExplorer

Voici peut être un moyen de s'y retrouver un peu mieux parmi toutes les guidelines ! le Guidance Explorer, comme son nom l'indique, est un outil d'exploration des guidelines. Une fois installé il se met à jour via le Web.

Centralisant bon nombre de guides et simplifiant l'accès à l'information, Guidance Explorer est l'une des premières choses à installer à côté de Visual Studio !

MS Health Common User Interface

http://www.codeplex.com/mscui

C'est un peu l'ovni de cette liste et même un vrai ovni à part entière dans tout le Framework et les guidelines. On se demande pourquoi Microsoft a investi dans cette branche très spécialisée plutôt qu'une autre. Le MSCUI est en effet un ensemble de guidelines, de code et de composants permettant de réaliser des application orientées médical. Composants WCF, Silverlight ou autres, c'est un ensemble incroyable quantitativement et qualitativement. Ayant été l'un des pioniers de l'informatique médicale en France avec la gamme de logiciel Hippocrate je connais particulièrement bien la question et j'ai été bluffé par ce que propose MS avec MSCUI. Avec cet outil un bon développeur peut assez rapidement mettre en place des solutions tout à fait honorables capables de concurrencer les principaux logiciels médicaux du marché...

Si le médical n'est pas votre branche, MSCUI ne vous intéressera que peu dans la pratique, mais regardez tout de même comment cela est fait et comment les composants se présentent, ergonomiquement et fonctionnellement c'est un beau travail.

Conclusion

Si ce tour d'horizon n'est pas exhaustif il contient malgré tout le top des guidelines et outils à connaître pour développer sereinement des solutions basées sur des patterns éprouvées. Ne pas réinventer la roue, mettre rapidement en place la bonne architecture d'un projet c'est déjà s'assurer à 50% de sa réussite.

Si les soirées d'hiver ne comportent pas plus d'heures que celles d'été, la froidure incite moins à sortir et à flâner qu'en août, profitez-en pour rester au chaud en vous plongeant dans les Patterns & Practices !

N'oubliez pas ce vieux proverbe qui nous vient du fond des âges :

"L'hiver, qui bouquine Patterns & Practice,
 l'été, produit du code qui glisse !"

Et Stay Tuned !

MEF - Managed Extensibility Framework - De la magie est des plugins !

Une gestion de plugin simplifiée 

Actuellement encore en preview mais très utilisable depuis la Preview 2 du mois d’octobre, MEF est un nouveau procédé de gestion des plugins pour le Framework .NET.

Projet Open Source se trouvant sur CodePlex (http://www.codeplex.com/MEF) MEF facilite l’implémentation des addins (ou plugins) en automatisant la liaison entre les propriétés du programme qui importe des valeurs et les addins qui exportent les valeurs. Sachant que tout module peut être importateur et exportateur à la fois, permettant des chaînes de addins eux-mêmes supportant des addins…

MEF et les autres

Microsoft a intégré dans le Framework 3.5 une gestion des plugins  qui se base sur l’espace de nom System.Addin. L’approche est différente de MEF et le choix n’est pas évident entre ces deux solutions.  D’autant qu’il en existe une troisième ! En effet, Microsoft a aussi publié le Composite Application Guidance for WPF, spécifiquement dédié aux applications de ce type donc, dont la dernière version date de juin…

MEF est utilisable aussi sous WPF, même sous Silverlight mais je n’ai pas encore testé cet aspect là.

Comment choisir ?

Personnellement l’approche de MEF me convient très bien, c’est assez simple et cela répond aux besoins d’une gestion de plugins (ou addins). En ces temps d’avalanche de technologies toutes plus alléchantes les unes que les autres chez Microsoft il est vrai que je suis assez tenté par la simplicité de MEF qui évite de trop s’encombrer les neurones déjà bien saturés ! Simple et complet, je préfère donc MEF, mais je suis convaincu que dans certains cas la solution spécifique à WPF est mieux adaptée ou que System.Addin apporte certains petits plus (sécurité par exemple). J’avoue bien humblement que je n’ai pas encore trouvé le temps de tester à fond System.Addin ni la solution WPF. A vous de voir donc, et le mieux c’est de regarder de près en testant chaque approche. Ici je vais vous parler de MEF, pour les autres solutions suivez les liens suivants :

Composite Applicationn Guidance for WPF (http://msdn.microsoft.com/en-us/library/cc707819.aspx)

Pour System.Addin je vous conseille les 12 billets de Jason He qui sont plus parlant que l’aride documentation de l’espace de nom sur MSDN. (http://blogs.msdn.com/zifengh/archive/2007/01/04/addin-model-in-paint-net-1-introduction.aspx)

MEF – Le principe

Le but est de simplifier l’écriture d’applications dites  extensibles. MEF automatise la découverte des modules (les plugins) ainsi que la composition des valeurs, c'est-à-dire un lien automatique entre les valeurs exportées et le module importateur. De prime abord c’est pas forcément très clair, mais le code qui va venir va vous éclairez (je l’espère en tout cas !). En première approximation disons que la composition dans MEF est une sorte de Databinding qui relie une propriété déclarée dans l’importateur à une ou plusieurs valeurs du ou des modules exportateurs (les plugins).

MEF – Les avantages

MEF est assez simple, je l’ai dit, et c’est un gros avantage (mais pas simpliste, nuance). Il est Open Source c’est un plus. Mais surtout MEF évite de réinventer la poudre à chaque fois qu’on désire implémenter une gestion de plugins. Et toute application moderne se doit d’être extensible ! Qu’il s’agisse d’applications à usage interne ou bien de logiciels d’éditeur, c’est souvent l’extensibilité et les plugins qui font le succès d’une application, ou aide grandement à celui-ci. Disposer d’une solution fiable pour résoudre ce problème d’architecture très courant est donc l’avantage principal de MEF.

Les extensions créées avec MEF peuvent être partagées par plusieurs applications, elles peuvent elles-mêmes utiliser des extensions et MEF saura les charger dans le bon ordre automatiquement.

MEF propose un ensemble de service de découverte simplifiant la localisation et le chargement des extensions. On trouve aussi un système de lazzy loading et un mécanisme de métadonnées riches permettant aux plugins d’informer l’hôte sur sa nature ou transmettre des données complémentaires.

Un Exemple ! Un Exemple !

Bon, je ne vais pas refaire la doc de MEF, qui n’existe pas d’ailleurs (enfin si mais c’est encore très partiel), et pour illustrer le propos je vais expliquer le fonctionnement de MEF au travers d’un exemple le plus simple possible (ce billet s’annonce déjà bien long !).

Installer MEF

Avant toute chose, et pour faire tourner l’exemple (et vous amuser avec MEF), il faut que vous installiez MEF. Rassurez-vous, c’est très simple, sur le site de MEF (indiqué en introduction) vous trouverez dans l’onglet Releases le dernier zip à télécharger. Il suffit de prendre le contenu du zip et de le copier quelque part sur votre disque. C’est tout.  Le source est fourni ainsi que la lib compilée. Il suffit dans une application d’ajouter une référence à la DLL « System.ComponentModel.Composition.dll » se trouvant le répertoire /Bin du fichier téléchargé et l’affaire est jouée. Un Using de System.ComponentModel.Composition sera nécessaire dans l’application hôte ainsi que dans les applications fournissant un service (les DLL des plugins).

L’application exemple

Je vais faire très simple comme annoncé : prenons une application console. Cette application doit appliquer des calculs à des valeurs. Tous les algorithmes de calcul seront des plugins. Algorithme est un bien grand mot puisque dans cet exemple j’implémenterai l’addition et la multiplication. Dans la réalité les plugins découverts seraient par exemple ajoutés à un menu ou une toolbar. Ici nous nous contenterons de les lister à la console et de les appeler sur des valeurs codées en dur (dans une vraie calculette les valeurs seraient saisies par l’utilisateur).

Le contrat

Le plus intelligent pour une gestion de plugin est bien entendu d’avoir une ou plusieurs interfaces décrivant ce que sait faire un plugin. C’est le contrat (ou les contrats) entre l’hôte et ses plugins.

Ainsi nous allons ajouter à notre solution un projet de type DLL pour décrire cette interface. Cela se fait dans un projet séparé puisque l’interface doit être techniquement connu à la fois de l’hôte et des plugins et qu’il faut éviter à tout prix l’existence de dépendances entre ces deux niveaux de l’architecture. De plus l’interface peut ainsi être diffusée avec l’exécutable pour que des tiers puissent écrire des plugins.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace MEFInterface
{
    public interface ICompute
    {
        double Compute(double x, double y);
        string OperationName { get; }
    }
}

Le code ci-dessus est très simple. Comme on le voit ce projet DLL ne fait aucune référence à MEF ni à notre application ni à rien d’autre d’ailleurs (en dehors du Framework). L'interface ICompute expose une méthode Compute() et une propriété de type chaîne OperationName. Compute réalise le calcul sur les deux valeurs passées en paramètre et OperationName retourne le nom de l'algorithme pour que l'hôte puisse éventuellement fabriquer un menu listant tous les plugins installés.

Les plugins

Cela peut sembler moins naturel de commencer par les plugins que par l’application hôte mais je pense que vous comprendrez mieux dans ce sens là. Donc comment implémenter un plugin ?

Nous ajoutons à notre solution un nouveau projet de type librairie de classes qui sera faite d’une seule classe implémentant l’interface que nous venons de voir. Prenons l’exemple de la DLL de l’addition, sachant que celle gérant la multiplication est identique (au calcul près) et que nous pourrions créer ainsi une ribambelle de projets implémentant autant d’algorithmes de calculs que nous en voulons.

Le projet ModuleAddition contient ainsi un fichier Addition.cs, fichier contenant le code suivant :

(code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; // MEF
using MEFInterface; // interface des plugins
 
namespace ModuleAddition
{
 
    [Export(typeof(ICompute))] // exporter la classe vue sous l'angle de l'interface partagée
    public class Addition : ICompute
    {
        // Réalise l'addition de deux doubles.
        public double Compute(double x, double y)
        {
            return x + y;
        }
 
        public string OperationName { get { return "Addition"; } }
 
    }
}

Ce code est redoutablement simple et n’a pas grand-chose de spécial. Il implémente l’interface que nous avons définie (d’où le using à MEFInterface, nom de notre projet interface, rien à voir avec un module de MEF donc, et la référence ajoutée cette DLL).

Ce qui est spécifique à MEF se résume à deux choses : d’une part le using de System.ComponentModel.Composition qui implique l’ajout dans les références de la DLL de MEF et d’autre part l’attribut Export qui décore la classe Addition (implémentant l’interface ICompute que nous avons créée).

L’attribut Export possède des variantes, ici l’usage que nous en faisons indique tout simplement à MEF que la classe en question est un fournisseur de service plugin et qu’il faut la voir non pas comme une classe mais comme l’interface ICompute. C’est un choix, il peut y en avoir d’autres, mais concernant une gestion de plugin cette approche m’a semblé préférable.

Concernant le code de la classe Addition on voit qu’elle implémente les éléments de notre interface donc la méthode Compute qui retournera ici l’addition des deux paramètres. Dans la classe Multiplication (l’autre plugin non visible ici) c’est la même chose, sauf que Compute calcule la multiplication. La propriété OperationName de l’interface est implémentée en retournant le nom de l’algorithme de calcul exposé par le plugin. Ce nom sera utile à l’hôte pour créer un bouton, une entrée de menu, etc.

On notera que MEF supporte la notion de métadonnées. Il existe ainsi des attributs permettant de décorer une classe en ajoutant autant de couple clé / valeur qu’ont le souhaite. Le nom du plugin, sa version, le nom de l’auteur et bien d’autres données peuvent ainsi être transmis à l’hôte via ce mécanisme que je ne démontre pas ce billet.

Pour simplifier les tests notons que j’ai modifié les propriétés du projet de chaque plugin pour qu’en mode debug les DLL soient directement placées dans le répertoire de debug de l’application hôte. Jai choisi ici aussi la simplicité : les plugins doivent être dans le répertoire de l’exécutable. Bien entendu dans la réalité vous pouvez décider de créer un sous-répertoire à votre application pour les plugins, ce qui est même plus propre.

L’hôte

Le voici ! Application en mode console (quel mode merveilleux pour les tests !), son fonctionnement est rudimentaire : nous voulons que l’application découvre grâce à MEF tous les plugins installés et que pour chacun elle affiche le nom de l’opération et effectue un appel au calcul correspondant. Les valeurs servant à ces derniers sont figées dans le programme, pas question d’ajouter une gestion de saisie utilisateur dans cette démo.

Les using et références

Pour fonctionner le programme doit faire référence à la fois à la MEF et au projet interface (aux projets interfaces si nous supportions plusieurs types de plugins par exemple).

Ces références trouvent leur pendant dans les using :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; // MEF
using MEFInterface;
using System.IO; // interface des addins

La section Main

Elle aura pour rôle de créer une instance de l’objet programme et d’appeler sa méthode Run (nom arbitraire bien entendu). Rien de spécial à comprendre donc.

static void Main(string[] args)
{
   new Program().Run();
}

La propriété importée

Nous avons vu que les plugins exportent une (ou plusieurs) valeur(s), dans notre exemple il s’agit d’instances de classes supportant l’interface ICompute. Du côté de l’hôte il faut « quelque chose » pour importer ces valeurs.

C’est le rôle de la propriété  Operations dans notre code :

[Import] // attribut marquant une propriété importée depuis les addins découverts
        public IEnumerable<ICompute> Operations { get; set; }

Comme vous le voyez cette propriété est une liste. Cela s’explique par le fait que nous supportons plusieurs plugins à la fois. Dans le cas contraire (un seul plugin) la propriété aurait été directement du type de l’interface ICompute. Un seul plugin peut sembler étrange mais cela peut correspondre à une partie spécifique de votre application que vous désirez pouvoir personnaliser à tout moment en fournissant simplement une nouvelle DLL qui écrasera celle installée chez les utilisateurs. Un mode d’utilisation à ne pas négliger… Mais ici nous supportons plusieurs plugins à la fois et notre propriété est ainsi une liste.  Autre spécificité liée à la MEF, la propriété est décorée par l’attribut Import qui indique à MEF qu’il devra faire le binding entre la propriété et les plugins supportant le type de celle-ci.

Le code du Run

L’application se déroule ici. Nous commençons par appeler une méthode Compose() dont le rôle sera justement de mettre en route toute la magie de MEF. Nous verrons cela plus bas. Ensuite nous ne faisons que boucler sur la collection représentée par notre propriété comme si nous y avions déjà placé du contenu et nous l’utilisons « normalement » c'est-à-dire comme si MEF n’existait pas. Rien de bien sorcier là non plus, un foreach énumère toutes les entrées (des instances vues comme des interfaces ICompute) et utilise les méthodes et les propriétés accessibles (le nom du plugin et son unique méthode Compute).

private void Run()
{
    Compose();
    Console.WriteLine("Operation Addins detected (test on x=5 and y=6) :");
    foreach (var operation in Operations)
    {
        Console.WriteLine(operation.OperationName+" : "+operation.Compute(5,6));
    }
    
    Console.ReadLine();
}

Comme vous le constatez, il n’y aurait pas MEF que nous aurions écrit le même code, sauf que nous trouverions quelque part, à la place de l’appel à Compose que nous allons voir maintenant, un code qui aurait « rempli » la propriété Operations en créant des instances de classes supportant ICompute.

Le code de Compose

Ecrire un bout de code qui créée des instances de classes supportant ICompute et remplir la liste Operations (la propriété liste de notre application), c’est ce que fait la méthode Compose. Mais c'est en réalité c’est MEF qui va le faire pour nous, et mieux encore, il va aller chercher tout ça dans des DLL de plugins.

Regardons le code de Compose :

private void Compose()
{
    // création du catalogue. Les addins sont dans le répertoire de l'exe
    var catalog = new DirectoryPartCatalog(System.Reflection.Assembly.GetExecutingAssembly().Location);
    // créé le conteneur
    var container = new CompositionContainer(catalog.CreateResolver());
    // ajoute this pour qu'il puisse être lié via ses attributs 'import'
    container.AddPart(this); 
    // réalise la composition (connexion de tous les exports à tous les imports)
    container.Compose();
}

4 lignes. 4 lignes seulement pour : 

  1. créer un catalogue de plugins d’après un répertoire disque,
  2. créer un conteneur qui est le point de fusion où se rencontre les exportateurs et les importateurs,
  3. ajouter l’instance de notre application au conteneur (puisqu’elle est consommatrice via sa propriété marquée Import), d) demander au conteneur d’effectuer le binding entre tous les exportateurs et tous les importateurs. Incroyable non ?

Et c’est tout !

Ce qui va se passer au lancement de l’application est assez simple : MEF va balayer tout le répertoire indiqué dans le catalogue (qui peut contenir plusieurs répertoires), chercher les DLL et tester pour chacune celles qui exportent des éléments compatibles avec les importations. Qu’il s’agisse ici de notre application (consommatrice via son Import) ou même des plugins entre eux qui peuvent aussi avoir des relations consommateur / fournisseur.

C’est là que réside la magie de MEF qui va ensuite faire le nécessaire pour renseigner automatiquement toutes les propriétés ayant l’attribut Import.  Dans notre cas MEF va détecter que deux DLL sont compatibles avec l’Import de notre application. Il va créer des instances des classes supportant l’interface ICompute, en faire une liste qui sera placée dans la propriété Operations automatiquement.

Il ne reste plus à notre application qu’à utiliser la propriété Operations comme n’importe quelle autre propriété, sauf qu’ici son contenu a été créé par MEF automatiquement.

Conclusion

Simple et un peu magique, c’est ça MEF.

MEF règle un problème récurrent d’architecture, l’extensibilité, de façon simple et élégante. Bien entendu MEF permet de faire plus choses que ce que j’en montre ici. A vous de le découvrir en le téléchargeant et en étudiant les exemples et le début de documentation fourni !

Le code du projet VS2008 : MEFExample.zip (16,08 kb)

Contourner le problème de l'appel d'une méthode virtuelle dans un constructeur

Ce problème est source de bogues bien sournois. J'ai déjà eu l'occasion de vous en parler dans un billet cet été (Appel d'un membre virtuel dans le constructeur ou "quand C# devient vicieux". A lire absolument...), la conclusion était qu'il ne faut tout simplement pas utiliser cette construction dangereuse. Je proposais alors de déplacer toutes les initialisations dans le constructeur de la classe parent, mais bien entendu cela n'est pas applicable tout le temps (sinon à quoi servirait l'héritage).

Dès lors comment proposer une méthode fiable et systématique pour contourner le problème proprement ?

Rappel

Je renvoie le lecteur au billet que j'évoque en introduction pour éviter de me répéter, le problème posé y est clairement démontré. Pour les paresseux du clic, voici en gros le résumé de la situation : L'appel d'une méthode virtuelle dans le constructeur d'une classe est fortement déconseillé. La raison : lorsque qu'une instance d'une classe dérivée est créée elle commence par appeler le constructeur de son parent (et ainsi de suite en cascade remontante). Si ce constructeur parent appelle une méthode virtuelle overridée dans la classe enfant, le problème est que l'instance enfant elle-même n'est pas encore initialisée, l'initialisation se trouvant encore dans le code du constructeur parent. Et cela, comme vous pouvez l'imaginer, ça sent le bug !

Une première solution

La seule et unique solution propre est donc de s'interdire d'appeler des méthodes virtuelles dans un constructeur. Et je serai même plus extrémiste : il faut s'interdire d'appeler toute méthode dans le constructeur d'une classe, tout simplement parce qu'une méthode non virtuelle, allez savoir, peut, au gréé des changements d'un code, devenir virtuelle un jour. Ce n'est pas quelque chose de souhaitable d'un pur point de vue méthodologique, mais nous savons tous qu'entre la théorie et la pratique il y a un monde...

Tout cela est bien joli mais s'il y a des appels à des méthodes c'est qu'elles servent à quelque chose, s'en passer totalement semble pour le coup tellement extrême qu'on se demande si ça vaut encore le coup de développper ! Bien entendu il existe une façon de contourner le problème : il suffit de créer une méthode publique "Init()" qui elle peut faire ce qu'elle veut. Charge à celui qui créé l'instance d'appeler dans la foulée cette dernière pour compléter l'initialisation de l'objet.

Le code suivant montre une telle construction :

 // Classe Parent
    public class Parent2
    {
        public Parent2(int valeur)
        {
            // MethodeVirtuelle();
        }
 
        public virtual void Init()
        {
            MethodeVirtuelle();
        }
 
        public virtual void MethodeVirtuelle()
        { }
    }
 
    // Classe dérivée
    public class Enfant2 : Parent2
    {
        private int val;
 
        public Enfant2(int valeur)
            : base(valeur)
        {
            val = valeur;
        }
 
        public override void MethodeVirtuelle()
        {
            Console.WriteLine("Classe Enfant2. champ val = " + val);
        }
    }

La méthode virtuelle est appelée dans Init() et le constructeur de la classe de base n'appelle plus aucune méthode.

C'est bien. Mais cela complique un peu l'utilisation des classes. En effet, désormais, pour créer une instance de la classe Enfant2 il faut procéder comme suit :

 // Méthode 2 : avec init séparé
 var enfant2 = new Enfant2(10);
 enfant2.Init(); // affichera 10

Et là, même si nous avons réglé un problème de conception essentiel, côté pratique nous sommes loin du compte ! Le pire c'est bien entendu que nous obligeons les utilisateurs de la classe Enfant2 à "penser à appeler Init()". Ce n'est pas tant l'appel à Init() qui est gênant que le fait qu'il faut penser à le faire ... Et nous savons tous que plus il y a de détails de ce genre à se souvenir pour faire marcher un code, plus le risque de bug augmente.

Conceptuellement, c'est propre, au niveau design c'est à fuir...

Faut-il donc choisir entre peste et choléra sans aucun espoir de se sortir de cette triste alternative ? Non. Nous pouvons faire un peu mieux et rendre tout cela transparent notamment en transférant à la classe enfant la responsabilité de s'initialiser correctement sans que l'utilisateur de cette classe ne soit obligé de penser à quoi que ce soit.

La méthode de la Factory

Il faut absolument utiliser la méthode de l'init séparé, cela est incontournable. Mais il faut tout aussi fermement éviter de rendre l'utilisation de la classe source de bugs. Voici nos contraintes, il va falloir faire avec.

La solution consiste à modifier légèrement l'approche. Nous allons fournir une méthode de classe (méthode statique) permettant de créer des instances de la classe Enfant2, charge à cette méthode appartenant à Enfant2 de faire l'intialisation correctement. Et pour éviter toute "bavure" nous allons cacher le constructeur de Enfant2. Dès lors nous aurons mis en place une Factory (très simple) capable de fabriquer des instances de Enfant2 correctement initialisées, en une seule opération et dans le respect du non appel des méthodes virtuelles dans les constructeurs... ouf !

C'est cette solution que montre le code qui suit (Parent3 et Enfant3 étant les nouvelles classes) :

    // Classe Parent
    public class Parent3
    {
        public Parent3(int valeur)
        {
            // MethodeVirtuelle();
        }
 
        public virtual void Init()
        {
            MethodeVirtuelle();
        }
 
        public virtual void MethodeVirtuelle()
        { }
    }
 
    // Classe dérivée
    public class Enfant3 : Parent3
    {
        private int val;
 
        public static Enfant3 CreerInstance(int valeur)
        {
            var enfant3 = new Enfant3(valeur);
            enfant3.Init();
            return enfant3;
        }
 
        protected Enfant3(int valeur)
            : base(valeur)
        {
            val = valeur;
        }
 
        public override void MethodeVirtuelle()
        {
            Console.WriteLine("Classe Enfant3. champ val = " + val);
        }
    }

La création d'une instance de Enfant3 s'effectue dès lors comme suit :

 var enfant3 = Enfant3.CreerInstance(10);

C'est simple, sans risque d'erreur (impossible de créer une instance autrement), et nous respectons l'interdiction des appels virtuels dans le constructeur sans nous priver des méthodes virtuelles lors de l'initialisation d'un objet. De plus la responsabilité de la totalité de l'action est transférée à la classe enfant ce qui centralise toute la connaissance de cette dernière en un seul point.

Dans une grosse librairie de code on peut se permettre de déconnecter la Factory des classes en proposant directement une ou plusieurs abstraites qui sont les seuls points d'accès pour créer des instances. Toutefois je vous conseille de laisser malgré tout les Factory "locales" dans chaque classe. Cela évite d'éparpiller le code et si un jour une classe enfant est modifiée au point que son initialisation le soit aussi, il n'y aura pas à penser à faire des vérifications dans le code de la Factory séparée. De fait une Factory centrale ne peut être vue que comme un moyen de regrouper les Factories locales, sans pour autant se passer de ces dernières ou en modifier le rôle.

Conclusion

Peut-on aller encore plus loin ? Peut-on procéder d'une autre façon pour satisfaire toutes les exigences de la situation ? Je ne doute pas qu'une autre voie puisse exister, pourquoi pas plus élégante. Encore faut-il la découvrir. C'est comme en montagne, une fois qu'une voie a été découverte pour atteindre le sommet plus facilement ça semble une évidence, mais combien ont du renoncer au sommet avant que le découvreur de la fameuse voie ne trace le chemin ?

Saurez-vous être ce premier de cordée génial et découvrir une voie alternative à la solution de la Factory ? Si tel est le cas, n'oubliez pas de laisser un commentaire !

Dans tous les cas : Stay Tuned !

Et pour jouer avec le code, le projet de test VS 2008 : VirtualInCtor.zip (5,99 kb)

La guerre des clones n'aura pas lieu ! ... Si vous possédez Clone Detective !

Clone Detective pour Visual Studio est un outil de debug un peu particulier puisqu'il ne cherche pas les bugs mais les redondances de code.

La redondance de code est un ennemi sournois... Le code dupliqué est bien souvent la porte ouverte aux inconsistances et aux regressions lors de mises à jour correctives ou évolutives. En effet, si un bug apparaît un jour dans une séquence mais qu'il n'a pas encore été repéré dans une autre fonction qui utilise pourtant un code similaire, la mise à jour ne concernera que la séquence incriminée. Un jour où l'autre la partie codée de façon similaire plantera aussi pour les mêmes raisons. Elle ne sera d'ailleurs peut être pas corrigée de la même façon ni par la même personne... Inconsistance. Coûts de maintenance inutiles. Les défauts de la redondance de code ne manque donc pas.

D'ailleurs un outil capable de retrouver ces fameux clones est un excellent assistant pour un auditeur... La présence des clones trahit non pas celle de Palpatine ou du comte Doku mais bien d'un code for mal refactoré, donc pauvre et qui laissera par force voir d'autres faiblesses !

Précisons que Clone Detective cherche les "clones", pas seulement le code purement redondant de type copier/coller. Il analyse le code en supprimant les commentaires, les espaces, les noms de variables etc, afin d'obtenir un code de référence le plus générique possible avant d'y chercher les clones. Les clones formes des classes de code équivalent, l'un pourrait remplacer l'autre sans problème, à la présentation et aux noms de variables près.

Il s'agit donc bien d'une recherche intelligente et non simplement d'une recherche de "doublons". Mais la lecture de la documentation de CD vous en dira bien plus que ces quelques lignes.

Donc pour se prémunir des dommages causés par les clones, et si on ne connait pas le numéro de portable de Yoda, le mieux est encore de télécharger Clone Detective. Bonne nouvelle il n'habite pas une galaxie lointaire, il est sur CodePlex et donc gratuit avec le code source pour les curieux ! Mieux, C.D. s'insère dans VS 2008 (voir / autres fenêtres, pour afficher celles de C.D. une fois installé). Vraiment un bel add-in dont il serait bête de se priver !

Pour accéder à la page de chargement, cliquez simplement sur le logo de Clone Detective inséré plus haut dans le corps de ce billet.

Que la force soit avec vous !

(et Stay Tuned !)