Analyse statique de programmes – avec NDepend 6.3.0

En tant que programmeur on connait la situation, un nouveau projet, un nouveau défi. D’abord c’est toujours recommandable de se bien organiser pour mieux comprendre les exigences. Puis c’est souvent le cas, qu’il y a déjà une base de codage existant qu’il faut analyser. Bien sûr, Visual Studio donne plusieurs outils pour faciliter la vie d’un développeur. Par exemple l’utile « Code Analysis » qui peut être trouvé dans la « properties fenêtre » d’un projet et qui peut être utilisé avec Native Code et Managed Code. Néanmoins cette solution ne suffit pas toujours pour les besoins d’un développeur, c’est pourquoi il y a des alternatives sur le marché. Une telle solution, très populaire, est NDepend. En tout cas NDepend peut être utilisé avec Managed Code in .NET.

Une analyse statique d’un programme peut par exemple réduire les couts d’une erreur et le nombre des erreurs. Puis cela peut faciliter la maintenance d’un codage, parce que les développeurs découvrent la base de code et peuvent apprendre des bonnes pratiques.

Dans cet article je vais d’abord écrire le fond d’une analyse statique de programmes et pourquoi on peut recommander d’utiliser un outil comme NDepend, pour mieux comprendre un codage existent de Managed Code. Dans un article suivant on regardera utilisation et les expériences dans un projet réel avec ASP.NET MVC.

Tout d’abord, la théorie…

L’analyse statique de programmes est l’analyse d’un logiciel sans [réellement] l’exécuter (Contrairement, l’analyse d’un logiciel pendant son exécution qui s’appelle l’analyse dynamique). C’est-à-dire, l’analyse statique permets d’obtenir des informations sur un programme.

Les objectifs d’une telle analyse peuvent être :

  • Bug alerts,
  • Style de codage,
  • Adapter les » best practices » (Naming conventions etc.)
  • Vérification de la performance

Quelques paramètres qui peuvent être utiles sont :

  • Sont tous les méthodes écrit en Pascal Case ?
  • Y-a-t-il des null references dans le codage ?
  • Est-ce qu’il y a des instances d’une programmation « copier/collier « ?
  • C’est quoi le moyen montant de lignes de codage dans une classe / une méthode ?
  • Est-elle loosely ou tightly coupled, l’architecture ?
  • Quelles sont les classes à changer ?

C’est recommandable d’utiliser un outil comme NDepend pour faire une analyse statique d’un logiciel. NDepend aide à comprendre le codage ou mettre des informations outils à la disposition. Cette solution a été créé par Patrick Smacchia et s’est développée pendant les années pour être utilisé dans un environnement des entreprises.

NDepend, actuellement en version 6.3.0, offre entre autres :

  • Personnalisation et application des règles
  • Une représentation visuel d’un codage
  • L’intégration dans un build
  • Trace de changements

Un premier demo de NDepend peut être télécharge sous NDepend.com et ajouté au Visual Studio en tant que Add-On. Le site web offre une bonne documentation. Dans un prochain article, je vais jeter un coup d’œil sur l’utilisation dans un projet réel.

Les Collections originals en C#

Dans beaucoup des applications on veut grouper des objets de la même famille. En C# il y a deux façons de grouper les objets : Arrays et Collections.

En général, les Arrays sont très outil, quand on travaille avec des objets strongly-typed d’un nombre fixe (fixed number of strongly-typed objects).

En outre, les Collections fournissent une façon beaucoup plus flexible de travailler avec des groupes d’objets. Dans une collection, le groupe des objets peut facilement grandir et diminuer pour atteindre les besoins d’une application. En plus pour quelques collections on peut assigner une clé à n’importe quel objet, pour rapidement aller chercher un objet en utilisant cette clé.

Microsoft propose pas mal de classes de collection, the generic collections, qui se trouvent dans le namespace System.Collections.Generic

Les plus importants sont probablement :

Collection Ordering Access
Dictionary Unordered Via Key
SortedDictionary Sorted Via Key
SortedList Sorted Via Key
List User has precise control over element ordering Via Index
LinkedList User has precise control over element ordering No
HashSet Undordered Via Key
SortedSet Sorted Via Key
Stack LIFO Only Top
Queue FIFO Only Front

