Dot.Blog

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

PEX : Tests unitaires intelligents pour VS 2008/2010

PEX est un produit des laboratoires de recherche de Microsoft. Vous allez me dire "encore un 'truc' pour faire du testing !" et je vous répondrai que si on avait déjà atteint la perfection ça se saurait et que donc, par force, il y a encore largement matière à recherche et à nouveaux produits en la matière !

Et PEX apporte beaucoup de nouvelles choses qui vont dans le sens de l'histoire, c'est à dire des tests unitaires plus faciles à intégrer au code, plus complets, plus dynamiques et surtout plus "intelligents".

PEX offre ainsi une façon de travailler plus moderne en apportant une aide précieuse à la création de tests. Mieux, PEX utilise un Add-In pour VS 2008 et 2010 qui sur un simple clic droit permet de générer des tables pour tester une méthode. Par exemple, vous avez une méthode qui capitalise une chaîne passée en paramètre et qui retourne le résultat. Un clic droit dans le corps de la méthode et un appel à PEX et ce dernier génère des valeurs pour tester la méthode. Un null passé en paramètre par exemple... Ensuite il va dérouler les appels à la méthode avec les conditions générées et établir un rapport.

Mieux, à partir des conditions de test établies (modifiables) PEX peut générer une "vraie" méthode de test pour retrouver l'esprit plus habituel des projets de tests unitaires (on peut ainsi dérouler ultérieurement les mêmes tests pour contrôler l'éventuelle régression d'un code). Mais cela n'est pas obligatoire, on peut juste utiliser PEX "à la volée".

Plus fort et sans les mains, face à certaines conditions d'erreur, par exemple le passage d'un null en paramètre évoqué plus haut, PEX peut vous proposer de fixer le code. Dans un tel cas il ajoutera le code nécessaire (ici une exception de type ArgementNullException si la chaîne passée en paramètre est null) !

PEX est un travail en cours, comme tout ce qui émane des laboratoires de recherche de Microsoft. Il montre l'une des directions étudiées par Microsoft pour améliorer les tests unitaires dans de futures versions de Visual Studio. l'avantage est bien entendu qu'il ne s'agit pas d'une démo, mais d'un produit très efficace d'ores et déjà utilisable.

Le mieux c'est de de vous rendre sur le site de PEX, lire les PDF, télécharger le produit, voir les vidéos et tout ça...

Bon Debug

Et Stay Tuned !

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

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

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

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

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

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

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

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

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

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

Bon refactoring !

 

C# - Les optimisations du compilateur dans le cas du tail-calling

Les optimisations du compilateurs C# ne sont pas un sujet de discussion très courant, en tout cas on voit très nettement que le fait d'avoir quitté l'environnement Win32 pour l'environnement managé de .NET a fait changer certaines obsessions des codeurs... Ce n'est pas pour autant que le sujet a moins d'intérêt ! Nous allons voir cela au travers d'une optimisation particulière appelée "tail-calling" (appel de queue, mais je n'ai pas trouvé de traduction française, si quelqu'un la connaît, qu'il laisse un commentaire au billet).

Principe

On appelle "tail-calling" un mécanisme d'optimisation du compilateur qui permet d'économiser les instructions exécutées en même temps que des accès à la pile. Les circonstances dans lesquelles le compilateur peut utiliser cette optimisation sont celles où une méthode se termine par l'appel d'une autre, d'où le nom de tail-calling (appel de queue).

Prenons l'exemple suivant :

static public void Main()
{
    Go();
}
 
static public void Go()
{
    Première();
    Seconde();
    Troisième();
}
 
static public void Troisième()
{
}

Dans cet exemple le compilateur peut transformer l'appel de Troisième() en un appel de queue (tail-calling). Pour mieux comprendre regardons l'état de la pile au moment de l'exécution de Seconde()  : Seconde()-Go()-Main()

Quand Troisième() est exécutée il devient possible, au lieu d'allouer un nouvel emplacement sur la pile pour cette méthode, de simplement remplacer l'entrée de Go() par Troisième(). La pile ressemble alors à Troisième()-Main().

