Aller au contenu

Building Maintainable Software

·989 mots·5 mins
Sommaire

En profitant d’une petite promo de -50% chez O’Reilly, je me suis offert l’ebook Building Maintainable Software, édition C-Tartine. Le livre propose de suivre une série de préceptes permettant d’améliorer la qualité du code produit. Bien que le contenu ressemble parfois plus à une grosse page marketing pour le Software Improvment Group, il reste intéressant et vaut le coup d’être lu. Deux petits problèmes par contre:

  1. On part parfois d’un cas concret (qui ressemble parfois à ce que j’ai pu commettre de code foireux), en prenant une méthode dans laquelle on trouve plusieurs concepts différents (appel à la db, cast vers une classe type DTO, validation d’input). Juste après, on passe directement sur un autre exemple, beaucoup plus simple à résoudre.
  2. J’ai l’impression que cela parle plus de théorie, sans proposer de solution automatique, ce qui rejoint un peu ce que je disais au niveau marketing: “si vous voulez vous améliorer, signez chez nous!”.

Les principaux conseils sont les suivants (pour les détails, il vous faudra acheter le bouquin 😛):

Au niveau des méthodes
#

  • Gardez vos méthodes/fonctions courtes. Pas plus de 15 lignes, en comptant les commentaires. Des exceptions sont possibles, mais dans une certaine mesure uniquement (pas plus de 6.9% de plus de 60 lignes; pas plus de 22.3% de plus de 30 lignes, au plus 43.7% de plus de 15 lignes et au moins 56.3% en dessous de 15 lignes). Oui, c’est dur à tenir, mais faisable.
  • Conserver une complexité de McCabe en dessous de 5, c’est-à-dire avec quatre branches au maximum. A nouveau, si on a une méthode avec une complexité cyclomatique de 15, la séparer en 3 fonctions avec une complexité de 5 conservera globalement le nombre 15, mais rendra le code de chacune de ces méthodes plus lisible, plus maintenable.
  • N’écrivez votre code qu’une seule fois: évitez les duplications, copie, etc., c’est juste mal: imaginez qu’un bug soit découvert dans une fonction; il devra alors être corrigé dans toutes les fonctions qui auront été copiées/collées. C’est aussi une forme de régression.
  • Conservez de petites interfaces. Quatre paramètres, pas plus. Au besoin, refactorisez certains paramètres dans une classe, plus facile à tester.

Au niveau des classes
#

  • Privilégiez un couplage faible entre vos classes. Ceci n’est pas toujours possible, mais dans la mesure du possible, éclatez vos classes en fonction de leur domaine de compétences. L’implémentation du service UserNotificationsService ne doit pas forcément se trouver embarqué dans une classe UserService. De même, pensez à passer par une interface (commune à plusieurs classes), afin d’ajouter une couche d’abstraction. La classe appellante n’aura alors que les méthodes offertes par l’interface comme points d’entrée.

Au niveau des composants
#

  • Tout comme pour les classes, il faut conserver un couplage faible au niveau des composants également. Une manière d’arriver à ce résultat est de conserver un nombre de points d’entrée restreint, et d’éviter qu’on ne puisse contacter trop facilement des couches séparées de l’architecture. Pour une architecture n-tiers par exemple, la couche d’abstraction à la base de données ne peut être connue que des services; sans cela, au bout de quelques semaines, n’importe quelle couche de présentation risque de contacter directement la base de données, “juste parce qu’elle en a la possibilité”. Vous pourrez également passer par des interfaces, afin de réduire le nombre de points d’entrée connus par un composant externe (qui ne connaîtra par exemple que IFileTransfer avec ses méthodes put et get, et non pas les détails d’implémentation complet d’une classe FtpFileTransfer ou SshFileTransfer).
  • Conserver un bon balancement au niveau des composants: évitez qu’un composant A ne soit un énorme mastodonte, alors que le composant juste à côté n’est capable que d’une action. De cette manière, les nouvelles fonctionnalités seront mieux réparties parmi les différents systèmes, et les responsabilités plus faciles à gérer. Un conseil est d’avoir un nombre de composants compris entre 6 et 12 (idéalement, 12), et que ces composants soit approximativement de même taille.

Et de manière plus générale
#

  • Conserver une densité de code faible: il n’est évidemment pas possible d’implémenter n’importe quelle nouvelle fonctionnalité en moins de 20 lignes de code; l’idée ici est que la réécriture du projet ne prenne pas plus de 20 hommes/mois. Pour cela, il faut (activement) passer du temps à réduire la taille du code existant: soit en faisant du refactoring (intensif?), soit en utilisant des librairies existantes, soit en explosant un système existant en plusieurs sous-systèmes communiquant entre eux. Mais surtout en évitant de copier/coller bêtement du code existant.
  • Automatiser les tests, ajouter un environnement d’intégration continue dès le début du projet et vérifier par des outils les points ci-dessus.

Ceci est sans doute un des points les plus ennuyants de ce livre: il n’y a finalement que très peu d’exemples concrets, notamment pour la mise en place d’un tel environnement. Ok, ça parle de Jenkins du début à la fin, mais plus comme un exemple à suivre (ou parfois à ne pas suivre) que comme un outil à utiliser. De manière plus générale, j’ai l’impression que le code .Net reste extrêmement fermé à des outils open source permettant d’augmenter la qualité du code. Il existe des linters pratiquement pour tous les langages, mais si vous voulez quelque chose de fonctionnel pour C#, il va falloir passer par la caisse. Une stratégie MS classique en sommme: “on vous offre les outils pour pas grand chose, et pour aller plus loin, vous douillez”.

Pour aller plus loin
#

En regardant un peu à droite-à gauche, pour du code .Net, les outils suivants ont l’air sympa, comme:

  • SonarLint (en cli, intégré dans un IDE ou en mode CI) (dont je ne peux plus me passer :-) )
  • StyleCop
  • Refactoring Essentials
  • CodeMaid, pour un code propre et soyeux. En zieutant la description, on trouve que CodeMaid is an open source Visual Studio extension to cleanup, dig through and simplify our C#, C++, F#, VB, PHP, JSON, XAML, XML, ASP, HTML, CSS, LESS, SCSS, JavaScript and TypeScript coding.