Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Rendez-vous aux Techdays

Hello à tous, ça fait très longtemps que je n’ai pas posté ici, en fait, j'ai concentré mes efforts sur un nouveau blog en anglais :

http://www.vlaquest.com ! (bookmarkez-le si, si ! Winking smile)

Pourquoi avoir 2 blogs ?

Certains de mes billets peuvent être assez spécifiques, et j’ai peur qu’ils n’intéressent en fin de compte qu’un nombre limité de francophones et lecteurs de Codes-Sources. Ces billets là ont une meilleure place sur un canal en anglais visant l’ensemble des spécialistes. Cela ne veut pas dire que je ne reviendrai plus : au contraire ! Suite à mon silence radio sur ce canal (qui n’est pas une bonne chose je suis d’accord avec vous), je reviens avec une nouvelle dynamique et volonté d’approfondir mon expertise autour de l’accompagnement aux développements .NET (les mots clés sont ALM et Visual Studio). Au lieu de tout traduire en 2 langues, je traduirai les posts qui me semblent les plus pertinents pour une audience francophone. Quant aux sujets un peu précis, je mise sur le fait que le public averti saura les trouver et les lire en anglais ! Ne m’en veuillez pas, ce n’est pas que je considère qu’il n’y a pas de spécialistes francophones, mais Codes-Source possède une large audience et je ne veux pas “polluer” le flux principal de sujets trop spécifiques non plus.

Rendez-vous aux Techdays autour de l’ALM

Cette année je vais animer une session pour présenter les challenges ALM autour de l’eCommerce. Il s’agit d'un retour d’XP d’une grande société de eCommerce, mais j’ai un accord pour ne pas la nommer ni montrer sur quoi portent les vrais projets internes. C’est toujours bon à prendre, car nous allons passer en revue la composition des équipes, comment TFS est utilisé, les branches, les builds, et surtout les Work Items. Il y a aura des trucs, astuces et conseils. Le créneau horaire sera mercredi 13 à 17h30 (2ème jour), fin d’après-midi mais la présentation ne sera pas monotone, promis !

Microsoft TechDays - 12, 13, 14 février 2013 au Palais des Congrès de Paris

Je ne serai là que les 2 premiers jours, vous me trouverez en général au stand Sogeti (partenaire Platinum) ou au stand Ask the Expert.

Sogeti France

Pour finir quelques news perso :

  • J’ai été renouvellé MVP Visual Studio ALM pour 2013 !
  • Grâce à Sogeti, j’ai déménagé sur Bordeaux, ma ville d’origine, je retrouve avec plaisir mon pays et ma famille ! Maintenant que je suis installé, je peux mieux me concentrer sur les geekeries et autres sujets pro !

A très bientôt ! Smile

Posté le par vLabz | 0 commentaire(s)
Classé sous : , , ,

[TFS 2010] Customiser l’affichage des builds dans TFS 2010

Voici un petit tutoriel afin de montrer comment on peut étendre l’affichage des builds avec TFS 2010. Dans mon dernier billet, j’ai parlé de mon projet Codeplex qui permet d’utiliser NDepend dans les builds TFS 2010 et d’avoir un reporting approprié (c’est pas fini). Aujourd’hui j’entends montrer que la customisation de l’affichage dans les rapports de builds n’est pas compliquée, bien qu’il faille tout de même pour cela faire un Add-in Visual Studio.

Pour info, il n’est pas possible d’étendre l’affichage des builds dans la partie Web Access, c’est seulement possible dans Visual Studio (peut-être dans la prochaine version ? ;) ).

Mon point de départ a été ces 2 articles issus du blog de Jason Prickett :

Un Add-in comme enveloppe

L’affichage des rapports de build est effectué en WPF par les composants TFS (alias Team Explorer) qui étendent Visual Studio. Pour modifier l’affichage, il faut s’inscire dans le pipeline de présentation d’un rapport de build. Nous devons alors choisir entre un Add-in Visual Studio, un Package intégré, ou (nouveauté VS 2010) une Extension Visual Studio.

J’ai choisi la facilité en optant pour un Add-in car je me suis bien sûr inspiré du code des articles mentionnés ci-dessus, mais je compte tenter un jour (si cela est possible) de transformer cet Add-in en Extension Visual Studio. En effet, les extensions ont l’avantage d’être très facilement distribuables via la gallerie d’extensions et d’être installables d’un simple clic sans les opérations bizarre sur la base de registre, ce qui est moins évident pour les autres types de “plugins”. Les extensions sont de simples composants MEF.

Créer un Add-in est toutefois assez simple :

  • Utilisez le Wizard pour créer un projet de type “Other Project Types –> Extensibility –> Visual Studio Add-in”
  • Implémentez l’interface IDTExtensibility2
  • Compilez et déployez les fichiers suivants dans votre répertoire “My Documents\Visual Studio 2010\Addins”
    • votre Dll (et votre Pdb)
    • le fichier .addIn

Il existe d’autre endroits où vous pouvez déployer un Add-in mais j’ai trouvé ce répertoire le plus simple.

Dans le pipeline de présentation des build Summaries

Dans l’implémentation de IDExtensibility2, nous allons créer une instance de notre classe de présentation (ici NDependSummaryFactory) qui implémente IBuildDetailFactory, puis l’inscrire dans le pipeline de présentation (et désinscrire quand on quitte) dans les méthodes OnStartupComplete (et OnBeginShutdown) de l’Add-in.

Cette classe va faire le boulot d’affichage. A commencer par récupération des données : dans la méthode LoadData on nous passe une instance de la fameuse IBuildDetail, avec ça on est bon pour récupérer tout ce qu’on veut comme info sur le build. Y compris les nodes que l’on a placé dans les données du build.

 

Extending TFS 2010 build display - class diagram

 

Nos instances de IBuildDetailNode et IBuildDetailSection sont des structures très minimalistes, qui vont notamment véhiculer un… objet WPF !

A partir de là, vous êtes libre d’afficher d’afficher des tas de choses qui sortent de l’ordinaire ! Enfin, on peut mettre un peu de couleur et variété dans ces rapports de builds un peu moroses.

 

Exemple de section commentée

Attention, on est bien en WPF donc n’oubliez pas de définir les Handlers si vous utilisez des contrôles, ce n’est pas un Hyperlink HTML auquel on se contente de passer un URL, en l’occurrence le lien lance un process Windows qui permet d’ouvrir le navigateur par défaut sur le fichier HTML du rapport NDepend.

Il n’y pas que le build Summary

Il est aussi possible de fournir des IBuildDetailInformationNodeConverter pour que les informations du rapport de build puissent être affichées dans la partie log, dans le flux qui s’affiche, lui, en temps (presque) réel pendant les builds. Mais j’avoue que je trouve l’intérêt est limité, au départ j’avais pris cette voie pour mon Add-in, mais supprimé tout affichage customisé. Pourquoi ? Parce que les BuildMessage s’affichent déjà très bien dans l’arborescence de messages, avec la souplesse de la verbosité, aussi, je me contente volontiers de texte hiérarchique pour cette partie.

Conclusion

Voilà, tout ça pour ça vous allez me dire, hélas, la cusomisation de l’affichage n’est pas aussi simple qu’avec d’autres usines de développement (je pense notamment à CruiseControl). L’approche la plus répandue est plutôt récupérer des rapports de compilation, de tests unitaires, de couverture de code, d’analyse statique etc., au format XML et d’appeler des fichiers XSL (dont vous laissez bien-sûr aux autres et aux fournisseurs de ces outils le soin de les élaborer) pour les convertir en blocs HTML. Un rapport de build plus classique est une aggrégation de blocs HTML. Il suffit d’importer le bon fichier XSL, pas besoin de code. Je trouve que le jeu en vaut néanmoins la chandelle avec TFS, surtout si le terrain a été un peu débroussaillé. J’espère que l’on verra fleurir des Add-ins ou Extensions qui vont enrichir nos rapports TFS un peu “rigides”.

Pour le détail du code, ou bien pour créer vos propres Add-ins, n’hésitez pas à réutiliser mon code.

Hope this helps.

Posté le par vLabz | 0 commentaire(s)
Classé sous : , , , ,

Intégration de NDepend dans TFS 2010 sur codeplex

J’ai finalement créé un projet open source pour intégrer NDepend dans les builds de TFS 2010 : http://ndependtfs.codeplex.com

Contenu du projet

Dans ce projet (attention c’est une beta) vous trouverez :

  • Le code de l’activité de Workflow NDependActivity à utiliser dans les builds TFS 2010 pour appeler NDepend et journaliser les données dans les rapports de build
  • L’Add-in pour Visual Studio qui permet d’afficher les données issues du build dans une nouvelle section du build Summary :

image

L’activité de build

Il s’agit d’une nouvelle activité NDependActivity dont le rôle est simplement de lancer NDepend.console.exe au lieu de faire un InvokeProcess comme j’avais décrit dans un billet précédent (et aussi ici).

L’avantage est d’avoir une solution plus intégrée et moins de travail à faire sur le workflow pour lancer NDepend.

L’autre activité est toujours NDependDataLog qui permet journaliser les infos NDepend dans les structures de données des rapports de builds. Cependant, elle est appelée automatiquement par la 1ère et peut être désactivée par une option.

Les 2 solutions marchent aujourd’hui :

  • NDependActivity tout court
  • InvokeProcess + NDependDataLog

J’ai utilisé la composition cette fois-ci pour écrire mon activité. N’hésitez pas à jeter un oeil au code, c’est un type de programmation un peu particulier, assez déclaratif.

L’Add-in pour Visual Studio

C’est lui qui est reponsable d’afficher le NDepend Summary que vous voyez ci-dessus.

Il pioche donc dans les données journalisées en tant que records dans les builds et les affiche en WPF (puisque Visual Studio s’appuie maintenant principalement sur WPF).

La suite

Je vous décrirai prochainement comme écrire ce genre d’Addin (en attendant vous avez toujours le code). Je m’attaquerai aussi à un plus gros morceau à savoir le warehouse adapter qui permettra d’acheminer les données vers le Warehouse de TFS afin de les utiliser dans des rapports d’historique.

Posté le par vLabz | 0 commentaire(s)

[TFS 2010] enrichir les données d’un build

Toujours dans le but d’intégrer NDepend dans TFS et par la même occasion de fournir un exemple d’extensibilité des builds de TFS 2010 et de Visual Studio 2010, nous allons aujourd’hui réaliser une étape simple qui consiste à écrire le résultat de l’analyse NDepend dans les données du Build.

Comment sont stockés les builds de TFS 2010

Les builds et leurs rapports comme toute donnée dans TFS sont stockés dans des bases SQL Server. Pour chaque build on retrouve une arborescence de build records. Ces derniers peuvent être de types variés mais le plus répandu est le BuildMessage. Rien ne vous interdit d’écrire vos propres données dans cette arborescence générique d’enregistrements.

