La complexité involontaire

Publié par David Beaumier le vendredi 26 juillet 2013 à 17:07

Comme développeur nous avons tous à lire et surtout, à comprendre le code écrit par d'autres personnes. Que ce soit pour modifier une fonctionnalité existante ou pour effectuer une forme de rétro-ingénierie, il est primordial de ne pas avoir à s'arracher les cheveux de la tête pour comprendre l'intention du code. Or, hélas, trop souvent ce n'est pas le cas.

Il peut y avoir plusieurs causes à cette situation : méthode trop longue, mauvais nommage, non-respect des règles de nomenclature, etc. Ceci dit, je crois que bien souvent le code ne s’est pas retrouvé dans cet état dès le départ. J’aurais plutôt tendance à blâmer la vilaine complexité involontaire. Non, il ne s’agit pas d’une maladie contagieuse ou d’un mal contre lequel votre anti-virus pourra vous protéger. C’est plutôt comme la moisissure sur le fromage : ça apparaît après un certain temps et plus rapidement si on le manipule fréquemment sans prendre les précautions nécessaires!

Prenons un exemple dans le domaine d’affaires de l’assurance pour illustrer le processus. Une personne a créé au départ une structure de contrôle pour ne traiter que les polices à renouveler au cours des 30 jours à venir. Assez simple, n’est-ce pas?

if (p.DateRenouvellement < Now.AddDays(30)) {
  TraiterRenouvellement(p);
}

Quelques temps plus tard, un collègue a implémenté une nouvelle règle d’affaires dans le traitement pour répondre à un besoin de l’entreprise.

if (p.DateRenouvellement < Now.AddDays(30)) {
  if (Date.Now.Year - p.Client.EstClientDepuis.Year > 10) {
    var rabais = 0.1;
    TraiterRenouvellement(p, rabais);
  }
Else {
  TraiterRenouvellement(p, 0);
}

Par la suite, une autre demande est venue s’ajouter et une autre personne est venue modifier la fonction.

if (p.DateRenouvellement < Now.AddDays(30)) {
  if (Date.Now.Year - p.Client.EstClientDepuis.Year > 10) {
    var rabais = (Date.Now.Year - p.Client.EstClientDepuis.Year)/100;
    TraiterRenouvellement(p, rabais);
} }

Et ainsi de suite, jusqu’à ce qu’on ait une méthode de 125 lignes, ou même plus! Bien qu’avec le recul on puisse identifier différents éléments qui auraient pu être faits pour réduire la complexité, le plus souvent on ne peut accuser les gens de mauvaise foi. C’est plutôt une spirale sournoise dans laquelle l’équipe s’est engagée s’en trop s’en rendre compte… Jusqu’au jour où on ne s’y retrouve plus!

Favoriser la lisibilité du code source

Barbara Liskov (bien connue pour avoir donné son nom au Liskov Substitution Principle) mentionnait dans une récente entrevue que l’on devrait accorder plus d'importance à la lisibilité du code qu'à son écriture (read-ability VS write-ability). Les compilateurs, éditeurs de code et autres outils de développement offrent une panoplie de fonctions qui tendent à réduire le nombre de lignes de code source. Cependant, est-ce qu'on y gagne réellement au change?

Je pense, par exemple, à la fonctionnalité de Resharper qui permet de convertir une boucle en une expression LINQ. Oui, il y a des cas où cela peut-être bénéfique, mais il y a aussi bien des cas où, en fin de compte, on aura perdu une part de lisibilité du code dans l'opération.

Quelques façons d’éviter la complexité involontaire

Il existe différentes façons de s’entraîner à développer sa capacité à détecter les pièges de la complexité involontaire. De façon générale il faut débuter par accepter de sortir de sa zone de confort et graduellement apprendre à prendre un peu de recul et évaluer le code que l’on produit ou modifie.

Plusieurs excellents ouvrages de référence ont été publiés sur le sujet. C’est un bon point de départ pour quiconque veut approfondir ces techniques. Voici quelques suggestions :

Revues de conception

Pourquoi ne pas ajouter la notion de revue de conception ou de test par un pair à la définition d’avoir terminé de votre équipe? Chacun s’assure qu’au moins une autre paire d’yeux a jugé son travail et en a validé la conformité aux standards de l’équipe. C’est une étape qui permet de détecter rapidement des éléments qui manquent de clarté et qui apparaissent ambigus pour une autre personne. Ça ne veut pas dire que vos collègues ont forcément raison et vous tort, mais ça vaut probablement la peine de tenir une brève discussion sur les aspects qui ont été soulevés durant la revue.

Bien que je trouve que la revue par un pair apporte la meilleure valeur pour l’équipe, je crois que l’on peut aussi faire preuve d’autocritique. Par exemple, pourquoi ne pas prendre un peu de temps chaque matin pour repasser le code qu’on a écrit la veille? Par comparaison, un ébéniste prend habituellement le temps de faire un montage à sec avant de coller les assemblages d’un meuble. Cela lui permet de vérifier toute anomalie et la corriger avant de faire le collage final. Oui, ça prend un peu de temps, mais c’est une étape qui lui permet de s’éviter d’éventuels ennuis.

Métriques du code

En plus des évaluations qualitatives dont on vient de discuter, la complexité du code peut se mesurer de façon quantitative. Il existe plusieurs mesures, telles que la complexité cyclomatique, l’index de maintenabilité, le niveau de profondeur des structures de contrôle et la cohésion.

Il existe aussi des outils d’analyse statique du code qui permettent d’assurer le respect des règles de développement de l’équipe (nomenclature, etc.). Plusieurs de ces outils sont gratuits (tel que Source Monitor) ou même intégrés directement aux IDEs (comme le propose Visual Studio).

Conclusion

Développer et maintenir un système c’est comme une partie d’échecs. On doit penser quelques coups d’avance, tout en étant capable de réagir aux mouvements de l’adversaire. Il revient à chacun de trouver le juste équilibre entre perfection et livraison, mais il convient, à mon avis, d’identifier le seuil minimal que vous vous engagez à respecter. Lorsque le contexte ne vous permet pas de rencontrer ce seuil, n’hésitez pas à rendre cette situation visible à l’équipe et à discuter de la possibilité d’ajouter un élément au carnet de produit pour revoir cette partie du code source à un moment qui sera plus opportun (tel qu’au début du prochain cycle de livraison).

J’ai un jour entendu une personne dire ceci : "Écrivez votre code comme si celui ou celle qui en fera la maintenance était un psychopathe dangereux qui connaît votre adresse". C'est peut-être un peu extrême, mais ça m'a toujours forcé à me mettre dans la peau de la personne qui allait devoir comprendre mon code en m'efforçant de réduire le plus possible la complexité de celui-ci. Bon développement!

blog comments powered by Disqus

0 Comments:

Post a comment

Comments have been closed for this post.