Quand Troisième() se terminera elle passera l'exécution à Main() au lieu de transférer le trait à Seconde() qui immédiatement devra le transférer à Main().

C'est une optimisation assez simple qui, cumulée tout au long d'une application, et ajoutée aux autres optimisations, permet de rendre le code exécutable plus efficace.

Quand l'optimisation est-elle effectuée ?

La question est alors de savoir quand le compilateur décide d'appliquer l'optimisation de tail-calling. Mais dans un premier temps il faut se demander de quel compilateur nous parlons.... Il y existe en effet deux compilateurs dans .NET, le premier prend le code source pour le compiler en IL alors que le second, le JIT, utilisera ce code IL pour créer le code natif. La compilation en IL peut éventuellement placer certains indices qui permettront de mieux repérer les cas où le tail-calling est applicable mais c'est bien entendu dans le JIT que cette optimisation s'effectue.

Il existe de nombreuses règles permettant au JIT de décider s'il peut ou non effectuer l'optimisation. Voici un exemple de règles qui font qu'il n'est pas possible d'utiliser le tail-calling (par force cette liste peut varier d'une implémentation à l'autre du JIT) :

  • L'appelant ne retourne pas directement après l'appel;
  • Il y a une incompatibilité des arguments passés sur la pile entre l'appelant et l'appelé ce qui imposerait une modification des arguments pour appliquer le tail-calling;
  • L'appelant et l'appelé n'ont pas le même type de retour (données de type différents, void);
  • L'appel est est transformé en inline, l'inlining étant plus efficace que le tail-calling et ouvrant la voie à d'autres optimisations;
  • La sécurité interdit ponctuellement d'utiliser l'optimisation;
  • Le compilateur, le profiler, la configuration ont coupé les optimisations du JIT.

Pour voir la liste complète des règles, jetez un oeil à ce post.

Intérêt de connaitre cette optimisation ?

Normalement les optimisations du JIT ne sont pas un sujet intéressant au premier chef le développeur. D'abord parce qu'un environnement managé comme .NET fait qu'à la limite ce sont les optimisations du code IL qui regarde directement le développeur et beaucoup moins la compilation native qui peut varier d'une plateforme à l'autre pour une même application. Ensuite il n'est pas forcément judicieux de se reposer sur les optimisations du JIT puisque, justement, ce dernier peut être différent sans que l'application ne le sache.

Qui s'intéresse à l'optimisation du tail-calling alors ? Si vous écrivez un profiler c'est une information intéressante, mais on n'écrit pas un tel outil tous les jours... Mais l'information est intéressante lorsque vous déboguez une application car vous pouvez vous trouver face à une pile d'appel qui vous semble "bizarre" ou "défaillante" car il lui manque l'une des méthodes appelées !

Et c'est là que savoir qu'il ne faut pas chercher dans cette direction pour trouver le bug peut vous faire gagner beaucoup de temps... Savoir reconnaître l'optimisation de tail-calling évite ainsi de s'arracher les cheveux dans une session de debug un peu compliquée si on tombe en plus sur un pile d'appel optimisée. Un bon debug consiste à ne pas chercher là où ça ne sert à rien (ou à chercher là où c'est utile, mais c'est parfois plus difficile à déterminer !), alors rappelez-vous du tail-calling !

Et stay tuned !

nota: le présent billet est basé sur un post de l'excellent blog ASP.NET Debugging

Debug ou Cracking ? Des outils .NET à la frange des deux mondes...

Un debugger comme celui de Visual Studio n'est que rarement comparé à un outil de cracking pour la bonne raison que son utilisation s'effectue systématiquement (ou presque) sur des applications en cours de développement / maintenance, impliquant que l'opérateur du debug a le droit d'accéder aux sources. Mais comment catégoriser les outils qui suivent ?

Les trois outils dont je vais vous parler aujourd'hui se situent tous à la limite entre debugging et cracking, non pas forcément par la volonté de leur concepteur mais bien par leur nature. Il s'agit en fait d'applications autonomes capable de percer les secrets d'applications .NET en cours de fonctionnement (2 outils sur les 3 pour être précis, l'un est un visualisateur pour VS).

Outils de debug très intéressants ne nécessitant pas forcément l'installation de VS sur la machine, ces applications sont des compagnons à mettre dans votre boîte à outils. Utilitaires autonomes pouvant être utilisés par n'importe qui, l'existence même de ces outils ouvre la voie à un cracking autrement plus simple que l'utilisation d'outils comparables pour Win32. La haute cohérence de .NET et sa "lisibilité" rendant l'opération moins ardue.

Anges ou Démons ?

Les objets n'ont pas d'âme (si tant est que les êtres vivants en aient une) mais surtout ils n'ont pas de conscience. De tels outils ne peuvent donc être taxés en eux-mêmes d'être "diaboliques". C'est l'Homme qui appuie sur la gâchette que l'on juge et condamne, non les particules de poudre et l'amorce ayant permis à la balle de sortir de l'arme... A vous d'en faire bonne usage donc. Le plus important étant même de savoir que de tels outils existent pour éventuellement réfléchir, pour des applications sensibles, à comment rendre inopérantes des attaques qui utiliseraient cette approche.

Les outils

Crack.NET

Ecrit par Josh Smith, cet outil est un "logiciel de débogage et de scripting qui vous donne accès à l'intérieur de toute application .NET desktop" (d'après la traduction de la présentation de l'auteur). Une fois lancé l'utilitaire permet de choisir l'application .NET à cracker (selon les termes mêmes du bouton de lancement). Visualiser la mémoire, traverser les grappes d'objets, il est ainsi possible de tracer l'état de l'application "victime". Imaginons un mot de passe de connexion à une base de données ou à un Service Web, même si l'exécutable est obfusqué, même si les valeurs sont cryptées sur disque, il devient possible de lire ces dernières en clair une fois en mémoire de l'application.

On flirte avec la limite cracking / debugging, mais encore une fois l'intention coupable ou non est du ressort de la conscience de l'utilisateur de l'outil.

Un outil à posséder donc.

http://joshsmithonwpf.wordpress.com/cracknet/

Mole

Mole est un outil un peu différent, c'est un visualisateur pour Visual Studio qui permet de plonger dans les arborescences d'objets, de visualiser les valeurs mais aussi de les modifier.

En tant qu'outil pour VS la frontière du cracking s'éloigne, celle du debugging étant plus clairement visible.

"Mole a été conçu pour permettre au développeur non seulement d'afficher des objets ou des données, mais aussi de percer et visualiser les propriétés de ces objets, puis de les modifier. Mole permet un nombre illimité d'objets et de sous-objets en cours d'inspection. Quand Mole trouve un objet IEnumerable, les données peuvent être visualisées dans une DataGridView ou dans une grille de propriétés. Mole gère facilement les collections qui contiennent plusieurs types de données. Mole permet aussi au développeur de voir les champs non publics de tous les objets. Vous pouvez apprendre beaucoup sur le framework. NET en inspectant ainsi les données de vos applications."

http://karlshifflett.wordpress.com/mole-for-visual-studio/

Snoop

"Snoop est un utilitaire conçu pour simplifier le débogage visuel des applications WPF à l'exécution."

Un peu comme Crack.NET il s'agit ici d'un utilitaire autonome permettant d'inspecter une application WPF lors de son exécution. Cela peut s'avérer très utile en debug, mais peu présenter certains risques entre de mauvaises mains...

 

En tout cas, si vous développez des applications WPF, il faut avoir Snoop, il peut fournir une aide appréciable en plus du debug sous VS.

http://blois.us/Snoop/

Conclusion

Objets inanimés avez-vous une âme ? Questionnait Lamartine. Les objets numériques qu'il n'a pas connus n'en ont ni plus ni moins que les objets physiques en tout cas. Cracker ou debugger, c'est à vous de voir avec votre conscience, mais dans tous les cas, il est important de connaître l'existence de tels outils qui peuvent s'avérer bien pratiques dans certaines circonstances.

Stay Tuned !