Comme les builds s’exécutent dans des Workflow WF4, Team Build 2010 utilise le mécanisme de tracking intégré à ce dernier pour journaliser les informations remontées par les activités qui s’exécutent. Il suffira d’utiliser la classe conteneur BuildInformationRecord et les informations seront écrites en base. La structure en arbre découle naturellement de celles des activités du Workflow à l’exécution.

Vous trouverez plus de détails à ce sujet sur le blog de Patrick Carnahan (MS Corp) : TFS 2010 – Customizing Build Information (Part 1).

Au final, notre but est de lire le contenu du rapport NDepend généré pendant le build et d’écrire les données dans un record du build.

 

image

 

Ces données seront ainsi disponibles pour de futurs usages :

  • Enrichissement du rapport de build
  • Enrichissement du Warehouse de TFS pour le reporting

Implémentation

Nota bene : le code fourni ici est minimaliste mais fonctionnel. Je prévois de créer un projet CodePlex pour partager la solution et créer petit à petit une solution clé en main, qui pourra aussi servir de base à l’intégration d’autres outils.

Voici la classe DTO qui représente les données remontées de NDepend.

    public class NDependReportInfo
    {
        public int NbSourceFiles { get; set; }
        public int NbLinesOfCode { get; set; }
        public int NbLinesOfComment { get; set; }
        public decimal PercentageComment { get; set; }
        public int NType { get; set; }
        public int NClass { get; set; }
        public long NILInstruction { get; set; }
        public int NNamespaces { get; set; }
        public decimal PercentCodeCoverage { get; set; }
        public decimal PercentPublicType { get; set; }
    }

Ci-dessous la classe sans prétention non plus qui permet de remplir ma classe DTO à partir du rapport (je voulais faire une déserialisation directement mais le format XML du rapport NDepend ne m’a pas permis de le faire via l’outil xsd.exe) :

    public class NDependReportReader
    {
        private XDocument _doc;
        public NDependReportReader(string reportPath)
        {
            _doc = XDocument.Load(reportPath);
        }
        public NDependReportInfo GetReportInfo()
        {
            var info = new NDependReportInfo();
            var metrics = _doc.Descendants("ApplicationMetrics").First();
            var nbLines = metrics.Attribute("NbLinesOfCode").Value;
            return new NDependReportInfo
            {
                NbSourceFiles = Convert.ToInt32(metrics.Attribute("NbSourceFiles").Value),
                NbLinesOfCode = Convert.ToInt32(metrics.Attribute("NbLinesOfCode").Value),
                PercentPublicType = Convert.ToDecimal(metrics.Attribute("PercentPublicType").Value, CultureInfo.InvariantCulture),
                NbLinesOfComment = Convert.ToInt32(metrics.Attribute("NbLinesOfComment").Value),
                NClass = Convert.ToInt32(metrics.Attribute("NClass").Value),
                NILInstruction = Convert.ToInt64(metrics.Attribute("NILInstruction").Value),
                NNamespaces = Convert.ToInt32(metrics.Attribute("NNamespaces").Value),
                NType = Convert.ToInt32(metrics.Attribute("NType").Value),
                PercentageComment = Convert.ToDecimal(metrics.Attribute("PercentageComment").Value, CultureInfo.InvariantCulture),
                PercentCodeCoverage = Convert.ToDecimal(metrics.Attribute("PercentCodeCoverage").Value, CultureInfo.InvariantCulture)
            };
        }
    }

 

On arrive à la partie intéressante, il s’agit d’une activité custom WF4 pour Team Build. C’est une code activity donc 100% code. Elle lit simplement les données du rapport et enregistre une instance de notre classe NDependReportInfo dans la structure des records du build.

 

    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class NDependDataLog : CodeActivity
    {
        /// <summary>
        /// Le seul argument de notre activité est le chemin vers le rapport NDepend
        /// </summary>
        public InArgument<string> ReportPath { get; set; }
        protected override void Execute(CodeActivityContext context)
        {
            string reportPath = context.GetValue(this.ReportPath);
            context.TrackBuildMessage("Report path " + reportPath);
            if (String.IsNullOrEmpty(reportPath))
            {
                context.TrackBuildWarning("No NDepend report specified");
            }
            else
            {
                if (!File.Exists(reportPath))
                {
                    context.TrackBuildError("NDepend report file " + reportPath + " not found");
                }
                else
                {
                    var reader = new NDependReportReader(reportPath);
                    var buildDetail = context.GetExtension<IBuildDetail>();
                    var info = reader.GetReportInfo();
                    context.Track(new BuildInformationRecord<NDependReportInfo>
                    {
                        Value = info
                    });
                    context.TrackBuildMessage("Report file successfully processed");
                }
            }
        }
    }

Les points clés :

  • context.GetExtension : c’est le moyen dans WF4 de récupérer un service ambient depuis le Workflow, pour les builds TFS on dispose ainsi d’un IBuildDetail qui est notre point d’entrée pour interagir avec le build en cours.
  • Track : on crée un BuildInformationRecord en passant l’instance de notre NDependReportInfo à son champ Value. Le Tracking participant qui analysera notre structure utilisera la réflexion pour le convertir en un dictionnaire de <String, String> (des clés / valeurs) qui seront stockées dans la base
  • TrackBuildMessage : c’est une “method extension” présente dans les assemblies de TFS qui enrichit le CodeActivityContext de WF4 et permet d’écrire des messages dans le Log de build de manière conviviale.

Pour compiler il vous faudra notamment les références :

  • C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0
    • Microsoft.TeamFoundation.Build.Client.dll
    • Microsoft.TeamFoundation.Client.dll
    • Microsoft.TeamFoundation.Common.dll
  • C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies
    • Microsoft.TeamFoundation.Build.Workflow.dll

Vérification dans la base

Disclaimer : ne vous aventurez pas à modifier des données en base directement, vous perdrez le support de Microsoft pour votre TFS, vous êtes prévenu, on utilise cette requête juste pour comprendre et vérifier que cela marche.

SELECT b.BuildNumber, bi.ParentId,  bif.*
FROM 
[Tfs_DefaultCollection].[dbo].[tbl_Build] b,
[Tfs_DefaultCollection].[dbo].[tbl_BuildInformation] bi,
[Tfs_DefaultCollection].[dbo].[tbl_BuildInformationField] bif
WHERE b.BuildId = bi.BuildId AND bi.NodeId = bif.NodeId
and BuildNumber = 'NDependBuild1>20110922.9\'
-- le nodetype va varier, il faut d'abord le déterminer
and bi.NodeType = 16

 

image

 

Lors de futurs billets nous verrons comment exploiter ces informations, à suivre !

Posté le par vLabz | 3 commentaire(s)
Classé sous : , , ,

Intégration de NDepend dans TFS 2010 – breaking the build

J’ai présenté dernièrement comment lancer une analyse NDepend au sein d’un workflow de build TFS 2010. Cette intégration dans TFS 2010 en plusieurs étapes que je vous propose peut très bien s’appliquer à d’autres produits que NDepend, j’ai choisi NDepend car c’est un excellent outil qui apporte une grande valeur ajoutée aux builds de Team Foundation Server.

 

Des règles critiques pour lever des alertes…

Outre les statistiques et métriques sur le code qu’il sait calculer, une des forces de NDepend est de pouvoir exécuter des règles représentant des exigences sur le code, les fameuses “CQL rules” (Code Query Language). Elles sont réparties en catégories (qualité, design, performance, effets de bord, nommage, etc.) et permettent de mettre en évidence les bouts de code qui ne les respectent pas.

image

Certaines de ces règles sont dites “critiques” et leur rôle est de lever une alerte suffisamment forte pour générer une erreur dans un build ou une analyse automatisée. Je vous propose de prendre en compte ces alertes de deux manières différentes et de faire évoluer notre Workflow de build en conséquence.

Pour cela, vous devrez éditer votre fichier .ndproj et cocher les règles que vous souhaitez rendre critiques, celles qui vont lever une erreur dans le build. La documentation de NDepend est très claire à ce sujet.

image

Dans VisualNDepend, cochez l’icône rouge à droite pour déclarer une règle comme “critique”

 

 

Et casser le build…

En effet, il est sain et même important de se mettre des barrières concrètes dans un build :

  • Erreurs sur les tests unitaires
  • Couverture minimale de tests unitaires
  • Duplication de code
  • Règles de qualité, conventions, bonnes pratiques non respectées (analyseurs statiques)

Cela permet de sonner l’alarme et dès qu’un problème est détecté, et si vous avez mis en place un build d’intégration continue, le vice sera détecté au plus tôt et donc plus facile et moins coûteux à corriger. On le sait bien, quand on laisse ce genre de problème traîner, ils ne sont généralement jamais corrigés…

Avec TFS 2010 et TeamBuild, deux résultats sont donc possibles selon votre préférences :

  • Build en erreur : on lève une erreur qui place le build en erreur et stoppe l’exécution de la séquence en courante dans le workflow (cf l’icône rouge de type “Stopper”)

image

 

 

  • Build partiellement réussi (partially succeeded) : on lève une erreur qui sera mise en évidence mais le build continue de s’exécuter tant qu’il n’y a pas d’autre erreur (cf l’icône mi-verte, mi-rouge un peu déroutante au début car il s’agit d’un état intermédiaire)

image

 

 

 

On les retrouve notamment dans la liste des derniers builds :

 

image

A vous de voir si vous préférez être permissif ou pas auprès des équipes de développement.

 

Implémentation

Revenez au Workflow de build que nous avons implémenté pour lancer NDepend. Le rajout de l’alerte est très simple, nous allons rajouter une activité If qui se contentera de lever une Exception ou d’afficher un message selon le cas.

Solution 1 : mettre le build en échec

 

image

Après la tâche InvokeProcess qui lance NDepend placez les activités suivantes :

  • If
    • Display : If NDepend Rules are Satisfied
    • Condition : ndependResult = 0
    • Then
      • WriteBuildMessage
        • Importance : Normal
        • Message : "NDepend rules successfully passed"
    • Else
      • Throw
        • Exception : New Exception("Some NDepend critical rules are unsatisfied. Please look at the NDepend report for more details.")

 

Solution 2 : placer le build en état de succès partiel

C’est la même solution que ci-dessus, à la différence près qu’on utilise une activité WriteBuildError au lieu d’un Throw :

image

  • WriteBuildError
    • Message : "Some NDepend critical rules are unsatisfied. Please look at the NDepend report for more details."

 

Résultat

Dans le résumé (Summary) du build, on ne fait pas de différence entre les deux solutions :

image

 

Tandis que dans le log, on trouve bien le Throw pour la solution 1:

image

 

Et pour la solution 2, le message du WriteBuildError :

image

Le build de la solution 2 est alors bien marqué comme partially succeeded :

image

 

Voilà, il ne vous reste plus qu’à adapter les règles NDepend à vos besoins. Votre build sera alors le chien de garde de la qualité de votre solution !

Nous aborderons prochainement comment mieux intégrer les résultats de NDepend dans TFS, à suivre !…

Posté le par vLabz | 0 commentaire(s)
Classé sous : , , ,