En plus il y a le vieux namespace System.Collections qui est considéré comme obsolète par Microsoft et beaucoup des développeurs. Dans cet namespace il y a ArrayList, Hashtable, Queue, SortedList, Stack.

LINQ en C#

Dans un dernier article on a regardé la fonctionnalité des expressions lambda, donc les fonctionnes anonymes. Autrefois j’ai écrit un article sur le sujet méthodes d’extension, qui va nous donner une base de savoir-faire en plus, dans cet article autour de LINQ.

MSDN propose également un bon réseau d’informations autour de LINQ.

Mais tout d’abord c’est quoi LINQ ?

LINQ c’est un acronyme pour Language Integrated Query. Simplifié on pourrait dire que LINQ est une bibliothèque de classes, qui nous donne des méthodes d’extension pour l’interface IEnumerable. Cette bibliothèque est donc disponible dans toutes les classes qui implémentent cette interface. Par exemple List<T>, Array, ObservableCollection<T>. Grâce à LINQ les queries sur les Collections en C# sont plus facile.

En gros, il y a 4 bibliothèques différentes :

  • LINQ to Object : query Arrays et Collections
  • LINQ to DataSet : query DataTables dans les DataSets
  • LINQ to XML : query XML Documents
  • LINQ to SQL : query SQL ServerPour obtenir plus d’information sur LINQ on peut également consulter MSDN.

LINQ propose deux notations différentes :

  • Query syntax
  • Method syntax

La query syntax ressemble beaucoup à un statement SQL. Un exemple se trouve dans le codage au dessous.

Maintenant regardons nous le method syntax d’une méthode LINQ très importante :

System.Linq.Enumerable.Where<TSource>
(this System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,bool>)

Ici on voit qu’il y a deux paramètres. Le premier paramètre comporte le mot clé this. Selon le mot clé this on voit facilement, qu’il s’agît d’une méthode d’extension, qui se réfère au type IEnumerable<T>. Le deuxième paramètre est une méthode (delegate) qui retourne une valeur boolean. Voici un exemple concret :

namespace LINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            var animaux = new string[]{ "Caribou", "Ours", "Castor", "Baleine", "Beluga" };

            // Query syntax
            //var query = from a in animaux
            //            where a.StartsWith("B")
            //            select a;

            // Method syntax
            var query = animaux.Where(a => a.StartsWith("B"));

            foreach (var x in query)
            {
                Console.WriteLine(x);
            }

            Console.ReadKey();
        }
    }
}

Lambda en C#

Une expression Lambda c’est une fonctionne anonyme, qui peut être utilisé pour créer par exemple ses delegates. C’est-à-dire une fonctionne se transforme en une variable. En C# on utilise l’opérateur => pour indiquer une expression lambda.
Dans un dernier article autour de delegates on a vu qu’il y a Action<T> et Func<T>, ce qu’on peut utiliser pour enregistrer une méthode dans une variable, si la signature (la valeur retournée et la liste des paramètres) et la même chose que la signature du delegate.

namespace Lambda
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, double> mult = Multiply;

            var product = mult(3, 4);

            Console.WriteLine(product);

            Console.ReadKey();
        }

        private static double Multiply(int i, int j)
        {
            return i + j;
        }
    }
}

Si on ne veut qu’utiliser une méthode une seule fois par exemple, on peut utiliser une méthode anonyme :

namespace Lambda
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, double> mult = delegate(int i, int j)
            {
                return i + j;
            };

            Console.WriteLine(mult(3,4));

            Console.ReadKey();
        }
    }
}

On peut maintenant créer une expression lambda, on simplement raccourci le delegate en ne pas utilisant le mot clé delegate.

Func<int, int, double> mult = (int i, int j) =>
{
    return i + j;
};

Mais bien sûr on peut le raccourcir un peu plus :

Func<int, int, double> mult = (i, j) => i + j;

Factory patron de conception (Factory Design Pattern)

Le patron de conception Factory, l’un de GoF, a la fonctionnalité de créer  des objets. L’avantage du Factory c’est qu’on implémente une abstraction qu’isole la logique pour déterminer quelle classe sera utilisée pour créer un objet. C’est important que le patron de conception Factory utilise un interface ou une classe classe base.

factory

Voici un exemple :

namespace Factory
{
    /// <summary>
    /// Interface Animal
    /// </summary>
    interface IAnimal
    {
        string Name { get; }
    }

