Conventions de codes, clean code, et autres – CheckIt

On parle souvent de conventions de code dans les entreprises, c’est-à-dire qu’on cherche à uniformiser le code. Les premières questions que je pose en arrivant sur un projet sont souvent :

  • Utilise-t-on la convention CamelCase ?
  • Est-ce que l’on met un underscore pour les champs ? Voir un double underscore pour les variables ?
  • Doit-on préfixer nos appels de membres par « this. » ?

Nombreuses sont les conventions qui changent en fonction des sociétés. Je ne cherche jamais à imposer les miennes, par contre, je souhaite que l’on se mette d’accord sur une manière de coder.

Personnellement, j’aime bien l’outil StyleCop. Toutefois, si l’on veut changer les conventions, cela devient peu flexible. On doit créer sa propre assembly. Ajouter un fichier xml, …  Ajouter une règle StyleCop

Pour automatiser StyleCop sur une usine de Build, cela est un peu compliqué surtout si vous n’avez pas la main sur l’usine. Il faut installer le plugin pour msbuild et ajouter les imports nécessaires dans le fichier .csproj. (Msbuil intégration)
En général, je compose avec les règles de base de StyleCop.

J’ai voulu alors développer des tests unitaires dans le but de vérifier mon code. Je peux les lancer quand je le souhaite. Ils seront exécutés pendant la Build sur le serveur. C’est un peu violent, mais les développeurs seront obligés de suivre ces règles. Si ces TU sont bien faits, pas besoin d’expliquer les règles, pas besoin non plus d’avoir une doc (que personne ne lit) pour les expliquer.

Je vous propose de suivre mon parcours dans la création de ce framework.

Par où commencer ?

Comme tout bon développement en TDD, on commence par des TU. J’ai donc écrit la syntaxe que je souhaitais pour vérifier un cas de base.
Je voudrais vérifier que les class d’une certaine assembly respectent une expression régulière. Ce qui donne :

[Fact]
public void Should_check_name_of_all_class()
{
    Check.Assembly("MyProject.dll").Class().Name().Match("^[A-Z].+$");
}

J’utilise xUnit pour développer mon Framework, mais les règles marchent pour tous les types de Framework de test unitaire.

Après le test, il faut que cela compile et que j’exécute mon test. Il plante (Normal, je n’ai pas encore implémenté le code).

Je vous passe l’implémentation exacte. Comment ai-je fait ? Je load les assemblies que je trouve et je parcours les classes pour vérifier leur nom. Ça marche mais j’ai plein de problèmes avec des classes créées automatiquement et des références d’assemblies qui ne m’appartiennent pas.

Après pas mal de code écrit, je trouve enfin la solution : Roslyn. Pas de problème, j’ai fait du TDD.

Roslyn est le compilateur open source de C#/VB.NET, ce qui me permet de parcourir l’arbre syntaxique du code. Je vous recommande d’aller voir la documentation sur GIT Roslyn

Mes prochaines étapes.

Maintenant que j’ai une base de travail, je vais pouvoir aller plus loin dans mes réflexions. Je voudrais proposer des méthodes de matching toutes faites (CamelCase,…), mais aussi proposer les règles de StyleCop sous forme d’un autre package. Peut- être également y ajouter le support de vb.net.
J’ai une branche sur laquelle je réfléchis pour intégrer de nouvelles fonctionnalités et avoir une écriture plus fluent. L’idée est de décrire sous forme plus lisible des conditions.
Exemple : Pour le cas de base que j’ai détaillé au dessus, je suis arrivé au résultat suivant :

[Fact]
public void Should_check_name_of_all_class()
{
    Check.Class().FromAssembly("MyProject.dll").Have().Name().Match("^[A-Z].+$");
}

Je voudrais vérifier que certains namespace ne contiennent que des interfaces.

[Fact]
public void Should_check_namespace_interfaces_contains_only_interfaces()
{
    Check.Type().FromNameSpace("MyProject.Interfaces").Contains().Only().Interface();
}

Ou vérifier que dans tous les projets de tests, les classes se terminent par Tests.

[Fact]
public void Should_check_class_name_end_with_tests()
{
    Check.Project("*.Tests.csproj").Contains().Only().Class("Tests$");
}

Ensuite, je voudrais aller plus loin dans l’ajout de contraintes sur les références des projets : empêcher que les data access soit référencés dans le projet client… Beaucoup d’idées à implémenter dans ce framework. L’avantage, c’est que j’utilise mes TU comme des specs.

En bref

En bref, pour le moment c’est un petit Framework. Mais à chaque envie, je rajouterais de l’expressivité dans la syntaxe. Si vous avez des idées de contraintes que vous voulez implémentées, faites un fork de https://github.com/swoog/CheckIt. Ajoutez votre test. Modifiez le code pour respecter votre test (ou pas mais dans ce cas là, votre test doit connaître une erreur). Faites-moi une pull request, je l’intégrerai dans le Framework.

Une version est automatiquement compilée et packagée sur le Nuget de https://www.myget.org/feed/swoog/package/nuget/CheckIt. La version officielle est sur https://www.nuget.org/packages/checkit/

Et peut être qu’un jour, je pourrais écrire :

[Fact]
public void Should_all_project_are_beautiful()
{
    Check.Project().Contains().Only().BeautifulCode();
}
Tags: Conventions,

Pas de commentaire

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *