Contrôles manquants en WPF

Je viens de finir un bon bouquin de base sur WPF : Pro WPF in C# 2008, de Matthew MacDonald (Editions Apress. ISBN-10: 1-59059-955-1. ISBN-13: 978-1-59059-955-6), et les pages 904 et 905 ont retenu toute mon attention. Elles listent les contrôles ou fonctionnalités manquantes en WPF par rapport à WinForms, et expliquent ce qu’on peut avoir en équivalence.

Ce genre de liste est évidemment très intéressante pour un architecte logiciel, car c’est de l’information concentrée sur les limites d’une migration de WinForms à WPF. Par contre, c’est sur la version 3.5 de .NET, et je n’ai pas réussi à retrouver cette information mise à jour pour .NET 4.0. Du coup, je m’y mets… Par contre, vu que je débute en WPF, si vous avez des informations supplémentaires, ça serait sympa de mettre un petit commentaire, car je vais laisser pas mal de rubriques à vide.

LinkLabel

Utiliser plutôt un Hyperlink dans un TextBlock. Pas de changement évidemment sur la version .NET 4.0. Personnellement, je ne pense pas que c’était un manque, mais plutôt une modification bienvenue, car le contrôle LinkLabel en WinForms était vraiment bizarre. Par exemple, pourquoi avoir un LinkArea permettant de délimiter le lien, alors que conceptuellement, les morceaux de texte n’en faisant plus partie devrait être des labels ? Si on a besoin de modifier le texte pour des questions de ressources, on se retrouvait avec des mots anglais découpés en fonction de la taille des mots français !

MaskedTextBox

Le livre propose de créer son propre composant en utilisant System.ComponentModel.MaskedTextProvider. Du coup, je me suis intéressé à cette classe. Il s’agit en fait d’un formateur fonctionnant avec un masque, mais sans retour graphique. Du coup, l’intégration à une zone de texte est relativement simple, et surtout, elle peut être réalisée sur n’importe quel autre contrôle. Cette URL est particulièrement détaillée.

Il existe peut-être des contrôles commerciaux qui reproduisent un MaskedTextBox en WPF, mais personnellement, je pense qu’il vaut mieux continuer à utiliser la solution du bouquin, car si un jour vous avez besoin de valider des données en provenance d’un autre type de contrôle, ou même d’incorporer ce comportement dans un traitement métier, ce sera beaucoup plus élégant de passer par un contrôle sans affichage.

DomainUpDown / NumericUpDown

Le bouquin propose de mettre en place un contrôle avec un TextBox et deux RepeatButton. Ca me paraît un très bon exemple d’une caractéristique à mon sens très importante de WPF, à savoir que le système de template réduit quasiment à néant le besoin de construire ses propres UserControl. Typiquement, ces deux contrôles ne sont que des TextBox en termes de fonctionnalités, à la différence que deux boutons sont rajoutés dans le template modifé.

CheckedListBox

Logiquement, ceci n’existe plus vu qu’on peut customiser librement un ListBox avec un template comprenant un checkbox. L’autre solution consistant à mettre plusieurs checkboxes dans un ScrollBox ne me paraît avoir aucun intérêt, vu qu’elle ne permet pas le binding, et surtout qu’elle n’est pas plus simple à faire que la solution sur une ListBox.

DataGridView

La plupart des fonctionnalités qui ne sont pas présentes de base dans WPF sont faisables avec un peu de code, et sinon, il y a ComponentOne qui fait de très bons contrôles WPF, avec plein de features super, et des versions Silverlight.

WebBrowser

Il semblerait qu’il y ait du nouveau en .NET 4.0, car Visual Studio 2010 montre bien un composant WPF WebBrowser :

image

Du coup, pas besoin de passer par la méthode du livre qui consistait à afficher un frame, avec la grosse limitation associée qui était qu’on n’avait pas accès au DOM. Là, on a bien de l’interaction possible. Un gros ouf pour celui-ci… et une bonne raison pour migrer de WinForms directement à WPF 4.0 plutôt qu’avec une étape par le 3.5.

PropertyGrid

Je ne vais pas parler de ce contrôle, parce que je ne sais pas du tout à quoi ça sert. J’ai jeté un oeil sur internet, et il se trouve que c’est un composant qui, comme son nom l’indique, sert à afficher les propriétés d’un objet, comme dans le dock de propriétés de Visual Studio par exemple.

Je n’aurais pas pensé que ce genre de composant était livré dans .NET. C’est vraiment le genre de trucs avancés que je m’attendais à ce que Microsoft nous laisse faire, mais bon… pourquoi pas. Mais du coup, je comprends tout à fait que ça n’ait pas passé le cut pour être intégré dans WPF.

ColorDialog, FolderBrowserDialog, FontDialog, PageSetupDialog

Le bouquin explique qu’on peut utiliser ceux de WinForms ou les recréer relativement facilement. A mon avis, ça sera très vite dans votre framework de contrôles communs. Et encore une fois, il y a des revendeurs de contrôles très bons et pas très chers.

PrintPreviewControl, PrintPreviewDialog

Je vous renvoie au bouquin, je n’ai rien à dire là-dessus, par manque de connaissance. Par contre, je serais très intéressé par les commentaires de gens qui font de la création de documents pour imprimantes en .NET.

ErrorProvider, HelpProvider

Ca me paraît sidérant qu’il n’y ait pas de solution pour ceci en WPF, tellement c’est important. Encore une fois, mes connaissances de WPF sont trop limitées, mais ça ne m’étonnerait pas qu’il y ait quelque chose pour la gestion de l’aide, même si ce n’est pas sous la forme d’un contrôle.

Au passage, les contrôles de type Provider créait une sorte d’inversion des propriétés entre le contrôle et la cible qui me paraît très proche des attached properties.

AutoComplete

Je ne savais même pas que c’était incorporé dans WinForms, et je me suis d’ailleurs retrouvé à le recréer. Si j’avais su… Du coup, le manque ne me paraît pas criant en WPF, surtout que beaucoup de gens ont une approche différente, et il me semble difficile d’avoir une seule façon de faire, donc c’est peut-être mieux comme ça, plutôt que de risquer avec une méthode intégrée d’avoir des problèmes de mauvaise utilisation.

Rien à voir avec ce sujet, mais j’ai découvert dans ce bouquin ou un autre que la correction orthographique était intégrée dans WPF ! Même chose : pour mon boulot, j’ai testé différentes façons de faire, dont de l’interop avec Office ou OpenOffice, et des contrôles commerciaux pour ceci. Bonne nouvelle : si on passe en WPF, je n’aurais pas besoin de tout ça. Yes…

MDI

Bon, alors là, pour le coup, je n’ai pas d’idée nouvelle sur le sujet, vu que je n’ai jamais en dix ans de carrière développé une interface MDI. Honnêtement, je me demande des fois si ça sert vraiment, ce truc. Autant un système comme les applications à base de pages me paraît vraiment une super innovation de WPF (ça fait déjà plusieurs fois que je crée des frameworks pour rendre ce genre de chose plus facile dans mon boulot), autant le MDI…

Bref, je suis intéressé par savoir si beaucoup de gens utilisent ceci, et comment ils ont décidé de le réaliser en WPF.

Conclusion

Cet article ne servira à rien sans vos commentaires. N’hésitez pas, c’est gratuit 🙂 Et comme vous le voyez, je ne connais pas grand chose à WPF, donc cet article est plus un appel à expérience sur les migrations et WPF. Merci par avance.

Posted in .NET | Tagged | Leave a comment

ArgumentException “Web Service method name is not valid”

En essayant de faire un appel à un service web sans passer par une référence web sur un stub auto-généré, je me suis retrouvé avec cette erreur, dont le libellé ne me paraissait pas très clair.

Je fais un petit article, car j’ai mis un bout de temps à trouver la solution sur internet…

Le problème est exposé ici et renvoie ensuite à cette page. La solution officielle MS est ici, et si vous voulez une explication plus détaillée, je vous conseille cette page (en cherchant “method name” dans le texte). Ce dernier lien est certainement ce que j’ai trouvé de plus fouillé sur SOAP.

Pour ceux qui attendent, le post sur TFS en milieu industriel va bientôt arriver. Je rentre à peine de vacances, il me faut un peu de temps pour mettre ça au propre, mais je n’ai pas oublié !

Posted in .NET, Debogage | Leave a comment

Accelerator : problème avec VS 2010 Beta 2

Comme je vous l’avais expliqué sur mon billet F# précédent, je pensais tester le jeu de la vie pour voir si j’arrivais à reproduire une véritable accélération par le calcul F# sur GPU au lieu de C# sur CPU.