    /// <summary>
    /// Caribou Class
    /// </summary>
    /// <seealso cref="Factory.IAnimal" />
    class Caribou : IAnimal
    {
        public string Name
        {
            get { return "Caribou"; }
        }
    }

    /// <summary>
    /// Ours class
    /// </summary>
    /// <seealso cref="Factory.IAnimal" />
    class Ours : IAnimal
    {
        public string Name
        {
            get { return "Ours"; }
        }
    }

    /// <summary>
    /// Animal Factory
    /// </summary>
    class AnimalFactory
    {
        public static IAnimal CreateAnimal(int num)
        {
            IAnimal AnimalSelector = null;

            switch (num)
            {
                case 1:
                    AnimalSelector = new Caribou();
                    break;
                case 2:
                    AnimalSelector = new Ours();
                    break;
                default:
                    AnimalSelector = new Caribou();
                    break;
            }

            return AnimalSelector;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                var animal = AnimalFactory.CreateAnimal(i);
                Console.WriteLine("Id = {0}, position = {1} ", i, animal.Name);
            }

            Console.ReadKey();
        }
    }
}

Singleton patron de conception (design pattern) en C#

Le patron de conception Singleton, assure qu’une classe ne pêut que être instancié uniquement une fois et que la classe mets en place un point d’accées global.

singleton

La classe << Singleton >> défini une opération qui laisse l’accés à l’instance au client. En plus, elle est responsable pour la création et la maintenance de cette instance unique.

On utilise le singleton en général, quand

  1. on n’a qu’une seule instance et
  2. il faut gérer cette instance

En regardant l’anatomie d’une classe singleton, normalement le constructor est modifié private et l’accès public static.

Voici un exemple pour une classe Singleton, static initialization :

namespace Singleton
{
    /// <summary>
    /// Singleton class
    /// </summary>
    internal sealed class Singleton
    {
       private static Singleton _instance = null;
       

       private Singleton()
       {
       }

       public static Singleton Instantiate()
       {
          if (_instance == null)
       {
          _instance = new Singleton();
       }
          return _instance;
    }
 }

    /// <summary>
    /// Main program
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Singleton single1 = Singleton.Instanciate();
            Singleton single2 = Singleton.Instanciate();

            if (single1 == single2)
            {
                Console.WriteLine("single1 and single2 are the same instance");
            }

            Console.ReadKey();
        }
    }
}

Le problème dans cette solution << Singleton >> est que la classe singleton peut introduire des dependencies pas nécessaire et qu’elle peut être utilisé par plusieurs threads en même temps, donc elle pourrais créer plusierus instances. Par exemple dans un application Web, si il y a plusieurs HTTP requests. Un peu plus secoure c’est la façon lazy en utilisant un << thread locker >>. Dans ce cas là il faut modifier la classe sealed et référencer l’instance par le constructor.

Voici un exemple pour une classe singleton, lazy implementation .NET :

namespace Singleton
{
    /// <summary>
    /// Singleton class
    /// </summary>
    internal sealed class Singleton
    {
       private static Singleton _instance = null;
       private static readonly object _locker = new object();

    private Singleton()
    {
    }

    public static Singleton Instantiate
    {
       get
       {
          lock (_locker)
       {
          if (_instance == null)
          {
             _instance = new Singleton();
          }
       }
       return _instance;
     }
   }
 }

    /// <summary>
    /// Main program
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Singleton single1 = Singleton.Instantiate;
            Singleton single2 = Singleton.Instantiate;

            if (single1 == single2)
            {
                Console.WriteLine("single1 and single2 are the same instance");
            }

            Console.ReadKey();
        }
    }
}

Un bon exemple pour l’utilisation d’un singleton pourrais être un log file ou une classe pour configurer l’accés à un base de données. En plus on ne crée pas beaucoup des variables dans un namespace global.

Néanmoins il y a quelques désavantages, qui mettent en feu la discussion autour du patron de conception singleton:

  • n’utilise pas des abstract classes ou interfaces
  • pas de subclasses
  • difficile à tester
  • difficle de travailler parallèlement…

Quand même le singleton est souvent utilisé dans des projets grands et a sans doute une légitimation.

textarea avec tinyMCE et HTML character count