Intégration de NDepend dans TFS 2010 - Partie 1

De retour après un petit moment de silence, les aléas de la vie…

Bref, j’ai prévu de vous parler de NDepend et surtout de comment on va pouvoir l’intégrer dans TFS 2010. Intégrer veut dire : lancer l’outil pendant les builds, récolter les résultats et les intégrer dans les bases de données de TFS et éventuellement dans les rapports de build, mais aussi produire des rapports qualimétriques en correlation avec les builds. Du pain sur la planche en somme, et je vous propose de parcourir cela ensemble.

Pourquoi NDepend ?

Je ne suis certes pas le 1er à parler de cet outil (au passage made in France par Patrick Smacchia), en quelques mots, il permet d’analyser vos assemblies et vos sources et afin de vous fournir des statistiques mais surtout d’appliquer des règles de qualité que vous pouvez définir vous mêmes grâce à un langage intégré. C’est donc le compagnon incontournable à mon avis de tout développement un peu sérieux qui vous permettra de mettre le doigt les zones de douleur dans votre code, ou de vérifier que vous avez bien séparé vos couches par exemple.

Entrées et sorties de NDepend

En entrée, NDepend prend donc vos assemblies et vos sources. Afin de pouvoir paramétrer l’analyse on utilise des fichiers .ndproj par analogie avec Visual Studio. L’analyse peut être lancée en ligne de commande, ou bien depuis Visual NDepend qui vous affichera de nombreux écrans interfactifs avec la possibilité de zoomer et de filtrer les axes qui vous intéressent. Nous nous intéresserons d’abord à la génération des rapports NDepend depuis les builds de TFS 2010.

Customiser le Workflow de Build

La 1ère étape de notre petit périple consiste à lancer NDepend au cours de chaque build. Cela va produire un rapport au format HTML que l’on va stocker dans le répertoire de sortie du build, ainsi, si l’on efface le build, le rapport sera jeté avec.

Je ne vais pas m’étendre sur la partie modification de build, d’autres ont réalisé de très bons tutoriaux. Vous avez également la “guidance” qui a été produite par les ALM Rangers il n’y pas plus de 2 semaines et qui est incontournable si vous voulez comprendre les builds en profondeur.

image

 

Instructions détaillées

 

Je suis parti du Workflow de build standard DefaultTemplate.xaml.

Commencez par déclarer RunNDependAnalysis et NDependConsolePath comme variables globales.

 

image

 

Insérez un statement If nommé IfCallNDepend dans l’activité de parallélisation “Get Impacted Tests,…” afin de pouvoir faire tourner l’analyse NDepend en parallèle d’autres traitements post-compilation.

 

image

 

A l’intérieur, collez le bloc “If BuildSetings.HasProjectsToBuild” que vous trouverez à l’intérieur de la séquence “Compile and Test” qui se produit dans l’étape majeure précédente du build (cf image ci-dessous). Nous allons la modifier et l’enrichir.

 

image

 

Renommez les étapes “Try to Compile the Project” "en “Try to Call NDepend”, et aussi  “Compile the Project” en “Call NDepend”.

Puis déclarez les 3 variables suivantes dans Call NDepend :

  • ndependProject (String)
  • ndependResult (Int32)
  • ndependConsolePathExpanded (String)

 

image

 

Maintenant, insérez les éléments manquants dans la séquence Call NDepend pour qu’elle ressemble la version présentée sur l’image, vous devrez rajouter une affectation, une écriture dans le log, une résolution de variable d’environnement, et une invocation de process. Le paramétrage et le détail sont fournis plus bas.

 

image

Convert Server Path to Local Path : ne rien changer

Assign : ndependProject <- localProject.Replace(".sln", ".ndproj")

On cherche un fichier ndproj du même nom que la solution.

WriteBuildMessage : "NDepend projet to build " + ndependProject

ExpandEnvironmentVariables :

  • Input : NDependConsolePath
  • Output : ndependConsolePathExpanded

Permet d’utiliser des variables d’environnement dans le paramètrage du build pour indiquer le chemin vers NDepend.Console.exe.

InvokeProcess :

  • Arguments : """" + ndependProject + """ /OutDir """ + System.IO.Path.Combine(BinariesDirectory + "\NDependOut") + """"
  • FileName : ndependConsolePathExpanded
  • Result : ndependResult
  • Handle Standard Output : stdOutput
    • WriteBuildMessage : stdOutput
  • Handle Error Output : errOutput
    • WriteBuildWarning : errOutput

On lance l’analyse via le fichier .ndproj, et la sortie sera effectuée au même endroit que la sortie du build.

 

Lancement du build

Voilà le tour est joué, archivez votre nouveau workflow de build et créez une nouvelle définition de build basée dessus.

Vous pouvez paramétrer le chemin du programme NDepend.Console.exe au niveau de la définition de build.

 

image

 

Avant de lancer le build, vous devrez créer un fichier .ndproj que vous archiverez à côté de votre fichier solution :

  • “Ma Solution.sln”
  • “Ma Solution.ndproj”

A la fin du build, vous trouverez le rapport très facilement à côté de vos binaires (Open Drop Folder) :

 

image

 

Et voilà le travail dans le sous-répertoire NDependOut :

 

image

 

Lors de prochains articles, nous irons plus loin en intégrant les métriques générées dans les données du build pour une exploitation ultérieure avec TFS 2010 et, à terme, le reporting. A suivre…

Posté le par vLabz | 2 commentaire(s)
Classé sous : , , ,

Développer avec Eclipse et TFS 2010, les démos…

Ma session animée avec Guillaume Rouchon et Xavier Warzee aux derniers Techdays 2011 est en ligne :

Développez en Java avec la plateforme TeamFoundation Server 2010

Nous faisons de nombreuses démonstration sur l’utilisation d’Eclipse (d’ailleurs titre aurait presque dû être “Développez avec Eclipse sur Team Foundation Server 2010”) dans un contexte où l’on utilise Team Foundation Server 2010 comme contrôleur de sources, et plus généralement comme plate-forme ALM. Cela s’opère grâce au plugin Eclipse Team Explorer Everywhere 2010 (dont Etienne vous a déjà parlé ici), développé en Java par Microsoft. Un produit qui sort donc du moule Microsoft habituel (surtout quand on regarde les system requirements) !

Le contenu

Le message est simple : TFS est une “bonne” plate-forme pour intégrer de nombreuses technologies, et être ainsi le support de process ALM unifiés au sein de l’entreprise. Les gains sont évidents : homogénéité, cohérence, moins de processes différents, moins d’outils différents, reporting globalisé.

Nous présentons de nombreux cas d’utilisations du gestionnaire de sources, des éléments de travail au sein d’une machine Linux et d’une machine Windows qui ont chacune un ou plusieurs environnements de dev (Eclipse, Visual Studio) pour simuler la concurrence :

image

Notre scénario savamment élaboré par Guillaume en particulier, fait intervenir de multiple technologies, on retrouve :

  • Un Web Service développé en Java, avec ses tests unitaires
  • Un site Web développé en PHP
  • Un composant Silverlight intégré dans le site PHP

Le tout est bien sûr intégré dans Team Foundation Server 2010.

Un build multi-technologies

C’est là que Xavier nous a bien aidé pour concocter un petit script de build qui fait le maximum puisqu’il permet d’adresser ces trois technologies à la fois. Le principal de la logique de build est implémenté en maven : compilation et tests Java, compilation Silverlight, et déploiement du site final en PHP !

 

Je vous laisse le soin de regarder la vidéo pour plus de détails et de surprises quand à la qualité de l’intégration TFS côté Eclipse, certaines petites fonctionnalités ne sont d’ailleurs pas dans Visual Studio !

Posté le par vLabz | 1 commentaire(s)
Classé sous : , , ,

Disques virtuels sous Windows 7 – VHD goodness

Voici une petite astuce qui pourra peut-être vous être utile. Le principe est d'utiliser des VHDs (Virtual Hard Disk) pour stocker des données volumineuses mais peu souvent utilisées et de "mapper" le disque virtuel dans un répertoire de votre disque principal grâce à la fonction Attach VHD de Windows 7. Les fichiers apparaissent bien dans votre répertoire mais les accès sont redirigés vers le disque virtuel qui peut être ailleurs.

image

 

Orgueil et préjugés

En fait, cela part d'un préjugé lorsque j'installe des training kits, des labs, ou que je décompresse des exemple de projets avec sources, cela fait un bon paquet de fichiers microscopiques. Je suis psychologiquement plus zen de savoir tout ce "bazar" confiné dans un espace disque à part que sur ma partition principale.

clip_image001

Ici, les fichiers apparaissent dans C:\Labs, cependant ils sont stockés réellement dans un disque virtuel (fichier .vhd) qui peut être situé n’importe où ailleurs sur C: ou sur un autre volume.

Une meilleure raison pour faire cela est l'aspect "nomade" de nos configurations. Votre VHD avec toute votre base de code sera peu volumineux (quelques Gigas) et vous pourrez l'embarquer sur une clé, pour l'utiliser comme référence sur un autre poste, ou bien pour le rendre accessible depuis plusieurs de vos machines virtuelles et travailler sur une même base de code.

Il y a aussi l'aspect sauvegarde, car recopier un gros fichier VHD de 1Go c'est tellement plus commode et performant que 20000 petits fichiers, on n'hésite plus à sauvegarder ce fichier fréquemment.

Rien d'indispensable donc, mais je suis plutôt content depuis que je suis passé sur système de "conteneur".

image

J'utilise donc un VHDs que j'ai nommé "Labs" pour stocker :

  • Mes projets de développement
  • Des trainings kits
  • Des exemples de code et ateliers
  • Des sources de projet Open Source
  • Toute documentation à base de nombreux fichiers (HTML)

Je n'y mets que du contenu portable (autonome).

 

Un volume virtuellement illimité

Une vraie bonne raison de pratiquer ce mode de stockage est le gain de place sur C:, car on peut alors étendre la taille de son disque C: au fur et à mesure du besoin en place.

J'utilise un SSD comme disque principal, et sa taille est très limitée (vu le prix !). Utiliser des VHD montés sur le volume C: me permet d’avoir un seul volume contenant l’intégralité de mes fichiers. Je n’ai pas à morceller logiquement mes données ou programmes sur plusieurs volumes.

En effet, j'ai commencé à installer un ou deux jeux sur mon système, mais je ne veux pas que les jeux prennent de la place sur mon SSD bien mieux utilisée par des VM. Au lieu d’installer les jeux sur D:, j’ai préféré n’avoir qu’un seul volume logique pour tout mon système. J’ai pu déporter le stockage des jeux sur D: en les faisant virtuellement apparaître sur C:. Je pourrai les remettre sur C: de manière transparente pour mes logiciels et mon système le jour où j’aurai un disque plus important. Souplesse, et pérennité de la configuration donc…

Remarque: si le disque n’est pas attaché, cela m’empêche juste de lancer les jeux

 

Mise en place