Malheureusement, il va d’abord falloir que je supprime ma Beta 2 de Visual Studio 2010 pour passer à la version finale : il y a en effet un bug renvoyant une MissingMethodException sur Microsoft.FSharp.Collections.FSharpList`1.get_TailOrNull(), détaillé sur http://cs.hubfs.net/forums/thread/13096.aspx

Si vous rencontrez cette erreur, ne vous cassez pas la tête à essayer les différentes solutions, parce que chaque forum a sa propre recette : désinstallez tout et réinstallez, franchement, il n’y a que ça qui marche 🙂

More news later…

Posted in .NET, F#, GPGPU | Tagged | Leave a comment

Accelerator, la suite…

Retour sur l’article précédent

A la fin du billet précédent, l’exemple de Microsoft fonctionnait correctement, et on avait vu comment l’algorithme était réalisé par le programme. Le but ici est de recréer le même programme en C#, afin de voir si les performances sont vraiment au rendez-vous.

Pour rappel, le programme en F# était le suivant :

open System
open Microsoft.ParallelArrays

[<EntryPoint>]
let main(args) = 
    let rawSize = 4000
    let filterSize = 5
    let random = Random()

//    let rawData = [| for i in 1 .. rawSize -> float32 (random.NextDouble() * float (random.Next(1, 100))) |]
    let rawData = [| for i in 1 .. rawSize -> float32 (i) |]

    use rawArray = new FloatParallelArray(rawData) 
    let filter = [1.0f .. float32 filterSize] 
    let rec expr i = let e = filter.[i] * ParallelArrays.Shift(rawArray, i)
                     if i = 0 then
                       e
                     else
                       e + expr (i-1)

    use dx9Target = new DX9Target()
    let debut = System.DateTime.Now
    let resDX = dx9Target.ToArray1D(expr (filterSize-1));

    printfn “F# Accelerator DX9”
    printfn “%A” resDX.[0 .. 9]
    printfn “Temps passé : %A” (DateTime.Now – debut)

    0

Equivalent en C#

Voici le code équivalent en C#. On pourra objecter qu’on doit pouvoir optimiser le code ci-dessous, mais on pourrait dire la même chose pour le code F# auquel on va le comparer. J’ai essayé de ne pas avoir trop de duplication des array, en accomplissant le plus possible de transformation directement sur l’array, sans le cloner.

using System;
using System.Diagnostics;

namespace TestPerfConvolutionPourComparaisonAccelerator
{
    class Program
    {
        static void Main(string[] args)
        {
            int rawSize = 8000;
            int filterSize = 800;

            Random random = new Random();
   
            double[] rawData = new double[rawSize];
            for (int index = 0; index < rawData.Length; index++)
                rawData[index] = (double)(index + 1);
//                rawData[index] = random.NextDouble() * random.Next(1, 100);

            int[] filter = new int[filterSize];
            for (int index = 0; index < filter.Length; index++)
                filter[index] = index + 1;

            Stopwatch Chrono = Stopwatch.StartNew();
            double[] resultat = ExprRecursive(rawData, filter, filterSize – 1);
            Chrono.Stop();

            Console.WriteLine(“C# sur CLR.NET”);
            Console.Write(“[“);
            for (int index = 0; index < Math.Min(resultat.Length, 10); index++)
                Console.Write(” {0:F1}f;”, resultat[index]);
            Console.WriteLine(” ]”);
            Console.WriteLine(“Temps passé : ” + Chrono.Elapsed.ToString());
        }

        private static void MultiplierArray(double[] liste, int multiplicateur)
        {
            for (int index = 0; index < liste.Length; index++)
                liste[index] *= multiplicateur;
        }

        private static void AjouterArray(double[] cible, double[] ajout)
        {
            for (int index = 0; index < cible.Length; index++)
                cible[index] += ajout[index];
        }

        private static void DecalageArray(double[] cible, int offset)
        {
            for (int index = 0; index < cible.Length; index++)
                cible[index] = index + offset < cible.Length ? cible[index + offset] : cible[cible.Length – 1];
        }

        private static double[] ExprRecursive(double[] rawData, int[] filter, int index)
        {
            double[] e = (double[])rawData.Clone();
            DecalageArray(e, index);
            MultiplierArray(e, filter[index]);
            if (index > 0) AjouterArray(e, ExprRecursive(rawData, filter, index – 1));
            return e;
        }
    }
}

Premiers essais

Avec une taille d’array de 4000 et une taille de filtre égale à 5, on obtient les résultats suivants en F# avec Accelerator, en mode DirectX 9 :

image

Voici ce que ça donne en C# :

image

Avant de parler de performance, on vérifie que les résultats sont bien les mêmes. Oui, je me suis déjà fait avoir, à réaliser des comparaisons de performances entre deux méthodes dont une ne faisait que la moitié du travail, et à devoir tout refaire. Ici, pas de souci, on est bien sur les mêmes nombres, et ça se confirmera avec les autres cas de calcul ci-dessous.

Maintenant, côté performances, beaucoup de différence, mais pas dans le sens où on l’attendait : C# est beaucoup plus rapide… Par contre, dans l’absolu, il s’agit de calculs très rapides, donc ça ne veut pas dire grand chose. Il faudrait gonfler la taille de l’array de donnée et celle du filtre pour voir comment ça évolue.

Montée en charge

On essaie de taper très haut dès le début, en passant à 40 000 au lieu de 4 000 pour la taille du tableau de donnée. Problème : on plante en F# !

image

On a peut-être poussé un peu fort. Voyons un peu ce que ça donne en C# :

image

Bon, on s’éloigne de ce qu’on cherchait à démontrer… Essayons en modifiant l’autre paramètre sur lequel on peut jouer, à savoir la taille du filtre, qu’on va passer à 1000, tout en ramenant la taille de l’array de données à 4 000. En F#, on a désormais un autre problème, de dépassement de pile, ce coup-ci :

image

En C#, ça passe toujours bien, et avec des temps pas dégradés du tout :

image

Restons dans des tailles faibles

Je ne vais pas me lancer dans du débogage pour savoir pourquoi ces données sont trop fortes. Pour l’instant, le but est de comparer les deux méthodes, donc on va plutôt prendre des couples de valeurs qui fonctionnent bien dans les deux langages.

Si on pousse au maximum, on peut aller sur du 8000 / 800. Dans ce cas, F# prend 1,86 secondes, tandis que C# prend à peine 0,33 secondes, soit six fois moins !

image

image

Du coup, pas la peine de se casser la tête à faire des courbes de comparaison en fonction des tailles : il semble que quelles que soient les valeurs, C# garde un fort avantage sur F# pour cet exemple.

<minuteDesproges>Attention, ne me faites pas dire ce que je n’ai pas dit !</minuteDesproges> : il y a plein d’exemples, dont certains démontrés récemment aux TechDays, montrant qu’on a bien une forte amélioration de performances. La question est de savoir pourquoi ce cas de test ne montre pas du tout cette amélioration. Il se pourrait que la surcharge de mise en place du target soit telle que, sur des opérations de l’ordre de la seconde, on perde plus de temps qu’on en gagne.

Conclusion à ce jour

Bref, l’étape suivante va être de trouver un exemple un peu plus costaud pour réellement faire travailler en profondeur les algorithmes. Mais il faut bien se rendre à l’évidence que pour ce type de calcul, C# est bien plus efficace que F# avec Accelerator. Ca me chiffonne un peu, mais je ne vais pas, contrairement à ce que font certains sur le climat, modifier mes données dans l’Allégresse 😉 pour qu’elles collent à ce que je veux démontrer…

Je pense qu’il faut tout simplement que je me documente plus sur Accelerator, et que je recommence ce travail de décorticage sur un autre exemple qui a été démontré comme allant plus vite en F# qu’en C#. Je suis tombé sur Internet sur un exemple avec le jeu de la vie, et c’est un des cas qui a été présenté aux TechDays, bref un bon candidat pour mon besoin. Si ça marche, ça devrait également me donner un peu plus de bille pour comprendre pourquoi l’exemple montré ici est moins performant en mode Accelerator qu’avec du code C#. Quoi qu’il en soit, je vous tiendrai au courant sur ce blog.

Une autre piste : si on prend des tailles de données et de filtre très petites (10 et 3), on reste à 0,22 secondes en F#, donc il y a bien une part incompressible d’initialisation du moteur, mais si on retranche des 1,86 secondes sur l’exemple avec le maximum de charge, il reste tout de même un facteur de 5 avec C# !

Un dernier truc

Je ne me lasse pas d’admirer F#, et en particulier, comme il devient rapidement intuitif. Je sais, au début ça paraît bizarre, mais on se prend vite à essayer des choses. Exemple : de la même manière que j’affichais seulement les 10 premières entrées du résultat avec le code C# suivant, je voulais faire pareil en F#.

for (int index = 0; index < Math.Min(resultat.Length, 10); index++)
                Console.Write(” {0:F1}f;”, resultat[index]);

Je savais que pour retrouver un élément d’un array, il fallait utiliser un point suivi de la notation avec des crochets. Par exemple, avec les paramètres à 8000 et 800, printfn “%A” resultat.[0] renvoyait 170986496.0f.

Et comme je le faisais remarquer dans le billet précédent, on peut utiliser la syntaxe a .. b pour retrouver tous les éléments entre a et b. Par exemple, on chargeait le filtre avec def filter = [1.0f .. 5.0f], ce qui le remplissait avec 5 éléments à savoir 1.0f, 2.0f, 3.0f, 4.0f et 5.0f. Ce qui est déjà génial…

Maintenant, si on mélange les deux, F# ne va pas comprendre… Les deux syntaxes sont certainement incompatibles… Et bien non ! Si on écrit printfn “%A” resultat.[0 .. 9], F# va bien afficher dans la console les 10 premières entrées de la liste !!! C’est tout de même rare qu’un langage anticipe à ce point ce que l’utilisateur veut lui faire faire. Du coup, je viens de comprendre pourquoi on est obligé de mettre un point avant d’utiliser l’indexeur. Ce n’est pas un manque de ‘sucre syntaxique’, mais bien que le point est en lui-même une méthode prenant en compte la suite comme un paramètre analysé de manière intelligente. Chapeau, F#…

[Edit]

Pingback de Sébastien Courtois :

http://sebastiencourtois.wordpress.com/2010/05/08/ms-research-devlabs-accelerator-v2-exploiter-vos-gpu-facilement-en-net/

Posted in .NET, F#, GPGPU | Tagged | Leave a comment

F# Accelerator V2 : complément de README

Quand on est grognon, c’est pour la vie

Bon, c’est sympa de la part de Microsoft R & D de nous mettre à disposition leurs trouvailles, mais ça vaudrait le coup de passer un poil plus de temps à écrire le README. Ben oui, quitte à faire une documentation, autant la faire complète, ou carrément laisser l’utilisateur se débrouiller…

Introduction à F#, au GPGPU et à Accelerator

Que je vous explique : j’ai téléchargé Accelerator V2 pour tests. C’est une technologie qui permet de tirer partie de la carte graphique pour faire des calculs scientifiques. Comme un GPU est en gros 100 fois plus puissant qu’un CPU pour le calcul en virgule flottante, ça peut être extrêmement intéressant d’utiliser cette puissance. Jusqu’à il y a peu, ça voulait dire se lancer dans des API spéciales pour les GPU, comprendre la notion de pipeline de données, les différents niveaux de mémoire dans la carte, et tout le bazar. Ensuite, il y a eu du mieux avec CUDA et d’autres moyens d’utiliser ça en C/C++, mais personnellement, très peu pour moi : je ne suis pas passé à un langage de plus haut niveau comme le C# pour revenir au C++. J’en ai fait 3 ans, c’est déjà largement trop pour une vie.

Avec Accelerator, on a enfin une solution pour abstraire confortablement l’utilisation du GPU. Et ce dans un vrai langage. Un langage encore mieux que C#. Si, ça existe… Celui qui a dit “Java” prend la porte, merci 🙂 Ce langage est F#. Si vous êtes sur les blogs de DF, il y a de bonnes chances pour que ça vous dise quelque chose, mais au cas où, F# est un langage fonctionnel, c’est-à-dire qu’il permet de décrire un algorithme par ce qu’il doit faire au lieu de comment il doit le faire. L’exemple que je trouve assez parlant est le suivant : un swap de deux variables. En C#, vous écrivez :

public Tuple<T, T> Swap<T>(Tuple<T, T> Entree)
{
    Tuple<T, T> Sortie= new Tuple<T, T>;
    Sortie.Premier = Entree.Second;
    Sortie.Second = Entree.Premier;
    return Sortie;
}

Bref, vous décrivez à C# ce qu’il doit faire, comment il doit réaliser l’opération d’échange entre deux membres d’un tuple. En F#, et c’est fondamentalement différent, le code ressemble plutôt à ceci :

let swap a b = (b a)

Simplissime, non ? Et ce n’est pas qu’une question de code plus court. En C, on peut faire du code court, mais abscons. Ici, rien de tout cela : un code simple, mais réduit au plus court seulement parce que F# se charge de la tringlerie. Vous ne lui dites pas comment la fonction doit faire son office, mais simplement “Je définis la fonction swap comme étant celle qui, quand je lui donne a suivi de b, me renvoie b suivi de a”. Comment ça marche derrière n’est pas votre problème. S’il a envie de transformer ça en utilisant un buffer pour stocker la version en cours d’inversion, tant mieux. S’il préfère utiliser une instruction du processeur réalisant un échange de cases mémoires, pareil.

Et c’est là que vient le lien avec les performances sur le GPGPU. Quand on programme sur une GPU, on a tous les problèmes du parallélisme, car il y a plusieurs pipelines de calcul, voire plusieurs dizaines actifs. Si vous avez déjà travaillé sur des programmes multithread, vous connaissez la difficulté de mise au point : gérer les threads, les locks, vérifier que la mémoire lue souvent est bien marquée comme volatile, etc. Bref, une sacrée galère parce que vous devez dire au code COMMENT il doit gérer le parallélisme. Au lieu de vous consacrer uniquement sur ce que vous voulez obtenir comme résultat. Vous voyez le truc : F# va nous débarrasser de toute cette problématique, et c’est en cela qu’il est le langage idéal pour du calcul en GPGPU.

Accelerator est le lien entre F# et les librairies pour utiliser le calcul sur GPGPU.

Retour sur le README

Bon, maintenant que je vous ai exposé le sujet, il faut que je revienne sur ce README que Microsoft donne à télécharger avec Accelerator. Je vous le recopie en entier, ça ne va pas faire sauter les serveurs, loin de là.

To use this Accelerator v2 F# sample you will need one of these two configurations:

* Visual Studio 2008 with the October 2009 F# CTP Add-in (http://go.microsoft.com/fwlink/?LinkId=151924), or
* Visual Studio 2010 Beta 2 with F# libraries installed

Build and run the sample by:

1)  Create a new F# Application Project in Visual Studio.
2)  Open the program.fs file from the Accelerator sample package.  Paste its contents into your F# Application Project’s program.fs file.
3)  Add these assembly references to your F# Application Project.
    – System.Drawing
    – Microsoft.Accelerator.dll, which can be found in <Accelerator v2 install directory>\bin\Managed\{Release|Debug}

See http://msdn.microsoft.com/en-us/fsharp/default.aspx for more information about Microsoft F# tools and documentation.

Bon, je ne vais pas trop me plaindre du fait qu’il y ait à peine plus de dix lignes. A cheval regardé, on ne regarde pas les dents. Simplement, quitte à donner des étapes pour l’installation, ça aurait été bien de ne pas oublier une des plus importantes : registrer la DLL Accelerator.dll dans la version que vous utilisez, sinon ça ne marche pas. Et oui, ce n’est pas le code managé tout seul qui va taper le GPGPU. Entre les deux, ça passe par une librairie native et du DirectX, qui a le bon goût d’être masqué au programmeur, mais qu’il faut quand même avoir.

Bref, pour compléter ce README, il faut aller dans C:\Program Files\Microsoft\Accelerator v2\bin ou équivalent en fonction de votre répertoire d’installation. Là-dedans, vous avez le répertoire Managed dont le README parle, mais aussi (et surtout) deux répertoires x86 et x64, qui contiennent les deux versions de la fameuse DLL obligatoire pour que ça marche, et dont on ne parle pas.

Une fois arrivé là, le plus simple est de recopier cette DLL dans votre répertoire exécutable : c’est encore le meilleur moyen pour que ça marche sans vous poser de problème, et surtout éviter l’affreux message “Unhandled Exception: System.DllNotFoundException: Unable to load DLL ‘Accelerator.dll’: Le module spécifié est introuvable. (Exception from HRESULT: 0x8007007E)”

image

On passe au piège suivant

Bon, vous êtes contents de voir que le code livré avec le README compile. Oui, Microsoft vous livre quand même un exemple avec, c’est gentil. Voici le code :

// Copyright (c) Microsoft Corporation 2009.
// This sample code is provided “as is” without warranty of any kind.
// We disclaim all warranties, either express or implied, including the
// warranties of merchantability and fitness for a particular purpose.

open System
open Microsoft.ParallelArrays

[<EntryPoint>]
let main(args) =
// Declare the start data and declare the filter
let rawSize = 4000
let filterSize = 5

// Create Random generator
let random = Random()

// Declare raw data array
let rawData = [| for i in 1 .. rawSize -> float32 (random.NextDouble() * float (random.Next(1, 100))) |]
// Create Accelerator types for the raw data
use rawArray = new FloatParallelArray(rawData)

// Declare filter for the convolution
let filter = [1.0f .. float32 filterSize]

// Build the expression
let rec expr i = let e = filter.[i] * ParallelArrays.Shift(rawArray, i)
                 if i = 0 then
                     e
                 else
                     e + expr (i-1)

// Create DX9 target
// use dx9Target = new DX9Target()

// Create x64 Multicore target (for x64 OS only.)
use x64MCTarget = new X64MulticoreTarget()

// Evaluate the Accelerator expression.
// let resDX = dx9Target.ToArray1D(expr (filterSize-1));
let resMC = x64MCTarget.ToArray1D(expr (filterSize-1)); // For x64 OS only.

// Print the result
// printfn “DX9 –> \r\n%A” resDX
printfn “x64 MC –> \r\n%A” resMC

0

Bon, le commentaire en haut dégageant toute responsabilité, on est habitué, et c’est logique vu que c’est encore de la R & D, mais est-ce que c’était trop demandé de ne pas considérer par défaut qu’on était en 64 bits ? Parce que moi, quand je publie un exemple avec une API, je m’arrange pour le faire le plus simple et général possible. Le but est que n’importe qui qui n’ait aucune connaissance à priori puisse copier / coller, et tout de suite faire fonctionner. Si la première chose qui se passe est une erreur comme ci-dessous, c’est mal barré :

image

Et oui, il plante, mais sans rien dire. Sympa… Ca aide drôlement les gens qui souhaitent juste découvrir la technologie. Ben oui, je ne suis pas en 64 bits, donc il faut penser à changer les trois dernières lignes de code par les versions DX9. Le code aurait déjà pu être regroupé en deux sections complètes avec les trois lignes complètes chacune. Et puis pourquoi mettre le 64 bits par défaut ? En mettant DX9 par défaut, ça marchait pour tout le monde, et ensuite, une note pour expliquer que ça peut être optimisé pour les machines 64 bits, avec le code commenté, et ça roulait…

L’est pas très finaud, celui-là…

C’est certainement ce que vous vous dites en lisant la paragraphe précédent. C’est vrai que ce n’est pas très complexe de lire le code source, et de voir qu’il y a une version DX9. Mais le problème est dans la façon de prendre le problème : personnellement, ma façon d’aborder une nouvelle technologie est de faire fonctionner un exemple, et ensuite seulement de regarder comment ça marche. Je ne vais pas me casser la tête à essayer de comprendre le code si c’est pour me rendre compte 45 minutes plus tard qu’en fait, non, ça ne marche pas. Du coup, j’étais à deux doigts de me dire “on laisse tomber, c’est pas mûr, leur truc”. Et je trouve que c’est dommage. Si Microsoft publie ce genre de choses, c’est pour que les gens les testent. Si ils ne leur mettent pas le pied à l’étrier au minimum, ce n’est pas la peine. Surtout que vous en conviendrez, ce n’est vraiment pas grand chose à changer au README et à l’exemple pour que ça se passe mieux. Ou alors le but est de filtrer de façon à ne garder que les gens suffisamment motivés pour enquêter et faire fonctionner le bidule. J’espère que ce n’est pas le cas…

Allez, fini de râler !

On passe au code proprement dit. Je me propose de vous guider ligne par ligne sur ce que fait ce fameux exemple. Première chose, écrémer : je laisse de côté la déclaration du point d’entrée du programme, des constantes rawSize et filterSize. Si c’est évident pour moi, je pense que ça doit l’être pour la majorité.

Cette fonction crée un tableau, en bouclant rawSize fois sur un calcul où on multiplie

let rawData = [| for i in 1 .. rawSize –> float32 (random.NextDouble() * float (random.Next (1,100))) |]

un float32 pris au hasard entre 0.0 et 1.0 par un entier, converti en float, pris lui entre 1 et 100. Bref, ça vous donne un tableau de float32 compris entre 0.0 et 100.0 à la fin. Si vous utilisez une fonction printfn “%A” rawData, et que vous réduisez la taille de rawSize à 4 pour faciliter la visualisation, vous obtenez le résultat suivant (par exemple, vu que c’est pris au hasard) :

[|58.5019684f; 35.348053f; 27.9487534f; 73.6845932f|]

La ligne suivante est intéressante :

use rawArray = new FloatParallelArray(rawData)

On définit une instance de FloatParallelArray, qui provient du namespace Microsoft.ParallelArrays fourni par Accelerator. Il s’agit d’un array de flottants, mais spécial pour utilisation dans les GPGPU.

On passe une ligne plus loin :

let filter = [1.0f .. float32 filterSize]

La syntaxe, spécifique à F#, est tout-à-fait dans la ligne de la simplicité d’écriture du langage. Pourquoi vous forcer à écrire une boucle, alors que vous voulez simplement obtenir un array avec des valeurs qui vont de 1 à filterSize ? Ecrivez le tout simplement avec .. au milieu, et F# se charge du boulot.

Bref, cette ligne est équivalente à :

let filter = [1.0f 2.0f 3.0f 4.0f 5.0f]

Dernière ligne du code “métier”, mais la plus compliquée :

let rec expr i = let e = filter.[i] * ParallelArrays.Shift(rawArray, i)
if i = 0 then
    e
else
    e + expr (i-1)

Le mot clé rec sert à spécifier que la fonction est récursive. La fonction expr, qui prend un paramètre i, est donc récursive, et définie de la manière suivante : on crée une valeur locale e qui prend comme valeur la i-ème valeur de la liste filter multipliée par “ParallelArrays.Shift(rawArray, i)“. Si on est à la récursion 0, on renvoie cette valeur, et sinon, on la renvoie sommée avec la récursion suivante.

C’est sur le calcul de e que ça se complique. Si on tente un printfn “%A” rawArray, on voit juste le ToString() standard, à savoir le type, en l’occurrence “Microsoft.ParallelArrays.FloatParallelArray”. Du coup, pas facile de voir ce que fait cette fameuse fonction Shift. Les commentaires parlent d’une convolution, donc on va jeter un oeil sur internet, en entrant ce mot clé, ainsi que le code de la fonction. On trouve assez facilement : en fait, Shift renvoie juste un tableau décalé du second paramètre (http://tomasp.net/blog/accelerator-intro.aspx pour des explications simples, et http://blogs.msdn.com/satnam_singh/archive/2010/01/11/a-c-implementation-of-a-convolver-using-accelerator-for-gpgpu-and-multicore-targets-using-linq-operators.aspx ou http://blogs.msdn.com/satnam_singh/archive/2009/12/15/gpgpu-and-x64-multicore-programming-with-accelerator-from-f.aspx si vous êtes plus courageux).

Le premier lien est vraiment intéressant, car plus accessible (le second blog est très bien, mais on a vraiment l’impression qu’il ne s’adresse qu’à ses collègues). Un truc particulièrement utile pour comprendre ce qui se passe est l’explication que FloatParallelArray n’est pas une classe de stockage de données, mais plutôt la représentation d’un calcul. C’est le target qui va se charger de déclencher ce calcul. L’auteur fait un parallèle très intéressant avec Linq. Plus je lis cet article, plus je le trouve excellent… Bref, qu’est-ce que vous faites encore ici ? Allez le lire, je vous dis ! C’est sur http://tomasp.net/blog/accelerator-intro.aspx et ne revenez que si vous avez besoin d’un article encore plus introductif : si, comme pour moi, vous comprenez 80%, c’est que vous n’avez pas besoin de mon article, dont le but est plutôt d’amener les gens de 0 à cet article.

Encore là ?

Si vous êtes encore là, c’est que ça vous a paru encore un peu abstrait, alors je vais tenter de faire le lien. Le mieux dans ce cas là est de laisser tomber pour l’instant la compréhension de la fonction expr. Passons aux trois lignes finales de code, en les prenant dans la version DX9. Le X64, c’est pour utiliser le multicore, et comme son nom le précise, ça ne fonctionne qu’en 64 bits.

use dx9Target = new DX9Target()
let resDX = dx9Target.ToArray1D(expr (filterSize-1));
printfn “%A” resDX

La dernière ligne sert juste à afficher le résultat du calcul. Celui-ci est réalisé par les deux lignes précédentes. La première déclare un target, c’est-à-dire en gros un moteur de calcul. Et c’est à ce moteur de calcul qu’on va demander d’évaluer la fonction expr(filterSize – 1), en l’occurrence pour nous la fameuse fonction récursive avec 5 – 1 = 4 comme paramètre.

Pour mieux comprendre, débarrassons nous en premier du hasard et d’un peu de complexité : on va laisser rawSize à 4, mais baisser filterSize à 3, et au lieu de prendre les valeurs de notre array rawData au hasard, on va utiliser la ligne suivante :

let rawData = [| for i in 1 .. rawSize -> float32 (i) |]

Ce qui va nous ramener un tableau avec [1.0f 2.0f 3.0f 4.0f].

Si on calcule récursivement la fonction en partant de filterSize – 1 = 2, le Shift du tableau par 2 va nous donner [3 4 4 4] (je ne mets pas les notations flottantes complètes pour que ça soit plus simple à lire) : le Shift décale les valeurs, mais en laissant les premières telles quelles.

Quand on multiplie par filter.[2], c’est-à-dire 3, on se retrouve avec [9 12 12 12]. Comme on est sur le niveau 2, il faut ajouter le niveau 1, puis récursivement le niveau 0. Au niveau 0, c’est simple, on renvoie simplement le tableau [1 2 3 4]. Au niveau 1, on peut faire exactement le même calcul de e, et on obtient [4 6 8 8]. Bref, en fin de récursion, quand on a ajouté tout ça, on se retrouve avec [14 20 23 24].

Ce que nous confirme le test :

image

Pour faire plus clair, on peut le prendre par l’autre bout : on met de côté la récursion, en considérant qu’elle va simplement ramener e(i=0) + e(i=1) + e(i=2).

Et si on prend les niveaux de récursion de manière séparée, on a :

e(i=0) => filter(0) * [1 2 3 4] = 1 * [1 2 3 4] = [1 2 3 4]

e(i=1) => filter(1) * Décalage de  [1 2 3 4] par 1 unité = 2 * [2 3 4 4] = [4 6 8 8]

e(i=2) => filter(2) * Décalage de [1 2 3 4] par 2 unités = 3 * [3 4 4 4] = [9 12 12 12]

Et si on somme tout ça, on a bien [9+4+1 12+6+2 12+8+3 12+8+4], soit [14 20 23 24].

Retour sur le target

On revient à l’explication initiale de F# : c’est le but du target de décider comment ce calcul va être fait. Dans le FloatParallelArray, vous ne faites que définir le calcul que j’ai détaillé ci-dessus. C’est ensuite la force de F# dans le target de décider comment il va utiliser le GPU pour réaliser le calcul. La seconde ligne du calcul consiste à déclarer au target qu’il doit évaluer expr(filterSize – 1), ou expr(2) sur l’exemple simplifié, puis renvoyer le résultat de ce calcul sous forme d’un array à une dimension. Le résultat peut ensuite être affiché.

Bref, et c’est le plus important à comprendre : on n’écrit pas l’algorithme, mais la définition du calcul à réaliser, et on passe ensuite cette définition de fonction un peu à la mode d’un pointeur de fonction / d’un delegate à la fonction du target qui se débrouille pour travailler avec ça.

Ce qui se passe derrière (en très gros)

Bon, je n’ai pas la prétention de comprendre ce qui se passe derrière, mais d’après ce que j’ai lu dans quelques blogs et docs sur les calculs par GPGPU, il semblerait que ce soient les pixel shaders des cartes qui soient utilisés pour simuler des vecteurs à 1 ou 2 dimensions. Schématiquement, comme les cartes GPU sont optimisées pour calculer des couleurs sur des points, on peut se servir des valeurs (de position ou de couleur, je ne sais pas) pour coder les valeurs de n’importe quel vecteur. Ensuite, le codage se fait d’une manière ou d’une autre en fonction de la librairie d’utilisation des GPGPU, et c’est justement le rôle des fonctions ToArray1D ou ToArray2D de l’API Accelerator.

Mais prenez ceci avec des pincettes : c’est la façon dont je le comprends, mais ce n’est pas encore très clair. J’essaierai de l’être plus dans un prochain article, quand je serai plus au point sur cette technologie, qui est pour moi essentielle. En attendant, j’espère avoir réussi à atteindre mon humble but, à savoir compléter le README de Microsoft et mieux documenter l’exemple de façon qu’une personne avec absolument 0 connaissance de F# et des GPGPU comprenne ce qui se passe dans l’exemple livré avec. Merci par avance de vos commentaires sur ce qui pourrait manquer pour atteindre ce but.

Posted in .NET, F#, GPGPU | Tagged | Leave a comment

Lancer les tests impactés : ça marche pas ?

Si vous avez plusieurs centaines de tests unitaires, et que ça finit pas prendre un temps non négligeable, vous serez sûrement sensibles à l’ajout d’une fonctionnalité dans Visual Studio 2010 qui permet de ne jouer que les tests impactés par les récentes modifications du code. En démonstration aux TechDays 2010, ça a fait vraiment réagir la salle : c’est le genre de fonctionnalité qu’il n’est pas facile à mettre en place soi-même et qui a un potentiel énorme pour des économies de temps. C’est relativement simple avec les bons outils de mettre en place une usine de test, ou de l’intégration continue. Mais des fonctionnalités de ce type, il faut vraiment du développement derrière…

Bref, vous vous êtes peut-être comme moi rué sur cette fonctionnalité dans la RC, pour la découvrir active dans les menus, mais avec un message d’erreur quand vous essayez de l’activer : “no tests were run because no tests are loaded, no tests are impacted, or the impacted tests are not able to run” ? Pas de panique, c’est normal : l’analyse d’impact n’est pas active par défaut (certainement parce que ça prend pas mal de temps en plus).

Dans le menu Test, vous pouvez choisir une collection de settings à activer, et Visual Studio 2010 (en tout cas la RC) est livré avec deux ensembles : Local et Trace and Test Impact. Par défaut, en mode Local, la gestion d’impact n’est pas active, alors que c’est le cas pour le second set. Bref, vous pouvez activer le second set, ou bien aller dans le menu juste en dessous “Edit test settings”, et modifier les paramètres de l’ensemble de settings que vous utilisez.

Capture_2010-04-05_20-41-33

En l’occurrence, supposons que vous éditiez le mode Local : vous pouvez aller dans la section Data and Diagnostics et activer Test Impact. Une fois ceci réalisé, vous pouvez tester, et ça marche : si vous faites une modification sur votre System Under Test et que vous utilisez le menu Test / Run / All Impacted Tests, vous ne lancerez que les tests qui ont été impactés potentiellement par la modification de code. Attention, il faut bien compiler votre solution pour que cela fonctionne (vous voyez la barre de couleur sur le côté gauche de votre code modifié passer de jaune à vert lorsque vous sauvegardez).

Il est à noter que l’analyse d’impacts prend un peu de temps, et du coup, les tests fonctionnent un peu moins vite avec ce mode activé. Du coup, ça vaut le coup de plutôt jouer entre les deux ensembles de settings, avec le Local très rapide, et lorsque vos tests commencent à prendre de l’ampleur, changer entre Local et un autre test où vous activez l’analyse d’impact pour être toujours le plus rapide en fonction des besoins (parfois, vous savez qu’il faut quoi qu’il arrive relancer la totalité des tests unitaires).

Posted in .NET, ALM, Debogage | Tagged | Leave a comment

Comportement bizarre sur les ajouts d’entités

Après quelques semaines à me demander quel était le bug étrange qui agitait la fenêtre “Add New Item” dans Visual Studio 2010, je crois que je viens de comprendre ce qui se passe : lorsque la fenêtre s’affiche, seuls les templates disponibles dans la version du framework que vous avez choisie sont visibles.

Par exemple, créons un projet en .NET avec la version 2.0 comme framework cible. Conformément à la logique, la liste ne propose pas les classes Linq To SQL. Bien…

greenshot_2010-03-24_22-51-20

Maintenant, si vous avez comme moi l’habitude de taper un mot clé dans la barre de recherche, plutôt que de chercher dans la liste, vous vous retrouvez d’un coup avec tout de disponible. Si on entre Linq en haut à droite, on se retrouve dans une entrée nommée “Search Results” :

greenshot_2010-03-24_22-56-41

Du coup, si on retourne sur “Visual C# Items”, la liste est désormais comme suit :

greenshot_2010-03-24_22-56-11

Si on descend plus bas, on voit désormais l’entrée Linq To SQL Classes, ce qui est presque normal (un message indiquant que le template a été trouvé mais n’est pas disponible sur cette version du framework .NET serait le bienvenu). Par contre, il semble que ça fasse carrément sauter la notion de filtre, parce qu’on voit du coup les templates sur les Entity ADO.NET, et d’autres templates plus récentes que .NET 2.0.

Là où ça pose problème, c’est qu’on peut choisir ces templates, et se retrouver avec des erreurs en cascade. Typiquement, si on prend les Linq To SQL Classes, on voit bien le designer Linq qui s’affiche, mais avec un message à la suite indiquant que la librairie System.Core n’a pas pu être ajoutée.

Logique, encore une fois, puisqu’on est en .NET 2.0, et que cette librairie n’est apparue que sur la version 3 du framework. Et si on va la chercher dans la liste des références, là, le blindage est plus consistant et on n’a pas moyen de la référencer depuis la liste standard .NET.

Bon, maintenant, essayer de voir sur les forums si quelqu’un a déjà envoyé le problème.

A propos de comportements bizarres, savez-vous que la RC de VS2010 a des plantages de l’Intellisense sur les machines équipées d’un TouchScreen, d’une tablette, etc. ? J’avoue que je ne vois pas le rapport. Ca fait peur, ce genre de bugs : la modularisation des applications devrait rendre inexistante les liens de ce type entre deux fonctionnalités qui n’ont rien à voir l’une avec l’autre… Si vous avez le problème, hotfix VS10-KB980610-x86.exe, et ça a l’air de marcher mieux (je l’ai juste mis hier, alors j’attends un peu, mais avant, c’était au moins une fois toutes les dix minutes, donc je pense que c’est bon).

Posted in .NET, Debogage | Tagged | Leave a comment

Team Foundation Server 2010 Basic, ou comment installer une ALM professionnelle complète en 17 clics

Aucun employé de Microsoft ne le dira jamais de manière officielle, mais quand vous discutez avec eux, certains l’avouent : Team Server avant la version 2008 était un accident industriel… Une erreur logicielle sortie uniquement pour que les concurrents et les solutions Open Source ne prennent pas trop d’avance.

Avec Rosario (la version 2008), Microsoft s’était enfin décidé à sortir quelque chose qui, fonctionnellement, tenait bien d’une ALM (Application Lifecycle Management), mais qui était redoutable à installer et à configurer. J’en ai personnellement fait l’expérience, échouant à recréer en trois jours de boulot avec Rosario ce que j’ai mis en place avec facilité, bien qu’en y passant du temps, avec CVS + NAnt et des appels directs à csc.exe et NUnit-console.exe.

Côté fonctionnalité, il y avait à peu près tout ce qu’il fallait pour une équipe de développement, mais rien de plus que ce qu’on pouvait se mettre en place en assemblant des produits OpenSource.

Attention les yeux !

La version 2010 n’a absolument rien à voir avec les précédentes. Microsoft a du menacer de virer sa division complète de développeurs sur TFS, car la version 2010 est impressionnante. Et sur les deux points : fonctionnalités (j’y reviendrai dans de prochains billets) et facilité d’installation et de configuration (le sujet du présent billet).

L’installation de TFS en version Basic (c’est à dire sans le reporting et le collaboratif, dont on peut très bien se passer pour des projets petits et même moyens) se fait en 17 clics de souris. En plus, vous n’êtes même pas obligés d’avoir un OS serveur ! Windows 7, même en 32 bits, fait très bien l’affaire, et vous pouvez donc pour vos tests avoir un TFS Basic 2010 RC sur votre bécane de développement, au même endroit que votre Visual Studio 2010 RC tout frais lui aussi. Autant vous dire que pour des beta-testeurs avec une machine limitée, c’est parfait… Plus besoin d’une VM limitée en RAM pour voir comment ça marche.

Pour vous dire à quel point c’est simple, je ne vais même pas vous faire de captures d’écran. Il n’y en a pas besoin : vous double-cliquez sur Setup.exe pour lancer l’installation, et ensuite vous ne faites que cliquer sur Next à chaque fois qu’on vous le demande. Même le choix du mode configuration est sur Basic par défaut, donc vous n’aurez même pas à changer ce mode. Vraiment, vous ne faites qu’avancer en gardant la configuration par défaut, et à la fin, vous vous retrouvez avec un serveur TFS accessible depuis http://localhost:8080/tfs.

Juste un petit truc : une erreur sur le WMI quand vous utilisez Windows 7 :

greenshot_2010-02-27_15-31-31

Rien de grave. Si vous cherchez le code TF255437 sur Google n’importe quel moteur de recherche, vous trouverez aisément la solution, comme par exemple sur http://social.msdn.microsoft.com/Forums/en-CA/tfsprerelease/thread/e6a24673-8606-4e79-87b5-5deae28234f6

Il suffit de cocher la fonctionnalité suivante dans les programmes Windows, et de relancer l’analyse de votre configuration. Bon, ça fait un clic de plus, mais le problème ne se produit pas en Windows Server.

greenshot_2010-02-27_15-32-23

L’installation complète a pris 17 clics de souris, plus le double-clic initial sur le programme setup.exe et les clics pour parcourir l’ISO d’installation, si on pinaille. Plus sérieusement, et plus important, à aucun moment le système d’installation ne demande de rentrer du texte pour configurer le logiciel ou le faire pointer sur une instance de SQLExpress ou autre. Si vous avez une installation de SQL, il la choisit pour vous, si vous n’en avez pas, il installe une instance de SQLExpress de manière silencieuse. Et surtout, à aucun moment, vous ne vous retrouvez en face d’une zone de saisie obligatoire en vous demandant “mais qu’est-ce qu’ils veulent que je mette là-dedans ?”.

Bref, génial pour tester. De manière générale, c’est le problème de beaucoup de serveurs : ils vous demandent plein de paramètres de configuration à l’installation. Quand vous connaissez bien le logiciel, pas de souci. Mais il y a obligatoirement une première fois… Microsoft a résolu brillamment ce problème sur TFS 2010 : installation complète par défaut, et si vous voulez paramétrer plus finement après, pas de souci, vous pouvez le faire. Mais si vous n’y connaissez rien, vous cliquez sur Next sans rien comprendre, et à la fin, tout est sur le répertoire virtuel tfs, sous port 8080.

Et ensuite ?

Bon, une fois arrivé là, vous vous dites que ça vaudrait le coup d’aller faire un tour sur cette fameuse url http://localhost:8080/tfs/. Allons-y, mais je vous préviens, il n’y a pas grand chose pour le moment. On vous demande votre login (authentification intégrée Windows), et voilà :

greenshot_2010-02-27_16-15-41

Eh ben, oui ! Il n’y a rien 🙂 Pas de projet à afficher, vu qu’on n’en a pas créé. Et il n’y a pas de lien pour en créer sur la page web.

Du coup, on jette un petit oeil à la console de configuration de TFS, qui s’est affichée à la fin de l’installation :

greenshot_2010-02-27_16-18-37

Si on va dans la premier node de l’arborescence, on n’en apprend pas beaucoup plus :

greenshot_2010-02-27_16-19-43

Mais, dans le deuxième, il semble y avoir un onglet intéressant dans la partie du bas :

greenshot_2010-02-27_16-20-43

Là encore, non seulement il n’y a pas de projet, mais il n’y a pas de lien de type Add ou autre chose.

greenshot_2010-02-27_16-21-46

Par contre, le lien How to add a Team Project paraît contenir ce qu’il nous faut. Le lien nous redirige sur http://msdn.microsoft.com/en-us/library/ms181477%28VS.100%29.aspx qui nous explique en gros que c’est depuis Visual Studio que ça se passe.

Configuration de Visual Studio

Du coup, c’est l’occasion d’installer la RC de Visual Studio 2010 aussi. Tout d’abord, quelques remarques :

  1. Ce n’est pas la peine d’avoir TFS 2010 pour utiliser VS 2010 : un Rosario suffit.
  2. Là où c’est encore plus fort, c’est que dans l’autre sens, c’est également vrai : vous pouvez très bien vous connecter avec une ancienne version de VS sur une nouvelle de TFS. Bref, il y a compatibilité dans les deux sens.
  3. Vous pouvez tout à fait installer VS 2010 RC sur la même machine qu’un VS 2008. Les deux ne se marchent pas sur les pieds. En tout cas, personnellement, je n’ai pas eu de problèmes…

Une fois arrivé dans Visual Studio, c’est extrêmement simple à nouveau : il suffit d’aller dans le menu Team, de sélectionner la seule entrée pour l’instant, à savoir “Connect to a Team Foundation Server”, et de se connecter au serveur, en l’occurrence la machine locale dans notre exemple.

greenshot_2010-02-27_16-31-53

Ce que TFS appelle des collections sont des ensembles de projets. Ca peut être pratique si vous avez deux logiciels qui ne partagent rien de les gérer dans deux collections. Mais la séparation est assez forte. Notez que l’installation par défaut a créé une collection par défaut, donc pas besoin de se poser de question.

Une fois que vous vous êtes connectés, vous avez accès au panel Team Explorer (CTRL+W, M, ou dans le menu View), qui va enfin nous permettre de créer un projet au sens TFS. Un clic droit sur localhost\DefaultCollection, et on choisit New Team Project… C’est parti pour un assistant, où on remplit d’abord le nom du projet et une petite description. Je ne suis pas fan des projets de type toto ou HelloWorld, alors on va plutôt en profiter pour tester les tests unitaires à la mode Microsoft. Je ne connais que la syntaxe NUnit, mais d’après ce que j’ai vu, c’est très proche.

greenshot_2010-02-27_16-41-23

L’étape suivante vous propose de choisir un modèle de processus :

greenshot_2010-02-27_16-44-06

La première fois, ça fait bizarre. Pourquoi est-ce que TFS me demande si je travaille en mode Agile ou CMMI (et il y a plein d’autres modèles à télécharger, de type RUP, etc.) ? En fait, c’est parce que TFS ne se limite pas, loin de là, à un contrôle de code source et une compilation automatique. C’est vraiment un ALM complet. Ce qui veut dire qu’il va gérer les tâches que vous entreprenez, les suivre, les relier à vos modifications de code, à votre gestion de branches, à vos livraisons, etc. Ce qui représente une énorme valeur ajoutée. On verra au fur et à mesure des prochains articles pourquoi.

La prochaine étape consiste à créer le répertoire dans le code source :

greenshot_2010-02-27_16-46-13

Une fois arrivé là, on peut avoir un petit résumé et lancer la création du projet. Ca prend quelques dizaines de secondes (mise en place du projet dans le serveur, dans la base de données, etc.). On peut ensuite commencer à bosser.

Création du premier projet sous contrôle de TFS

Supposons qu’on crée un projet avec nos opérations arithmétiques à tester, et qu’on coche Add to source control comme suit :

greenshot_2010-02-27_18-01-12

On aura ensuite l’affichage de la fenêtre suivante qui nous demande où dans la collection courante le projet doit être ajouté :

greenshot_2010-02-27_18-04-10

On peut bien sûr créer un nouveau répertoire et mettre en place une arborescence pour organiser notre travail, mais dans un premier temps et vu qu’il s’agit d’un test, je vais simplement placer ce projet sous un seul niveau de répertoire, à savoir TestsTFS. Le bouton Advanced… permet de contrôler de manière plus fine la correspondance entre le contenu et le contrôle de code source.

Quand on crée un projet, vous savez que Visual Studio crée pour vous un fichier de définition du projet, un pour la solution, et dans notre cas aussi un AssemblyInfo.cs, ainsi qu’un fichier de classe Class1.cs. Dans le cas d’un contrôle de code source, il y a aussi les fichiers .vspscc et .vssscc. Et du coup, la fenêtre Pending Changes vous indique que tous ces fichiers sont en attente d’ajout dans le contrôle de code source. En effet, nous avons créé le projet, mais pour l’instant, on n’a rien mis dedans.

greenshot_2010-02-27_18-12-03

Pour valider tout ceci dans le CCS (Contrôle de Code Source, l’acronyme n’est pas officiel, mais je n’ai pas envie de taper ça 36 fois…), il suffit de cliquer sur Check In. Il est de bonne pratique de rajouter un commentaire pour se rappeler du contenu global de cette livraison. La deuxième icone vous permet de relier la livraison de code à un Work Item. Je préfère garder cette notion, fondamentale, pour un prochain article plus complet sur la question, donc je ne vais pas créer un Work Item pour l’associer, mais sachez d’ores et déjà que ceci est extrêmement important. Un Work Item, pour vous expliquer quand même en deux mots, vous permet d’identifier, sur tout le cycle de vie, une opération de modification de votre logiciel. Typiquement, si vous mettez en place une fonctionnalité, ça doit être réalisé sous un Work Item. Ainsi, vous pourrez facilement consulter tout ce qui a été fait sur cette fonctionnalité, lancer des tests dessus, la passer sur une autre branche de développement, etc. J’arrête pour l’instant, mais on y reviendra car c’est absolument essentiel. Dans toutes les solutions ALM, la grosse difficulté d’intégration aux processus de la société qui les utilisent gravite autour de cette notion.

Espaces de travail

Pour l’instant, les fichiers sont rajoutés dans le CCS, mais ils sont aussi présents dans le répertoire dans lequel j’ai initialement créé le projet. Ceci était fait exprès pour vous faire voir que, dorénavant, on peut supprimer ces fichiers et les récupérer à un endroit un peu plus approprié pour travailler.

Supprimons donc tout le contenu de C:\Temp\OperationsArithmetiques après avoir clos la solution, et nous allons réaliser l’opération de Check Out, c’est-à-dire la récupération d’une copie de travail de ce qui se trouve désormais sur le serveur.

Pour cela, un double clic sur “Source Control” dans le panel “Team Explorer” nous amène en vue principale un autre onglet, à savoir “Source Control Explorer”, dans lequel on retrouve le projet et la solution que nous avons précédemment créés :

greenshot_2010-02-27_18-23-15

Par contre, on voit que pour l’instant, le projet n’est pas “mappé”. Il faut mettre en place une correspondance pour que le gestionnaire de code source sache où les fichiers doivent être placés en local pour travailler dessus. L’endroit du disque dur local où on stocke les fichiers pour modification, avant retour dans le serveur TFS, est appelé un workspace, ou espace de travail.

En cliquant sur le lien “Not Mapped”, VS vous propose de mettre en place cette correspondance. C’est le bon moment pour créer un répertoire de base dans lequel vous mettrez tous vos projets. Pour moi, c’est dans D:\WIP\Workspace (WIP comme Work In Progress pour les curieux), et VS rajoute automatiquement le nom du projet, de façon à ce qu’un répertoire soit créé pour ce projet TFS en particulier. On veut récupérer le contenu en récursif, donc la case en bas à gauche reste à son état coché par défaut.

greenshot_2010-02-27_18-25-38

Quand on clique sur Map, VS nous demande si on veut supprimer notre ancien mapping sur C:\Temp, et c’est bien ce qu’on veut faire, donc on confirme. Juste après, une autre boîte apparaît, où VS nous propose de lancer aussitôt l’opération de Get, qui consiste à alimenter le répertoire de correspondance avec les fichiers en provenance de TFS. En effet, dans un premier temps, on avait juste créé le répertoire et on l’avait mis en correspondance avec le projet sur le gestionnaire de code source, mais maintenant, il faut lui dire de rapatrier les fichiers. Un peu comme une synchronisation descendante.

greenshot_2010-02-27_18-32-04

Le rapatriement des fichiers se fait :

greenshot_2010-02-27_18-32-29

Et on a bien tout ce qu’il faut pour compiler, modifier et tester en local :

greenshot_2010-02-27_18-35-51

Si on avait répondu non à la commande de Get proposée, on pouvait réaliser l’équivalent en cliquant sur l’icone Get Latest Version (recursive) dans l’onglet “Source Control Explorer”.

Une fois arrivé à ce point, on peut ouvrir la solution D:\WIP\Workspace\TestsUnitairesMicrosoft\TestsTFS\OperationsArithmetiques\OperationsArithmetiques.sln et travailler dessus comme on le ferait pour n’importe quelle solution en local, à la seule différence que le panel Pending Changes s’enrichit au fur et à mesure des modifications, en attendant la prochaine étape de validation des modifications.

Notons juste que le seul fait de modifier un fichier génère un CheckOut, c’est-à-dire une opération signifiant qu’on prend la main sur le fichier. Il y a des options pour contrôler ceci, comme dans la plupart des IDE ou des plugins de contrôle de code source. Mais on peut bien sûr aussi faire un CheckOut sur tous les fichiers qu’on a l’intention de modifier, de façon à signaler qu’un travail est en cours sur ces fichiers. Je crois qu’il est même possible de demander un CheckOut exclusif, mais je n’ai pas encore cherché comment faire (et honnêtement, c’est une pratique assez moyenne quand on bosse en équipe).

Conclusion

Vous voulez une ALM super fonctionnelle et facile à utiliser ? 30 minutes de boulot et vous êtes dedans, avec une seule machine avec un OS client. On n’a pas encore parler de la compilation automatique, des WorkItems, mais ça sera pour une prochaine fois. Pareil pour les tests unitaires. J’ai dit que je faisais ce projet test pour les manipuler, mais il y a assez je pense dans cet article pour vous occuper un bout de temps si vous débutez, et vous faire à quel point c’est simple à mettre en place. Dans les prochains articles, on passera à la deuxième qualité de TFS, à savoir la richesse des fonctionnalités. Si elles sont aussi simples à mettre en place que le serveur lui-même, ça promet !

Pour faire un lien avec le monde professionnel (et vous savez maintenant que c’est ce qui me motive dans ce blog), la richesse de TSF 2010 est telle que la société pour laquelle je travaille est en train de se poser la question de la migration vers cette solution. Nous avons pourtant une ALM “cousue main” sur laquelle nous avons passé des mois de développement sur les sept dernières années, mais suite à ce que j’ai vu aux TechDays et à ce que je suis en train de trouver en testant TFS, nous envisageons sérieusement de mettre une partie de ce travail à la poubelle, et d’intégrer dans TFS ce qui est spécifique à notre organisation (heureusement, il en reste beaucoup, sinon je serais vraiment dégoûté !). Apparemment, l’accès aux API, aux services et à de nombreux points d’entrées dans TFS devraient nous permettre de mettre ceci en place assez facilement. De prochains articles détailleront les étapes envisagées (puis effectuées ?) pour cette migration.

Comme ça, on sera vraiment dans ce que je souhaite réaliser sur ce blog : vous faire voir des vraies solutions, applicables à l’industrie, et même réellement appliquées dans ce cas, en tout cas je l’espère…

Posted in ALM | Tagged | Leave a comment

Revue de livre – Microsoft .NET : Architecting Applications for the Enterprise, de Dino Esposito et Andrea Saltarello

Un peu de retard dans mes blogs, mais pour tout vous dire, c’est que, suite aux TechDays, il y a tellement de nouveautés intéressantes à tester que je suis à fond dans Silverlight 4, EF4 et TFS 2010, alors les compte-rendus seront mis au propre un peu plus tard. Surtout que j’ai besoin de ces tests pour mon travail…

Par contre, je viens de finir le livre “Microsoft .NET : Architecting Applications for the Enterprise” (ISBN-13 : 978-0-7356-2609-6) de Dino Esposito et Andrea Saltarello, et je me permets de faire une critique de ce livre, qui contient de très nombreuses bonnes pistes, mais se limite parfois un peu trop à cause d’hypothèses discutables.

cat

Structure du livre

Bon, autant vous le dire tout de suite, la première partie du livre (l’architecture aujourd’hui, UML, et les patterns) ne sert quasiment à rien si vous avez un minimum de connaissances en architecture de développement. C’est vraiment très introductif, avec une description de la différence entre un architecte et un développeur (qui tourne court, d’ailleurs), les bases d’UML (qui n’est pas du tout utilisé dans la suite du bouquin, à part pour les use cases), et enfin la notion de patterns. Honnêtement, toute cette première partie est uniquement de la quadricapillectomie, et semble avoir été mise dans le livre uniquement parce que l’éditeur considérait qu’il fallait 100 pages de plus sur le livre et qu’on ne pouvait pas attaquer sans introduction.

Le vrai contenu est la deuxième partie, et là, c’est enfin un livre d’architecture qui peut servir de référence pour des cas d’utilisations bien précis. En effet, cette deuxième partie est découpée selon les tiers applicatifs. Chaque chapitre reprend les différentes couches utilisables dans une application industrielle, et détaille les différents patterns architecturaux. La limite est que le livre ne prend pas d’initiative sur les bonnes pratiques : Esposito et Saltarello présentent bien sûr l’objectif de chacune des couches, mais à mon avis de manière trop orientée, et en sautant très vite aux mises en pratique les plus habituelles.

Exemple typique : dans l’introduction au tiers d’accès aux données, les auteurs sautent directement à la conclusion que la sérialisation doit se faire dans une base de données. Pourquoi se restreindre à cette hypothèse ? C’est vrai que c’est la majorité des cas, mais j’attendais d’un livre d’architecture qu’il se place à un plus haut niveau, en énumérant les objectifs de cette couche sans présupposer du moyen de les mettre en place, car immanquablement, des idées intéressantes se perdent. Pourquoi évacuer le stockage dans des fichiers ? Pourquoi évacuer les applications qui n’ont pas besoin de persistence ? Dans des articles précédents, je vous ai parlé de la prévalence. Ca peut être la réponse à des besoins particuliers, mais si on suit les auteurs, on ne risque pas d’y penser. Dommage… Mais ça n’enlève rien à la qualité des solutions proposées, même si elles ne sont pas toujours vulgarisées.

The Business layer

Le livre (ou plutôt la deuxième partie du livre) commence par une description complète du tiers Métier. Il détaille les patterns ActiveRecord, TableModule et les approches de type Modèle de Domaine, ainsi que le TransactionScript, dont je n’avais aucune idée de l’existence auparavant.

Ce chapitre a l’avantage de comparer ces différentes méthodes du point de vue de la productivité en fonction de la complexité de l’application, ce qui est très appréciable, la plupart des livres sur le sujet se contentant de décrire les patterns et de laisser au jugement du lecteur comment choisir. En particulier, à la page 143, vous trouverez un excellent graphique montrant la supériorité du Modèle de Domaine en termes de maintenabilité sur des grosses applications.

Bon, le bouquin est censé être générique sur .NET, mais il est édité par Microsoft, quand même ! Alors évidemment, quand on parle de TableModule, c’est bien entendu les DataSets typés ADO.NET qui sont présentés. Un peu plus loin, on a droit à une citation de Castle Project pour l’ActiveRecord, donc le livre n’est pas 100% orienté Microsoft. Mais dans l’ensemble, ne vous attendez pas à des exemples génériques.

The Service layer

A mon goût le plus lent au démarrage des chapitres de cette deuxième partie. Il met dix bonnes pages à décoller, avec une loooooongue introduction sur ce qu’est un service et comment le différencier d’un objet métier. Bon, si on n’a pas compris la différence, je crois qu’on ne comprend pas la notion même de tiers applicatifs, alors autant ne pas lire le livre, non ? C’est un reproche récurrent sur ce livre, pourtant très bon : par moment, il reprend les connaissances tellement à la base que ça ne sert à rien. La majorité du contenu n’est de toute façon accessible qu’à des gens qui ont déjà un peu d’expérience en architecture informatique, alors pourquoi expliquer des notions comme à des débutants ? Ils ne pourront de toute façon pas lire la suite…

Le livre expose clairement la problématique des DTO, à mon avis. En tout cas, sa conclusion me convient bien, car elle n’est pas dogmatique. Après avoir exposé le principal (et léger) défaut du livre, voici sa principale qualité de mon point de vue : il est très proche des préoccupations industrielles (et si vous m’avez déjà lu, vous savez à quel point je me méfie de tout ce qui est technologies ou documentations non applicables à mon métier). Sur les DTOs en particulier, pas de théorie sur l’utilité ou pas de cette technologie, pas d’idée tranchée sur la nécessité d’en utiliser un pour bouchonner chaque objet métier transporté, mais une approche pragmatique avec des recommandations pour savoir quand en utiliser ou pas, quels sont les avantages et les inconvénients, et surtout l’explication d’une approche mixte très intéressante. Bref, du vrai jus de cerveau de gens qui ont déjà monté beaucoup de vrais projets, et pas les recommandations strictes d’un éminent spécialiste refusant l’idée même d’une base de données qui ne suive pas toutes les règles de normalisation (c’est du vécu, là).

Une autre partie intéressante du deuxième chapitre sur le tiers Service est la description d’une architecture SOA, et la différence d’avec une simple couche de services, en particulier en termes de contractualisation, et de compatibilité par la notion de policies. J’ai rarement vu une explication aussi claire de SOA. Pour avoir mis en place une formation sur le sujet à destination de non-spécialistes, je sais que le sujet est difficile à encadrer clairement et ce livre y arrive à la perfection. Si je refais un jour cette formation, je changerai certainement ma façon de présenter SOA à la suite de ses enseignements.

The Data Access layer

Le chapitre sur les DAL est le plus fourni de tout le livre. Clairement, il y a de quoi dire, mais je pense que c’est aussi le cas pour le Métier ou la couche de services. Surtout que, contrairement aux précédents chapitres, le livre n’apporte pas sur cette couche une vue de haut niveau montrant des solutions différentes de l’archétype DAL avec le support du mutibase, etc.

Là où ça devient intéressant, c’est quand les auteurs recensent ce qui fait le DAL lui-même, car c’est vrai que la réalisation est parfois très dur à démêler du métier, en particulier quand on commence à utiliser des procédures stockées avec du métier, par exemple. Du coup, la clarification sur les responsabilités du DAL est la bienvenue, avec le support des transactions et de la concurrence comme axes principaux. Ce genre de présentation permet de renouer avec d’autres technologies que la base de données, même si le livre ne le fait pas. En tout cas, personnellement, cela m’a permis de valider que du point de vue structurel, un module de prévalence peut bien être considéré comme un DAL à part entière.

Le livre s’attarde ensuite sur la notion d’O/RM, avec la bonne idée de ne pas prolonger la polémique sur l’intégration forte ou faible de ces frameworks dans le métier. Il présente la notion de POCO ainsi que la Persistence Ignorance.

Le démontage des mythes sur les procédures stockées (page 333 et suivante) me paraît par contre un peu abusif. Je suis moi-même personnellement opposé à leur utilisation dans les DAL, mais je trouve que les auteurs y vont un peu fort, et sont même parfois de mauvaise foi. En s’attaquant au mythe de la sécurité supérieure des procédures stockées, ils vont un peu vite en besogne, en s’appuyant sur le fait que des requêtes ad-hoc peuvent être paramétrées également, pour ne pas s’exposer à l’injection SQL. C’est tout à fait vrai, mais le problème est que c’est beaucoup moins automatique. “On peut faire aussi bien avec de l’ad-hoc, donc les SP ne sont pas meilleures”, je trouve ça un peu limite. Une personne de mauvaise foi (bon, allez, je suis qualifié…) pourrait retourner l’argumentation et déduire logiquement qu’il faut un effort pour faire aussi sécurisé avec des requêtes ad-hoc qu’avec des SP. Et je crois qu’on est plus dans le vrai, là…

The Presentation layer

Je ne suis pas assez bon en couche de présentation pour me permettre de faire des réflexions sur le contenu de ce quatrième chapitre. Toutefois, je remarque juste l’absence du pattern MVVM, ce qui est dommage car je comptais sur ce livre pour mieux comprendre cette méthode d’architecture. Je m’y suis intéressé pour des raisons de testabilité, et vu le niveau du livre, je me disais que j’allais avoir une approche de haut niveau qui allait m’apprendre plein de choses, mais il a du sortir trop tôt pour que MVVM soit dedans. On retrouve donc le classique MVC, avec à nouveau quelques digressions complètement inutiles, comme par exemple “MVC : Pattern or Paradigm ?”. Franchement, je suis plutôt du genre à couper les cheveux en quatre, mais si je présente une architecture à mes coéquipiers et que quelqu’un me demande si c’est un pattern ou un paradigme, je serais personnellement affligé…

Je trouve un peu dommage que cette partie n’insiste pas plus sur la testabilité et sur la possibilité de mise en commun des architectures Windows et Web, mais il s’agit de préoccupations personnelles, donc c’est normal de ne pas toujours retrouver exactement ce qu’on veut dans un livre.

Lois de Murphy

Bon, pour en finir avec les reproches : chaque chapitre comporte à la fin une série de proverbes du type Lois de Murphy, et qui n’ont rien, mais absolument rien à voir avec le sujet du chapitre qui les contient. C’est marrant, bien sûr (normal, c’est de l’humour d’informaticien, et les auteurs savent à qui ils s’adressent), mais ça serait beaucoup mieux si ça avait un peu plus de rapport avec le sujet de chaque chapitre…

Conclusion

Vu que je suis un râleur (mes collègues confirmeront, bien qu’anonymement pour éviter un audit de code), je me rends compte que j’ai surtout parlé des quelques points faibles du livre, mais il ne faut surtout pas que ça vous donne une idée négative de celui-ci. Si j’ai fait un compte-rendu, c’est bien parce que c’est un des meilleurs livres d’architecture que j’ai lu. En tout cas la deuxième partie. Encore une fois, honnêtement, la première ne sert strictement à rien. Si vous lisez un livre d’archi, vous connaissez déjà ça. Ce n’est pas un reproche sur le contenu, mais juste pour que vous ne perdiez pas de temps si vous le lisez.

Mais cette deuxième partie est vraiment excellente. En à peine deux cents pages, vous avez couvert toutes les problématiques des architectures informatiques, avec une approche industrielle, pratique et pas du tout dogmatique, et la plupart des patterns standards de résolution de ces problématiques, complétés par leurs avantages et leurs inconvénients. Le fait de classer tout ceci par tiers est très appréciable, car si vous avez une question d’architecture, vous pouvez assez vite retomber sur les pages qui vous intéressent.

Bref, bravo à Dino Esposito et Andrea Saltarello pour cet excellent bouquin ! C’est rare d’apprendre autant de choses en aussi peu de pages…

PS : Executive Summary

Les auteurs ont eu l’excellente initiative de résumer les points absolument essentiels de leur livre en deux pages, tout à la fin. Je ne vais évidemment pas vous donner ces dix points ici, sinon vous n’achèterez pas le livre 🙂 Mais il y en a un qui m’a toujours paru fondamental, et je tiens à le rappeler ici : “Premature Optimization is the root of all software evil”. Pour avoir personnellement fait l’expérience de cette règle, je ne peux que souscrire à sa mise en avant par les auteurs. Après avoir perdu une bonne dizaines de jours de développement à écrire un système de transformation de données en mémoire, pour me rendre compte ensuite qu’avec des fichiers sur disque, c’était non seulement plus simple mais aussi plus rapide, je me suis demandé si je n’allais pas me faire tatouer cette phrase sur le front…

Bref, pour ceux qui ne le savent pas (mais je me demande si on peut réellement le comprendre sans en avoir fait soi-même la cruelle expérience…), il ne faut JAMAIS optimiser un système qui n’est pas encore complètement stable. Une fois les prérequis fixés, les demandes d’évolution satisfaites, avec un client qui comprend qu’une phase d’optimisation coûte cher et devra être recommencée de zéro sur une prochaine version, là, oui, vous pouvez vous lancer dans l’optimisation. Mais jamais avant.

Optimiser avant que l’application soit figée, c’est comme tirer sur un lapin au canon : même si, par chance, il tombe juste devant la ligne de mire, le temps que vous tiriez, il sera ailleurs. Et si, avec encore plus de chance, il ne bouge pas et que vous le touchez, il ne sera plus en état pour en faire quoi que ce soit après…

Posted in Veille | Tagged | Leave a comment

Tech Days 2010 : A l’année prochaine…

Bon, fin des TechDays. Me voilà revenu chez moi, et je peux enfin mettre toutes ces notes en ligne, en espérant que ça servira à d’autres autant qu’à moi. En effet, le plus dur après les TechDays, quand on revient la tête pleine d’idées, c’est de retomber dans le bain du boulot au jour le jour, avec plein de choses à faire. Le risque, c’est de replonger la tête dans le guidon, et de ne pas mettre en pratique les choses qui nous ont paru importante.

Donc, objectif dans les prochaines semaines : faire des petits prototypes appliqués à un environnement industriel avec certaines des nouveautés les plus adaptées à mon travail parmi ce que Microsoft nous a présenté. J’ai commencé avec Silverlight dans le train du retour et vous aurez des nouvelles de tout ceci dans les prochains billets de ce blog.

Pour résumé, les fonctionnalités que j’ai vues et qui me paraissent vraiment importantes :

  • Gestion des crédentiels dans la pile HTTP de Silverlight.
  • Impression depuis Silverlight.
  • Le nécessaire changement de paradigme de programmation pour s’ouvrir à la parallélisation. F# est, à mon humble avis, appelé à être un pivot dans cette voie. Pas nécessairement en remplacement, mais plutôt en complément de C# pour les librairies métier.
  • RIA Services, excellent pour résoudre certains problèmes tels que la double validation client et serveur.
  • PowerPivot, analyse OLAP en mémoire avec des performances extraordinaires (100 millions de lignes traitées et affichées en 2 secondes).
  • Et encore et toujours, la sécurité qui reste un facteur de différentiation.
Posted in Retours | Leave a comment