Peut-être vous cherchez la fonctionnalité de compter les caractères dans votre WYSIWYG editor, où vous voulez savoir comment mettre en place un bon editor comme le tinyMCE dans votre projet ASP.NET. Alors, cet article est pour vous.

tinyMCE est probablement le meilleur editor WYSIWYG sur le marché. En plus il est distribué sous la licence Open Source LGPL 2.1 et est donc gratuit à utiliser dans votre projet commercial !

Ensuite, un character counter ou compteur de caractères. D’abord il faut se poser la question : est-ce que un compteur de caractère dans un control rich text WYSIWYG fait du sens ?

Le problème, c’est que un tel control ajoute toujours du HTML au fond. Si ce n’est pas grave, voici la solution comment implementer dans un projet ASP.NET Web Forms le tinyMCE rich text edior avec un compteur de caractères.

tinyMCE

D’abord il faut considerer qu’on s’occupe de deux scènarios différents, l’editor est un control JavaScript et est donc << rendered >> sur le client d’un autre côté ASP.NET Web Forms travaille sur le serveur et offre des controls uniquement pour Web Forms. Néanmoins on peut utiliser le control TextBox de WebForms pour créer un tinyMCE WYSIWYG editor.

Voici l’HTML :

<h1>Tiny MCE Text Editor</h1>

<asp:TextBox ID="TextBox1" runat="server" CssClass="tinymce"></asp:TextBox>

<div style="float: right;">
   Total Characters(including trails): <span id="totalChars">0</span><br />
</div>

<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /

…et le JavaScript :

<%-- tinyMCE --%>
<script>

 function setCnt(editor) {
    var content = editor.getContent({ format: 'raw' });
    var count = content.length;
    $("#totalChars").html(count);
 };

 tinymce.init({
    selector: ".tinymce",
    theme: "modern",
    encoding: "xml", // decode html tags
    forced_root_block : false,
    setup: function (editor) {
       editor.on('change', function (e) { setCnt(editor) });
       editor.on('keyup', function (e) { setCnt(editor) });
    }
 });

</script>

…enfin, le code behind :

namespace tinyMCE
{
    public partial class _Default : Page
    {

        protected void Button1_Click(object sender, EventArgs e)
        {
            var message = HttpUtility.HtmlDecode(TextBox1.Text);
        }
    }
}

Comment ajouter un répertoire existant dans un Solution Visual Studio ?

Ça arrive souvent, qu’on a on a crée une bibliothèque soi-même ou une bibliothèque est pêut-etre indisponible sur NuGet ou un autre package manager dans le Visual Studio, mais il faut l’inclure dans un solution existant.

En fait, c’est facile avec Visual Studio. Il ne faut que copier et collier un répertoire dans le répertoire, retourner au Visual Studio, pousser le bouton << show all files >> clic droit le nouveau répertoire et choisir << include in project >>. Fini.

tinymc

Méthode d’extension C# (Extension Methods)

Les méthodes d’extension en C# offrent la possibilité d’ajouter de la fonctionnalité (des méthodes) aux types de données déjà existent dans le langage de programmation C#. L’avantage des méthodes d’extension est que ce n’est pas nécessaire de modifier un type de données ou de créer un nouveau type qui doit hériter d’un type existant. En effet, il n’y a pas de différence entre appeler une méthode d’extension ou d’appeler une méthode qui est définie dans un type de données.

Pour définir et appeler une méthode d’extension en C# il ne faut que respecter les règles suivants :

  1. Définir une classe static visible pour le client et comportant la méthode d’extension (p.ex. public).
  2. Implémenter la méthode d’extension avec la même visibilité que la classe et le mot clé static.
  3. Le premier paramètre de la méthode spécifie le type de donnés qui est élargi. Ce paramètre doit compter le modificateur this.
  4. Dans le code qui appelle la méthode il faut inclure le namespace qui comporte la méthode d’extension.
  5. Appeler les méthodes comme c’était une méthode instance de ce type de donnés.

Dans l’exemple suivant on jette un coup d’œil à la fonctionnalité d’une méthode d’extension lié à la classe String. Le but de cette méthode est de transformer les caractères à ignorer (blankspaces dans ce cas-là) dans un String.

public static class MyStringExtensions
{
  public static string ModifyWhitespaces(this string val)
  {
    return Regex.Replace(val, @"\s+", " ");
  }
}

// utilisation: 
var name = "Tino  !";
name = name.ModifyWhitespaces();