Côté pratique, j'utilise Windows 7 pour "monter" ces disques dans mon système de fichier. Il suffit d'utiliser le Disk Management pour cela (commande "diskmgmt.msc") et vous pourrez créer, attacher, détacher, assigner une lettre à un VHD attaché etc.

Lorsque vous attacherez la 1ère fois un nouveau disque, le Disk Management vous proposera si vous voulez l’utiliser comme un nouveau lecteur (E:, F: etc.) ou bien le “monter” dans un répertoire de votre système de fichiers.

clip_image003

Ici, j'ai deux disques virtuels Labs et Games, qui ne me prennent que quelques Gigas chacun en taille réelle et qui sont mappés respectivement sur C:\Labs et C:\Games.

Il est ainsi assez simple de déplacer un répertoire volumineux sur un autre disque. Voici comment par exemple stocker le contenu de C:\Games sur le lecteur D :

  • Je renomme mon répertoire C:\Games => C:\tempGames
  • Je crée un répertoire vide "Games"
  • Je crée un VHD nommé "Games.vhd" sur mon disque D: et je l’attache à C:\Games
  • Je déplace le contenu de tempGames vers C:\Games et cela remplit mon VHD sur D:

Résultat : un gain de place sur C: et les jeux restent installés de manière cohérente.

 

Attacher automatiquement les disques au démarrage

Problème : il manque la case à cocher pour réattacher un disque virtuel à chaque démarrage !

Solution : une tâche programmée qui se déclenche à chaque démarrage de votre PC et qui lance "diskpart.exe" afin d'automatiser le montage de vos disques.

 

Créez un fichier texte avec les commandes diskpart suivantes (selon vos disques) : 

select vdisk file="C:\VHDs\labs.vhd"
attach vdisk 
select vdisk file="D:\VHDs\Games.vhd" 
attach vdisk

Puis définissez la tâche programmée :

image

Configurer la tâche pour se déclencher au démarrage du système par exemple (Trigger at System Startup), et faites-lui lancer l’action suivante :

image

 

 

Cette petite logistique est plutôt simple à mettre en place et j’en suis assez satisfait. Utilisez-vous cette fonctionnalité des VHD dans Windows 7 ?

Posté le par vLabz | 3 commentaire(s)
Classé sous : ,

Un nouveau MVP sur Visual Studio ALM !

Ca y’est j’ai été nominé MVP et ça fait rudement plaisir de commencer l’année avec une telle nouvelle qui tombe dans votre boîte mail !

Après donc 11 ans de loyaux services avec les technologies Microsoft et plus récemment mon implication dans la communauté, les événements, la presse, j’obtiens ce statut prisé pour les uns, mystérieux ou inconnu pour d’autres (notamment les non-microsoftiens), et ce dans mon domaine de prédilection à savoir l’ALM (donc le SDLC => gestion du cycle de vie des applications).

image

Pour l’anecdote, je repense à ma première usine de build en .NET 1.0 il y a dix ans de cela, je ne voulais pas installer Visual Studio sur le serveur qui allait servir à tout compiler et packager (c’était un vrai risque à l’époque), et j’avais pourtant besoin d’automatiser les choses pour notre équipe, j’avais écrit un gros VBScript dans une tâche programmée, qui posait un label dans VSS, allait chercher les sources, lisait les options dans les projets Visual Studio et les reproduisait sur la ligne de commande (csc.exe) pour compiler des solutions entières, car les fichiers projets proj n’était pas encore au format XML (pas de MSBuild). On pouvait alors générer une version livrable du projet avec très peu d’efforts et de manière assez propre… Depuis les choses ont bien évolué, la plate-forme .NET s’est dotée d’outils, Microsoft ou pas (NAnt, MSBuild, TFS, Cruise Control, Gemini, etc.), et nous pouvons nous concentrer de plus en plus sur les besoins eux-mêmes que sur les outils.

Une consécration ? la récompense ultime ? non !!! Je le prends avant tout cette nomination comme une réelle source motivation pour la suite des choses, et surtout comme un challenge, car il va falloir être à la hauteur des espérances de ceux avec qui l’on travaille, et prouver sur le terrain que la compétence colle avec le titre, bref du boulot en perspective, car l’ALM, Visual Studio 2010 et TFS, l’agilité, ce sont des sujets vastes et pas pour autant moins passionnants !

Ce qui est donc sûr c’est qu’il y a encore du chemin à parcourir ! :)

Posté le par vLabz | 5 commentaire(s)
Classé sous :

Petit point sur la relance d’une exception

Voici un bref comparatif de plusieurs techniques pour relancer une exception et diverses options pour remédier à la perversion de la Stack Trace provoquée par l’opération.

Technique 1 : throw ex

try
{
    int result = MoteurCalcul.Calculer(10, 0);
}
catch (Exception ex)
{
    throw ex;
}

C’est la pire des solutions, l’exception a une nouvelle origine et l’on perd donc les informations de pile (stack trace) liées à l’exception d’origine.

Technique 2 : throw

try
{
    int result = MoteurCalcul.Calculer(10, 0);
}
catch (Exception ex)
{
    throw;
}

2 caractères en moins, mais qui font la différence. On garde l'historique de la stack trace, sauf pour la ligne d'où à été fait l'appel au sein du try : à la place on a la ligne d'où a été relancée l'exception dans le catch correspondant. Cela peut être gênant quand on a un gros bloc try qui appelle plusieurs fois la même méthode.

Technique 3 : throw new MyExcpetion(“blahblah”, ex);

try
{
    int result = MoteurCalcul.Calculer(10, 0);
}
catch (Exception ex)
{
    throw new MyException("Muhahahaha", ex);
}

Si l'on relance une nouvelle exception avec l'exception originale en tant qu’InnerException, on a toute la trace exacte concernant l'exception originale + celle de la nouvelle exception.

Technique 4 : framework underground

Si l'on veut faire un rethrow de l'exception originale sans altérer la stack trace (et donc faire comme-ci l'exception n'avait pas été interceptée), on peut invoquer la méthode privée InternalPreserveStackTrace sur l'exception avant de la relancer (donc par réflexion), ou bien régler son champ privé _remoteStackTraceString.

Attention jeu dangereux, vous trouverez néanmoins le code dans le blog de Fabrice Marguerie avec en prime des explications détaillées sur le contenu de la stack trace (des exemples de dump de pile). Je rajouterai par précaution un test sur la MethodInfo afin de ne l’invoquer que si elle existe bel et bien (on ne peut pas savoir comment le framework va évoluer, et même, on ne veut pas savoir).

Enfin il existe une manière portable mais coûteuse de faire l'équivalent en utilisant une sérialization et désérialisation cross-domain ce qui préserve la stack trace originale avant de refaire le throw. Toute l’histoire ici.

Conclusion

On arrive malheureusement à un point où la technique va influencer des choix potentiellement fonctionnels. Mon avis qui n’engage que moi :

  • Si on n’a pas une vraie valeur ajoutée à apporter à l’exception originale => ne pas l’intercepter ! Au temps des langages sans système d’Exception, on devait passer 60% du temps à gérer des codes d’erreurs, je comprends qu’on ait souvent le réflexe de vouloir intercepter au maximum, mais il faut apprendre à s’abstenir dans certains cas. Si c’est pour du logging, se poser la question du qui journalise quoi, souvent on retrouve le logging au niveau le plus haut… n’est-ce pas plus naturel et préférable ainsi ?
  • Dans le cas où l’on apporte une valeur (sémantique ou technique) à l’exception originale, préférer lancer une nouvelle exception que l’on aura nous-mêmes définie avec l’exception originale en InnerException. Dans ce cas, prévoyez des modules de logging et des catch parents un poil intelligent pour savoir dépioter toutes les InnerExceptions (récursivité), on gagne en complexité…
  • Le throw tout court est une bonne solution de compromis quand le bloc try est court ou n’a pas plusieurs appels à une même méthode. L’important est de pouvoir retrouver le chemin d’exécution dans la stack trace et cela reste aisé dans ce cas.
  • Je ne saurais recommander d’utiliser la technique qui permet de préserver la stack trace même s’il est bon de savoir que c’est “possible”. La formule est néamoins tentante, elle marche avec les frameworks 2.0 à 4.0. Rendre cet appel paramétrable par config peut être un garde fou (car même si la méthode existe encore en framework 5.0, on n’est pas à l’abri d’un effet de bord !).
  • Quand à la sérialisation cross-domain, c’est intéressant à comprendre, mais côté application, c’est trop coûteux à mon sens pour présenter un réel intérêt.

Et vous ? Plutôt throw, throw new ?

Posté le par vLabz | 3 commentaire(s)
Classé sous :

Team Foundation Server dans Azure : de nouvelles perspectives…

Suivant la PDC de loin comme la plupart d’entre nous, j’ai pu néamoins suivre les démos de Brian Harry et l’annonce concernant le chantier entamé par Microsoft depuis plus de 7 mois pour faire tourner TFS dans Azure. C’est effectivement une excellente nouvelle pour ce que cela apportera aux utilisateurs de TFS mais également pour Azure car TFS est un produit presque idéal (en terme d’architecture et de fonctionnalités) pour être sujet à tourner dans le Cloud made in Microsoft.

Brian Harry a donc montré comment l’on pouvait se connecter aux Team Projects qui sont hébergés dans Azure. C’est encore au stade expérimental mais cela ouvre des perspectives de plus intéressantes !

Prêt à l’emploi

Plus la peine de passer une demi-journée à vérifier les pré-requis et à installer la plate-forme. Avec le cloud, TFS est prêt à l’emploi : c’est une question de minutes voire de secondes pour créer son projet sans rien avoir à déployer au préalable !

TFS anywhere

Simple mais efficace, par nature le cloud est accessible à tout le monde sur le net, donc pas de prise de tête à configurer les accès extérieurs !

Open Ids

Grâce à l’AppFabric Access Control service on ne sera plus limité à des comptes Active Directory, on va pouvoir utiliser nos comptes internet basés sur les standard de fait (LiveId, Google Id, Facebook, ou même un identifiant propre à notre société).

Transparence pour les outils clients

Côté utilisation, on peut voir que Team Explorer marche de manière transparente pour manipuler les Work Items, les projets Visual Studio, effectuer des Checkins. Ce qui m’a impressioné c’est le Build dans un VM Azure dédiée (le Role VM de Windows Azure) là encore de manière complètement  transparente. Si votre application a une configuration suffisamment standard (pas de dépendence trop exotique) il ne sera pas nécessaire de réquisitionner une VM dédiée dans Azure, un simple Worker Role Azure suffira.

Tous les clients sont annoncés comme supportés : Test manager pour les test plans et les tests cases, et également Eclipse ! En revanche, pas un mot sur Lab Management, il ne sera donc peut-être pas dans le scope des premières offres qui seront proposées… Il y a pourtant matière puisque rappelons que Lab Management est dédié à la virtualisation des tests et qui dit virtualisation… Bref, à suivre !

De l’Azurisation de TFS

Les choix d’archicture à la base de TFS et les récentes évolutions pour la version 2010 ont permis que ce portage dans Azure soit en fin de compte un chantier plutôt mineur. Pour s’en convaincre, vous pouvez consultez les explications que Brian Harry nous a livrées pour l’occasion. Il en ressort par contre qu’une fois le portage effectué, la transformation de TFS en un véritable service 24/24 et 7/7 est un casse-tête ardu. La session à venir dédiée au portage de TFS dans Azure nous en dira plus !

Une Community Technical Preview doit venir pour 2011, on l’attend avec impatience !

Posté le par vLabz | 2 commentaire(s)
Classé sous : , , ,

Lancement du User Group ALM France chez Microsoft

Une petite annonce à propos d’un nouveau groupe qui va se lancer autour du thème de l’ALM (Application Lifecycle Management), ma spécialité justement :)

Je ne vais pas être original et relayer le billet du blog du groupe car je ne vais pas spécialement présenter mieux l’événement :


Lancement du User Group ALM FRANCE jeudi 4 novembre chez Microsoft !

Vous avez entendus parler d’ALM - Application Lifecycle Management ou vous souhaitez découvrir ce que cache réellement cet acronyme ?

Vous avez déjà une expertise ALM reconnue ou acquise sur le terrain dans la mise en œuvre de filière de développement ?

Quelle que soit votre expérience, nous vous invitons à rejoindre cette nouvelle communauté d'utilisateurs, au sein de l’ALM FRANCE.

Notre objectif est de promouvoir la gestion du cycle de vie des applications et les outils associés. Cette discipline recouvre de nombreux aspects comme la conception, la gestion des exigences, l'architecture, la gouvernance des processus, la gestion de projet, les outils, l'assurance qualité, la gestion des configurations, le déploiement, l'exploitation et la prise en compte de l'expérience utilisateur.

Le fonctionnement du groupe privilégiera le partage d'expériences concrètes sur tous ces domaines, afin de permettre à chacun de bénéficier des meilleures pratiques du terrain.

Vous avez certainement quelques idées à partager !

Alors notez donc l'événement dans votre agenda et inscrivez-vous ci-dessous.

Cette soirée de lancement se déroulera chez Microsoft France.


Vous noterez les sponsors divers et variés (il n’y a pas que du MS) et justement c’est l’occasion de s’ouvrir un peu l’esprit car l’ALM n’est pas spécifique à une technologie. J’y serai présent avec la plupart de mes collègues de Sogeti donc à la semaine prochaine !

Posté le par vLabz | 1 commentaire(s)

Industrialisez vos builds avec TFS 2008 : centralisez vos scripts

Encore quelques petits posts sur TFS 2008 avant de passer à 2010, pour ceux qui n’ont pas prévu de migrer tout de suite (des billets sur la migration vers TFS 2010 à venir aussi). Si vous avez mis en pratique une logique de build commune à plusieurs de vos projets, une logique potentiellement complexe comme celle que j’ai proposée à propos de l’auto-incrémentation, vous allez vite vous retrouver avec plusieurs scripts similaires à maintenir en parallèle, et cela n’est pas souhaitable.

Nous voulons simplement ici appliquer une des règles de base de l’informatique : factoriser, ne plus avoir de bout de code logique en 2 exemplaires. Je ne m’étends pas sur les conséquences d’un bug à corriger dans 10 scripts de 10 Team Projects différents. Comment va-t-on s’y prendre avec MSBuild ?

Imports en cascade

Le plan c’est de passer de ça :

image

A ça :

image

Même si nous tenons à factoriser le maximum de logique, notre build a typiquement besoin de définir ses propres targets ne serait-ce que pour exécuter un packaging maison à base de zip par exemple.

Target forwarding

Le problème de la surcharge de target se pose alors : si l’on commence à surcharger les targets “BeforeGet”, “AfterGet”, “BeforceCompile”, “AfterCompile”, etc. dans notre fichier commun pour rajouter de la logique commune, on sera embêté quand un script principal aura également besoin de surcharger la même target. Il en résultera que nos targets communes ne seront pas appelées car la priorité aura été donnée au script principal, car il les surcharge en dernier, et avec MSBuild le dernier a raison.

La solution consiste à reproduire le comportement de Microsoft.TeamFoundation.Build.targets, c’est à dire définir des targets potentiellement surchargeables. Ici par exemple, un extrait de notre script commun qui a besoin de rajouter un bout de logique “BeforeCompile”. Pour donner la possibilité à des scripts principaux de surcharger BeforeCompile, on crée la target MyBeforeCompile.

  <Target Name="MyBeforeCompile" />
  
  <Target Name="BeforeCompile" DependsOnTargets="BeforeCompileCommon;MyBeforeCompile" />
  <Target Name="BeforeCompileCommon">
    <!-- Logique commune before compile -->
  </Target>
  <Target Name="MyAfterCompile" />
  <Target Name="AfterCompile" DependsOnTargets="MyAfterCompile" />

La target AfterCompile n’est pas utilisée par notre script, mais afin de prévoir une utilisation future en douceur, on prévoit le coup et on la surcharge aussi.

Oui, c’est un peu rébarbatif, mais une fois que c’est fait, ça l’est une bonne fois pour toutes. Cela vous donnera la souplesse de définir des comportements partagés ou au contraire d’en injecter dans seulement certains scripts, et ce à n’importe quelle étape du build. Pour info, la liste des targets customisables est sur MSDN.

Où mettre le script commun ?

Dans le prochain billet, j’aborderai des solutions possibles pour effectivement partager ce script. Nous verrons une approche par Workspace, et celle du déploiement dans le répertoire MSBuild de chaque machine de build.

Posté le par vLabz | 0 commentaire(s)
Classé sous : , , , ,

Vive les mocks et les POCOs

J’observe régulièrement autour de moi de la confusion à propos de ces deux termes et j’aimerais juste rappeler ce qu’ils signifient. Je ne suis bien sûr pas le mieux placé pour faire une leçon mais je vais faire de mon mieux pour mettre en valeur ce qui selon moi fait la différence entre le développeur débutant et le développeur érudit.

POCO != DTO

DTO = Data Transfer Object

    public class CreditCard
    {
        public String Number { get; set; }
        public String [] Types { get; set; }
        public String Digit { get; set; }
        public int ExpirationYear { get; set; }
        public int ExiprationMonth { get; set; }
    }

POCO = Plain Old CLR Object

    public class CreditCard
    {
        public String[] Types { get; set; }
        public String Digit { get; set; }
        public int ExpirationYear { get; set; }
        public int ExiprationMonth { get; set; }
        private String _number;
        public String Number
        {
            get
            {
                return _number;
            }
            set
            {
                if (VerifyNumber(value))
                {
                    _number = value;
                }
                else
                {
                    throw new InvalidNumberException(value);
                }
            }
        }
        public int GetNumberOfDaysBeforeExpiration()
        {
            // ... computations skipped here
            return 0;
        }
        public static bool VerifyNumber(string number)
        {
            // .... verification code
            return true;
        }
    }

La différence fondamentale que je veux souligner à travers mes deux exemples c’est que les POCOs peuvent contenir des méthodes et des traitements !

Un POCO est une classe qui n’a pas dépendance particulière : qui n’hérite de rien, qui n’a pas d’attribut qui proviennent d’ailleurs etc…

Pour éclaircir la formule, il est souhaitable qu’un DTO soit un POCO et un POCO n’est pas forcément un DTO.

Les POCOs, ainsi débarrassés de dépendances obscures, sont de bons candidats pour être “proxifiés” c’est à dire qu’on pourra les utiliser plus facilement via frameworks et des outils qui rajoutent dynamiquement ou statiquement des comportements (transparent proxies, post compilation). C’est la mode alors pensez-y.

De même, j’aimerais souligner l’approche Domain Driven Design qui est à mon avis l’apologie du POCO, pour que toutes les entités soient POCO et qu’aucune classe du domaine n’ait une dépendance externe, Amen.

Mocks aren’t stubs

Pour reprendre ici la formule de Martin Fowler. On adhère ou pas à l’article, c’est un autre sujet, il a cependant le mérite de clarifier les choses.

Un Mock permet de vérifier le comportement intrinsèque d’un objet, alors qu’un stub (bouchon) permet de remplacer un objet par une fausse implémentation qui ne marchera que spécifiquement pour nos tests, sans faire de contrôle particulier. C’est ce concept de “bouchon” que nous avons l’habitude d’utiliser et nous devrions dire le plus souvent bouchon ou stub au lieu de mock. La confusion vient des frameworks de Mocks (Rhino Mocks, TypeMock, Moq) qui nous font penser que les objets qu’ils nous fournissent sont des Mocks. En fait dans 90% des cas voire plus, on utilise des stubs. L'usage de Mocks quand on parle simplement de bouchons est donc inapproprié.

Il existe d’autres types d’objets comme les fakes (implémentation complète qui marche mais dédiée à des tests), ou les dummies (l’objet ne sera pas vraiment utilisé par le test mais la fonction testée a besoin qu’il existe).

Edit : je réalise seulement maintenant que l’ami Thomas Jaskula a déjà posté sur cette différence, alors je vous recommande vivement son billet sur le sujet. Ca confirme que je ne suis pas parano et que par conséquent une deuxième couche ne peut pas faire de mal.

 

Voilà, la prochaine fois je parle stubs POCO ;)

Posté le par vLabz | 0 commentaire(s)
Classé sous : , ,

La quête de OneNote anywhere, suite et fin

Chers amis lecteurs cette quête qui a commencée il y a 3 ans touche à sa fin.

Je ne vais pas ménager le suspens : la solution réside en OneNote 2010 et sa capacité à se synchroniser avec SkyDrive.

Rappel de la problématique : vous utilisez Microsoft OneNote depuis plusieurs machines. Vous êtes flemmard et vous voulez que vos notes soient synchronisées sur toutes vos machines le plus simplement possible.

  • Solution 1 : utilisez une clé USB, mais il faut l’avoir sur soi tout le temps, ne jamais l’oublier…
  • Solution 2 : synchroniser en ligne !

Rappel : OneNote a été conçu dès le début pour intégrer des modifications en concurrence, il gère élégament les conflits.

Ceux qui me connaissent savent que j’affectionne OneNote, à la fois pour tout ce qui est pro et mais aussi pour des notes perso. Je suis particulièrement satisfait des dernières évolutions de ce dernier, alors en route pour la synchro en ligne, la vraie !

Vive le Cloud !

Pour peu que vous possédiez un Live ID et par conséquent un espace SkyDrive (sinon consultez le billet récent d’Arnaud à propos de la DropBox), OneNote 2010 vous propose nativement et sans effort de synchroniser vos bloc-notes via votre espace SkyDrive.

Pour mettre en ligne l’un de vos bloc-notes, rien de plus simple, allez dans File->Share. Sélectionnez votre bloc-note et choisissez “Web” :

image

C’est le moment de vous connecter à SkyDrive, on peut remarquer que les différentes options sont intégrées à OneNote (authentification, souscription, accès à SkyDrive).

Une fois connecté, il reste à choisir le répertoire dans lequel sera placé le bloc-note :

image

Le bloc-note va dès lors se synchroniser en ligne, mais vous seul pouvez y accéder. Rien ne vous empêche alors de régler les droits des répertoires dans SkyDrive pour autoriser d’autres comptes Live ID d’accéder à votre bloc-note.

NB : cela n’est pas opérationnel avec la beta d’Office 2010.

OneNote 2007

La solution avec OneNote 2007 est de se synchroniser avec un site SharePoint ou une adresse WebDAV. Malheureusement, on ne peut pas dire que OneNote 2007 respecte bien les standards WebDAV, pour avoir essayé plusieurs fournisseurs WebDAV, on se retrouve avec d’énormes lenteurs, des timeouts, voire une impossibilité de se synchroniser via OneNote (alors que les dits services sont tout à fait corrects en utilisation directe).

Côté OneNote 2007, la quête n’est pas complètement terminée donc. Le salut viendrait en fait de SharePoint, qui lui, bizarrement, va fonctionner sans problème en pair avec OneNote.

Un lecteur fort aimable (spéciale dédicace pour bbdanix) m’a cependant signalé l’existence d’un espace SharePoint gratuit auquel je n’avais pas pensé : Office Live Small Business  ! J’ai pu l’utiliser pendant presque un an (j’aurais dû relayer l’info à l’époque, toutes mes excuses) et je peux vous confirmer que cela marche à peu près correctement :

  • Le service n’est pas une foudre de guerre en vitesse (les Vikings de AoE2 font mieux)
  • Quelques petites désynchro on pu se produire comme l’apparition d’une page nouvellement créée en double (le temps de la renommer par exemple), ou bien l’apparition d’une page supprimée dans les pages à classer

Bref rien de très grave, mais pas la perfection tout de même.

Un serveur SharePoint à part reste l’idéal : si vous avez la possibilité de squatter le serveur d’un pote, d’un collègue, de votre société, cela sera sans doute plus véloce et moins sujet à des désynchro (par contre le https n’est pas superflu, je n’ai pas réussi à enregistrer un mot de passe d’un compte distant qui n’utilisait pas https).

La Cerise

Cerise sur le gateau, vous n’avez pas accès à OneNote et pourtant vous avez besoin de lire ou modifier vos notes… Facile !

Allez dans SkyDrive, et profitez de la toute nouvelle interface Web d’édition et de modifications de documents Office (Word, Excel, PowerPoint ET OneNote) en grâce à Office Web Apps :

image

La synchro marchera dans tous les sens (machine 1 <-> SkyDrive <-> machine 2 <-> machine 3, etc.). Que du bon !

Posté le par vLabz | 1 commentaire(s)
Classé sous :

TFS 2010 : Un nouveau Process Template Scrum

D’abord annoncé par Aaron Bjork sur son blog, puis relayé hier par Brian Harry, le nouveau Process Template Scrum Microsoft fait son chemin. Jusqu'à présent nous n’avions droit qu’à deux Process Templates estampillés Microsoft :

  • le Process Template MSF Agile
  • le Process Template MSF pour CMMI

Dans mon expérience, j'ai plutôt tendance à partir du Process Template Agile pour le modifier, l’adapter pour nos besoins et/ou ceux du client, il a l'avantage d'être simple.

Face au succès de plus en plus retentissant de Scrum, Microsoft a bien réagi de nous livrer ce nouveau Process Template, cela nous donne une base de départ bien adaptée à tous ceux qui préfèront employer le vocabulaire Scrum (Sprint, Product Backlog Item, etc.). Ce template est proche du MSF Agile, et outre les aspects terminologie dans les Work Items, on y trouve notamment trois nouveaux rapports Reporting Services : les fameux Release Burndown, Velocity et Sprint Burndown.

image

La documentation du process (le “process guidance”) quant à elle est encore en cours de rédaction.

 

Attention, si vous voulez passer la vitesse supérieure avec Scrum, nous ne vous contenterez pas de ce Process Template, mais vous opterez sans doute pour des produits plus complets comme Scrum for Team System fourni gratuitement par ECM Consulting (Conchango) ou le plus récent Urban Turtle, payant mais plus fonctionnel.

Côté TFS 2008 vous avez le choix entre Light Weight Scrum qui est fourni par la communauté et  Scrum for Team System.

Posté le par vLabz | 1 commentaire(s)
Classé sous : ,

Tests unitaires : comparer des objets .NET en profondeur

J’ai trouvé une petite librairie toute simple qui permet de comparer élégamment deux objets en profondeur et qui répond à un besoin fréquent dans le monde des tests.

J’écris un petit programme qui interprète des blocs Xml et j’écris en même temps les tests unitaires qui vont avec (oui c’est du TDD). Au passage l’écriture de ces tests me permet de prendre du recul par rapport aux résultats attendus et donc à mieux structurer mon approche et au final mon code. Question temps passé, il y a un petit surcoût lié à l’écriture de ces tests mais il m’évite la perte de temps liée au lancement de mon programme avec des paramètres différents pour tester tel ou tel bout de code, de même, j’économise pas mal de temps de débuggage. Cela est dû au fait que le test unitaire un est un point d’entrée dans mon programme, mettant le doigt sur un bout de code précis, et au fait qu’il est particulièrement rapide à s’exécuter : je les lance tout le temps, d’un clic de bouton. Mais le but de ce post n’est pas de s’attarder sur les joies ou les peines du TDD…

Voici un exemple de test :

        [TestMethod]
        public void ChoosingPhase_Missing1()
        {
            var result = Engine.Compute("Choosing4_miss1.xml");
            Assert.AreEqual<State>(State.ChoosingPhases, result.State);
            Assert.AreEqual<Int32>(1, result.PlayersNeedPlaying.Count);
            Assert.AreEqual<String>("Fufu", result.PlayersNeedPlaying[0]);
        }
Ce test vérifie 3 choses en même temps, ce qui n’est pas idéal pour un test unitaire, mais passons. Ce qui m’embête surtout ici, c’est la verbosité des 3 assertions successives.

Dans ce genre de cas il est plus élégant de construire un objet qui représente l’état final attendu et de le comparer au résultat obtenu. Quelque chose dans le genre :

        [TestMethod]
        public void ChoosingPhase_Missing1()
        {
            var result = Engine.Compute("Choosing4_miss1.xml");
            var expected = new Result
            {
                State = State.ChoosingPhases,
                PlayersNeedPlaying = new List<String> { "Fufu" }
            };
            Assert.AreEqual<Result>(expected, result);
        }

Malheureusement, AreEqual fait tout sauf une comparaison en profondeur, il s’appuie sur la méthode Object.Equals qui a peu de chance de marcher sur des classes si elle n’est pas surchargée.

Bien qu’écrire le code qui compare deux objets en profondeur est une aventure intéressante en soi, j’ai bien sûr cherché et je suis tombé sur Compare .NET Objects. C’est un projet sur CodePlex qui est lui-même accompagné d’une foule de tests unitaires (à base de NUnit) !

La méthode principale renvoie un booléen, donc on peut l’utiliser comme ceci :

            Assert.IsTrue(comparer.Compare(expected, result));

Via diverses propriétés, le comparateur nous donne la liste des membres différents dans le graphe des deux objets, et les met également à notre disposition sous forme d’une chaîne unique, utile pour les messages d’erreurs. J’ai donc factorisé l’appel au comparateur :

        [TestMethod]
        public void ChoosingPhase_Missing1()
        {
            var result = Engine.Compute("Choosing4_miss1.xml");
            var expected = new Result
                {
                    State = State.ChoosingPhases,
                    PlayersNeedPlaying = new List<String> { "Fufu" }
                };
            AssertContentAreEqual(expected, result);
        }
        public static void AssertContentAreEqual(object obj1, object obj2)
        {
            CompareObjects comparer = new CompareObjects();
            if (!comparer.Compare(obj1, obj2))
            {
                Assert.Fail(comparer.DifferencesString);
            }
        }

A noter qu’avec des objets plus complexes à comparer, il est courant de se créer des petites fonctions helpers, de style factories, pour créer des instances réutilisables.

En tout cas un big merci à KellermanSoftware pour cette fonction bien pratique :)

Posté le par vLabz | 2 commentaire(s)
Classé sous : ,

Industrialisez vos builds avec TFS 2008 : incrémenter la version, le label et le numéro du build

Je vais commencer une série de billets sur des problématiques courantes liées à TFS 2008. Bien que la mode soit actuellement plutôt autour de TFS 2010 et de VS 2010, la version 2008 est encore présumablement déployée chez bon nombre et certains n’ont pas les moyens de dégager le temps ou les ressources pour migrer vers TFS 2010.

Le but sera de donner des recettes qui répondent à des besoins du terrain plutôt classiques pour les projets sous TFS 2008 en essayant de proposer des solutions les plus simples. L’industrialisation de vos builds vous permettra ainsi de gagner un temps précieux en automatisant un maximum de tâches sur l’ensemble de vos projets.

Build versionnant : recette rapide

Je ne suis clairement pas le 1er à poster sur l’incrémentation des numéros de version dans les builds, on bénéficie aujourd’hui de nombreux posts sur le sujet et grâce à eux nous avons aujourd’hui un certain recul, de même nous bénéficions de frameworks MSBuild en Open Source tout à fait opérationels (certains plus ou moins en activité). Faire une passe plus en profondeur à ce jour me semble intéressant.

Malgré la longueur de ce post, le travail est pré-mâché pour être applicable rapidement.

Voici ce que nous allons mettre en place :

  • Un build qui pose un label de type “1.2.3.4”  ou “MonProjet_1.2.3.4”
  • Le nom des builds contiendra le numéro de version et non plus la date (ex: “MonBuild_1.2.3.4”)
  • Le numéro de version est incrémenté à chaque build (build ou revision)
  • Le build va modifier les fichiers sources AssemblyInfo.cs (.vb) pour y mettre le numéro de version. Cependant, cela ne se produit que sur le serveur de build, les sources en question en sont pas mis à jour dans le contrôleur de source
  • Le numéro de version est maintenu dans un fichier Xml dans le contrôleur de source, on peut le modifier à tout moment et cela sera répercuté sur les binaires au prochain build

Une version est avant tout technique

Je dois m’expliquer sur certains choix. Pourquoi systématiquement incrémenter le numéro de version ? Et si je veux produire un version qui tombe rond : 1.1.0.0 ?

A mon sens il faut arrêter de vouloir décider à l’avance des versions que l’on va livrer. Cela se traduit généralement par une perversion du système de build / packaging. En effet, on n’est jamais à l’abri d’un build qui échoue, ou d’un build de faible qualité qui ne sera pas viable pour une livraison, même intermédiaire. N’est-ce pas détourné que de prétendre qu’un build passera tous les tests jusqu’à livraison ? Si vous ne vous trompez jamais, je vous embauche et je vous paye cher ;)

Je pense qu’il faut accepter que la version d’un produit buildé est une version technique, et qu’il est préférable de communiquer une version “simplifiée” au client, un nom de code par exemple, suivi du numéro de patch. Bref, faire correspondre une version technique avec une version marketing (que le cient soit interne ou externe ne change rien).

De même, ne vous inquiétez pas s’il y a des trous entre les versions, si entre deux livraisons on passe de la 1.2.56.0 à la 1.2.185.0. Certains builds échoueront, d’autres seront buggés. C’est pour cela que le plus simple est sans doute d’avoir un système qui permette à tout build d’être potentiellement livrable. J’entends par là :

  • un label en bonne et dûe forme incluant le numéro de version
  • un numéro de version incorporé dans les binaires
  • un nom de build facilement repérable (encore une fois le numéro de version est pratique)
  • un package livrable en sortie

Ce type de build est typiquement exécutable en tant que Nightly build (je le recommande) et à la demande lorsqu’une livraison est prévue (nb : on peut facilement forcer un build déjà programmé avec TFS).

Tâches MSBuild utilisées

Avec MSBuild est facile de créer ses propres tâches (Tasks) : en deux coups de cuillère à pot on référence quelques assemblies Microsoft.Build.*, on hérite de la classe Task et c’est parti. J’ai fait le choix de ne pas créer de nouvelle tâche (bien que cela eût été plus facile parfois que de comprendre les existantes !) afin de vous épargner de les builder vous-même ou d’avoir des configs de serveur de build un peu torp exotiques avec trop nombreuses tierces parties. En effet, si vous utilisez ainsi des tâches compilées maison, cela vous demande également de créer les projets équivalent dans le contrôleur de sources (du moins j’espère que vous auriez ce réflexe !).

Je me suis appuyé sur les 3 frameworks MSBuild les plus connus à ce jour :

La 1ère étape consiste donc à les télécharger et à les déployer sur le serveur de build. Pour cela, il faut soit installer les MSI soit dézipper les binaires dans un sous-répertoire de %programfiles%\MSBuild (pour SDCTasks), vous devez obtenir respectivement ExtensionPack, MSBuildCommunityTasks et SDCTasks.

Implémentation

Dans le fichier .proj de votre build, commencez par repérer la 1ère balise Import et collez ceci en dessous :

<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks" /> 
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" /> 
<UsingTask  AssemblyFile="$(MSBuildExtensionsPath)\SDCTasks\Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.VersionNumber.Parse" /> 

Ces tâches permettent de déclarer les tâches que nous allons utiliser dans les 3 frameworks préalablement cités.

Puis insérez les Targets suivantes :

  <Target Name="GetProjectVersionNumber">
    <!-- récupération du fichier Xml -->
    <Message Text="Getting version number from Xml file %(ProjectVersionNumberFile.FullPath)" />
    <ExtensionPack.VisualStudio.TfsSource TaskAction="Get" ItemCol="@(ProjectVersionNumberFile)" Force="true" />
    <Error Condition="!Exists('%(ProjectVersionNumberFile.FullPath)')" Text="Missing project info XML with version number [%(ProjectVersionNumberFile.FullPath)]."/>
    <!-- lecture du numéro de version -->
    <Community.Tasks.XmlRead XPath="/Project/CurrentVersion" XmlFileName="%(ProjectVersionNumberFile.FullPath)">
      <Output TaskParameter="Value" PropertyName="ProjectVersionNumber" />
    </Community.Tasks.XmlRead>
    <Message Text="Project CurrentVersion is $(ProjectVersionNumber)"/>
    <Error Condition="$(ProjectVersionNumber)==''" Text="Version information was not found the Xml version file."/>
    <!-- Analyse du numéro de version -->
    <Sdc.Tasks.VersionNumber.Parse Text="$(ProjectVersionNumber)">
      <Output TaskParameter="MajorNumber" PropertyName="ProjectMajorNumber" />
      <Output TaskParameter="MinorNumber" PropertyName="ProjectMinorNumber" />
      <Output TaskParameter="BuildNumber" PropertyName="ProjectBuildNumber" />
      <Output TaskParameter="RevisionNumber" PropertyName="ProjectRevisionNumber" />
    </Sdc.Tasks.VersionNumber.Parse>
    <!-- Incrément du numéro de version selon les valeurs fixées dans les propriétés BuildNumberIncrement et RevisionNumberIncrement -->
    <ExtensionPack.Science.Maths TaskAction="Add" Numbers="$(ProjectBuildNumber);$(BuildNumberIncrement)">
      <Output TaskParameter="Result" PropertyName="ProjectBuildNumber" />
    </ExtensionPack.Science.Maths>
    <ExtensionPack.Science.Maths TaskAction="Add" Numbers="$(ProjectRevisionNumber);$(RevisionNumberIncrement)">
      <Output TaskParameter="Result" PropertyName="ProjectRevisionNumber" />
    </ExtensionPack.Science.Maths>
    <PropertyGroup>
      <ProjectVersionNumber>$(ProjectMajorNumber).$(ProjectMinorNumber).$(ProjectBuildNumber).$(ProjectRevisionNumber)</ProjectVersionNumber>
    </PropertyGroup>
    <Message Text="New version is $(ProjectVersionNumber)"/>
    <ExtensionPack.VisualStudio.TfsSource TaskAction="Checkout" ItemCol="@(ProjectVersionNumberFile)" />
    <!-- MAJ du numéro dans le fichier Xml -->
    <Community.Tasks.XmlUpdate XPath="/Project/CurrentVersion" XmlFileName="%(ProjectVersionNumberFile.FullPath)" Value="$(ProjectVersionNumber)" />
    <!-- Archivage du fichier dans le contrôleur de sources -->
    <TfsSource TaskAction="Checkin" ItemCol="@(ProjectVersionNumberFile)" Comments="Update for build version $(ProjectVersionNumber) - $(NoCICheckinComment)" OverrideText="Needed for build automation" />
  </Target>
  <!-- Cette tâche permet de modifier le nom du build et le label qui sera posé -->
  <!-- Elle déclenche la tâche GetProjectVersionNumber ci-dessus -->
  <Target Name="BuildNumberOverrideTarget" DependsOnTargets="CoreInitializeWorkspace;GetProjectVersionNumber">
    <PropertyGroup>
      <!-- Le nom du build, ne pas hésiter à customiser ce nom -->
      <BuildNumber>$(TeamProject)_$(ProjectVersionNumber)</BuildNumber>
      <!-- Le nom du label, customisable également -->
      <LabelName>$(ProjectVersionNumber)</LabelName>
      <!-- Le répertoire où sera posé le label dans le contrôleur de sources -->
      <LabelScope>$/$(TeamProject)/Main</LabelScope>
    </PropertyGroup>
  </Target>
  <Target Name="BeforeCompile">
    <!-- Afin de modifier le ou les fichiers qui contiennent des numéros de version, on enlève l'attribut lecture-seule -->
    <Community.Tasks.Attrib Files="@(VersionInfoSourceFile)" readOnly="false" />
    <!-- Puis on écrase toute version trouvée avec la version courante (devrait marcher avec C# et VB) -->
    <Community.Tasks.FileUpdate Files="@(VersionInfoSourceFile)" Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)" ReplacementText="$(ProjectVersionNumber)" />
  </Target>

A la fin du fichier, avant la balise </Project> insérez le bloc suivant :

  <PropertyGroup>
    <!-- L'incrément utilisé pour le 3ème numéro dans la version (build) -->
    <BuildNumberIncrement>1</BuildNumberIncrement>
    <!-- L'incrément utilisé pour le 4ème numéro dans la version (revision) -->
    <RevisionNumberIncrement>0</RevisionNumberIncrement>
  </PropertyGroup>
  
  <ItemGroup>
    <!-- Chemin vers le fichier Xml qui contient le numéro de version -->
    <ProjectVersionNumberFile Include="$(SolutionRoot)\TeamBuildTypes\AutoIncrProject\ProjectInfo.xml" />
    <!-- Chemin vers le fichier source qui contient l'attribut de version -->
    <VersionInfoSourceFile Include="$(SolutionRoot)\Main\WindowsFormsApplication1\Properties\AssemblyInfo.cs" />
  </ItemGroup>

Fichier Xml

Afin de garder trace du numéro de version, j’utilise un fichier Xml tout simple qui sera maintenu par le build dans le contrôleur de source. J’ai préféré utiliser un fichier indépendant plutôt qu’un fichier source afin de le placer dans un répertoire indépendant de celui des sources. Ce n’est pas très important, mais je préfère éviter de polluer ainsi les sources directement avec des archivages déclenchés par les builds (cf Résultat).

Créez donc un fichier ProjectInfo.xml dans votre Team Project et collez-y le contenu suivant :

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <CurrentVersion>1.0.0.0</CurrentVersion>
</Project>

Configuration

Voilà c’est presque prêt il ne reste plus qu’à customiser une ou deux choses dans notre script de build :

  • BuildNumberIncrement et RevisionNumberIncrement : généralement l’un est à 1 et l’autre à 0. Lorsque je crée une branche pour la maintenance, je préfère incrémenter le numéro de révision et laisser le numéro de build figé (il correspond du coup au numéro qui a été livré depuis la branche principale).
  • ProjectVersionNumberFile : Je m’arrange pour que ce fichier soit généralement dans le scope de mes branches, mais pas dans celui des sources.
  • VersionInfoSourceFile : Il est possible de mettre plusieurs fichiers en dupliquant la balise. J'ai une légère préférence ceci dit pour ne référencer qu’un seul fichier VersionInfo.cs (ou .vb) commun à plusieurs projets en utilisant des linked items. Moins y’en a dans la config du build et mieux on se porte.

Résultat

Vos builds auront désormais des noms plus clairs…

image

…sauf s’ils plantent avant la fin de la tâche BuildNumberOverrideTarget !

L’historique de vos sources sera “pollué” par les builds. Autant on peut parfois considérer cela comme du bruit, autant cela peut s’avérer bien pratique d’avoir cette vision entrelacée des changesets au fil des versions :

image

Si vous avez placé votre fichier Xml en dehors du scope des sources, vous pourrez justement éviter cette “pollution” en demandant l’historique sur les sources seulement !

Notez le commentaire ***NO_CI***, il correspond à la propriété pré-définie $(NoCICheckinComment) et permet d’éviter le déclenchement d’un build d’intégration continue. Sans cela, on aurait une belle boucle infinie de builds !

Les labels créés au cours des build :

image

Attention à vos labels

Vos builds vont être effacés en fonction de la politique de rétention que vous aurez choisie (cf définition du build). Afin d’éviter de perdre un build qui a finalement été livré, pensez à le “retenir indéfiniement” en effectuant un clic-droit dessus :

image

En cas de perte d’un build livré, ce n’est pas trop grave : vous retrouverez très vite le changeset qui vous intéresse grâce à… l’historique du fichier ProjectInfo.xml ! Vous pourrez recréer un label sur la base de ce changeset.

Notes

Vous noterez la dépendance de la Target BuildNumberOverrideTarget envers CoreInitializeWorkspace, sans cette astuce (merci à ce post) le workspace ne serait pas toujours créé avant de récupérer le fichier VersionInfo.Xml et ça ne pourrait pas marcher, à moins d’avoir recours à des “tf.exe view” mais ça complique la sauce.

A vous…

J’espère que cette recette vous sera utile autant qu’à moi, si vous venez à l’adaptez n’hésitez pas à me dire en quoi, ça fait toujours plaisir que quelque chose sert :)

Vous aurez probablement une erreur à la 1ère exécution à cause d’un chemin de fichier non trouvé, un répertoire en trop, en moins ? Si, si, moi aussi j’ai bloqué un peu bêtement sur mon propre projet d’exemple ;)

Posté le par vLabz | 0 commentaire(s)
Classé sous : , ,

Tests unitaires avec Oracle

Je suis plutôt de l’école de ceux qui cherchent à installer le moins de choses sur un serveur de build, quitte à un peu se casser la tête parfois. Pourquoi ça ?

  • Pour éviter d’avoir des incompatibilités entre les dépendances de projets différents (ou du même projet à deux moments différents dans le temps)
  • Pour éviter d’avoir des configs à rallonge sur les serveur de build : un déploiement par xcopy ou bien un partage commun reste plus simple)

Je recherche donc généralement à ne pas installer les dépendances des projets de mes serveurs mais plutôt à les recopier, soit en les intégrant dans le source control, soit par un partage réseau, soit dans un répertoire “well known” sur la machine.

Bref, 1er exemple avec Oracle. Il est tout à fait possible d’utiliser la couche cliente ODAC (Oracle Data Access Components) sans l’installer (à condition de ne pas faire de transaction distribuées, sinon c’est une autre affaire). Pour cela il faut définir des variables d’environnement avant d’appeler la librairie ODP.NET.

set PATH=%PATH%;\\MONSERVEUR\Shared\oracle\11.2.0\client_1;\\MONSERVEUR\Shared\oracle\11.2.0\client_1\bin
set ORACLE_HOME=\\MONSERVEUR\Shared\oracle\11.2.0\client_1

La compilation utilise une version d’ODP.NET hébergée directement dans le contrôleur de sources. L’exécution des tests unitaires, elle, va nécessiter que ces variables soient correctement définies pour qu’ODP.NET trouve la couche cliente. Rappel : dans Windows les variables d'environnement sont héritées du processus parent.

L’idéal est de définir les variables le plus tard possible (éviter les variables d’env système). J’utilise les tasks MSBuild suivantes pour ce faire :

<MSBuild.ExtensionPack.Computer.EnvironmentVariable TaskAction="Set" Variable="PATH" Value="$(PATH)%3B\\MONSERVEUR\Shared\oracle\10.2.0\bin"/>

<MSBuild.ExtensionPack.Computer.EnvironmentVariable TaskAction="Set" Variable="ORACLE_HOME" Value=\\"MONSERVEUR\Shared\oracle\10.2.0"/>

Le MsBuild Extension Pack est la meilleure librairie de tâches que je connaisse à ce jour.

Il m’est ainsi facile de faire tourner les tests de plusieurs projets liés à différentes versions d’Oracle sur une même machine sans embrouille d’installation.

Posté le par vLabz | 0 commentaire(s)
Classé sous : , , ,

PDC 2009 : Mise en place d’une chaîne complète avec Visual Studio et TFS 2010

Le but de cette session a été de montrer les étapes à franchir avant de pouvoir considérer qu’un projet est réellement terminé (d’où le « Done Done » à répétition pour insister qu’il n’y a plus rien à faire). Cela va passer par la mise en place d’un processus de build, de tests unitaires, de tests d’interface graphique, et de leur automatisation. Le tout bien évidemment avec Visual Studio et Team Foundation Server 2010.

Rien de nouveau ici, aucune annonce particulière, mais une démarche intéressante particulièrement bien résumée en une heure seulement.

image

Constat

On part d’un développement « classique » (ou du moins sans cycles) :

  • Les développeurs écrivent du code
  • Compilent
  • Archivent les sources
  • Recommencent ainsi pendant plusieurs semaines

Puis un des développeurs (le responsable sans doute) cherche à déployer l’application :

  • Il compile et package le tout
  • Déploie l’application en environnement de test
  • Un testeur (lui-même ou un autre) teste l’application
  • Ca marche pas (normal, un projet ça marche pas du 1er coup)
  • Le développeur se plaint du testeur
  • Le moral général baisse et la pression monte

Travailler par cycles

Pour pallier ce déroulement que l’on peut qualifier d’échec (même si au final on arrive à faire marcher le projet, mais dans des conditions plutôt mauvaises donc), il est recommandé d’opter pour une méthodologie en cycles. Les cycles réprésentent les étapes de construction du produit à des échelles de plus en plus importantes, en partant du codage jusqu’à l’obtention du produit final. Ils s’imbriquent les uns dans les autres et chacun nécessite un certain nombre d’étapes de validation afin de considérer le cycle suivant dans l’échelle. Plus tôt on réalise ces opérations de validation, mieux ce sera pour le projet.

image

La question devient : quels sont les coûts associés à s’y prendre tôt ? En effet, attendre tard pour faire des tests provoque des allers-retours qui ont une inertie et un coût important, sans compter qu’il est difficile de savoir ce qu’il reste vraiment à corriger.

D’un autre côté, mettre en place des tests tôt est très coûteux quand on sait qu’on devra les jouer à chaque itération. En général, on s’oriente donc vers la 1ère option qui diffère le problème.

image

Visual Studio et Team Foundation Server 2010

C’est là qu’une bonne plate-forme de développement va pouvoir sauver la mise :

  • En fluidifiant les développements malgré la complexité inhérante au travail en équipe
  • En automatisant les tâches de tests qui serait si coûteuse à exécuter manuellement
  • En exposant clairement les informations permettant de maîtriser le projet

Nous allons maintenant voir comment Visual Studio et Team Foundation Server 2010 peuvent répondre concrètement à cette problématique.

image

On va partir d’un scénario concret : une application qui compile dans Visual Studio et c’est tout. Aucun build mis en place, aucun test, aucune automatisation. Comment faire tout ça ?

image

Mise en place d’un build automatisé

Notre démonstrateur développeur adopte une attitude qui n’est plus acceptable aujourd’hui : « ça marche sur ma machine, donc j’archive et j’ai fini mon boulot ». Evidemment son chef de projet (ici Jamie) n’est pas satisfait et lui demande de mettre en place un build automatisé avec TFS. Ca ne prend que quelques minutes à mettre en place (voire secondes pour les rôdés).

image

Intégration continue

Le moment est venu de mettre en place une intégration continue car le chef de projet veut détecter les erreurs au plus tôt pour pouvoir réagir tant que « le codage est frais », et avec un minimum de conséquences.

Afin de garantir que le build restera « vert » en permanance, le chef de projet demande au développeur de rajouter un build de type Gated Checkin pour valider chaque archivage sur le serveur de build avant de l’incorporer au contrôleur de sources.

C’est également le moment de rajouter une checkin policy “Work item” afin de forcer chaque archivage à être associé à élément de travail (et garantir une bonne traçabilité).

Dans la démo, le chef de projet a fait exprès de faire une erreur qui plante le build pour illustrer le Gated Checkin.

image

Les tests unitaires

Vérifier que le projet compile c’est bien, mais c’est tellement plus probant d’exécuter des tests (ici des tests unitaires) pour vérifier la santé du projet. L’astuce est bien sûr d’automatiser cette exécution au cours du build.

image

Le chef de projet a donc fait rajouter par son développeur des tests unitaires. Ce dernier a utilisé le générateur de tests automatiques pour sa classe métier. Personnellement cette pratique n’est pas ma tasse de thé, étant plutôt adepte du TDD, mais bon, ça peut être pratique quand il est « trop tard » et que le code a été écrit sans tests.

Le build n’a pas eu à être modifié puisque par défaut il cherche à exécuter les tests de tous les assemblies qu’il trouvera dans le Workspace sur la base de ce wildcard : **/*test*.dll. Il suffit donc de nommer son projet avec le mot « Test » dedans.

Les tests d’interface graphique

La prochaine étape est la plus aboutie et consiste à écrire des tests d’interface graphique et à les automatiser !

Pour cela notre développeur va :

  • Rajouter un projet de tests classique pour héberger des tests d’IHM
  • Rajouter un « Coded UI » test
  • Pendant le rajout, il choisit d’enregistrer lui-même les actions à effectuer sur l’application
  • Cela lance le « Coded UI Test Builder »
  • Puis il lance l’application et joue son scénario de test, les actions sont enregistrées au fur et à mesure
  • Enfin, il clique sur le bouton « Generate Code » qui génère le code dans la classe de test

NB : il n’a pas rajouté l’étape de validation qui permet de vérifier automatiquement la valeur d’un contrôle, à mon avis ils ont zappé cette étape volontairement pour les besoins de la démo.

Ce test peut être lancé facilement sur le poste d’un développeur, il va effectivement lancer l’application et la piloter de manière visible.

Comment automatiser ce test ?

En effet, on ne va pas le déployer sur le serveur de build automatisé : ce genre de tests se marient mal avec les builds automatisés classiques car ils nécessitent d’interagir une session graphique d’utilisateur. De plus, pour bien faire les choses, on veut maîtriser la notion d’environnement qui permet de cibler différentes configurations.

Team Lab Management 2010

On va donc avoir recours à Team Lab Management 2010, la nouvelle plate-forme d’exécution de tests applicatifs automatisés avec TFS 2010. Cette plate-forme est complexe à mettre en place, elle implique l’installation d’un serveur Hyper-V, mais aussi de System Center Virtual Machine Manager. C’est pourquoi elle était déjà prête à servir pour les besoins de la démo.

image

Le développeur a donc créé un nouveau build, avec des différences significatives par rapport à un build classique :

  • Au prélable, modification du chemin de démarrage de l’application dans le Coded UI test, ceci afin de « hard-coder » le chemin de lancement de l’application car le test sera lancer sur une autre machine
  • Rajout et configuration des Lab Workflow parameters :
    • Configuration de l’environnement cible
    • Référencement de l'autre build automatisé créé au début pour compiler le projet
    • Etape de déploiement par xcopy vers le chemin voulu
    • Configuration des plans de test à lancer

Puis il a lancé le build, et au bout de 2 minutes, le test automatisé s’est bien lancé sur la machine virtuelle dédiée à l’exécution des tests d’IHM.

A ce moment, le chef de projet a considéré de que le développement était bien « Done done ».

Conclusion

image

J’ai bien aimé dans cette session le fait de répondre concrètement à la problématique posée au début, le tout par la pratique, en montrant concrètement chaque étape dans des démos. Ils ont même illustré l’emploi de Lab Manager qui est plus complexe à mettre en place, et le tout en moins d’une heure. Vraiment, une belle performance !

/done-done

Posté le par vLabz | 0 commentaire(s)
Classé sous : , , , ,
Plus de Messages Page suivante »


Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01