À l'occasion de l'évolution majeure du logiciel wxMidiPiano (un piano virtuel téléchargeable), un problème tout bête s'est produit : l'interdépendance des #includes empêchait la compilation du nouveau code réorganisé. La nouvelle version utilise en effet beaucoup plus de types et de classes, ce qui a accru les dépendances internes. Il n'est pas nécessaire de tâtonner pour résoudre ce problème, voyons comment.
La directive #include en C++ fonctionne hiérarchiquement en prenant le contenu d'un fichier pour le mettre dans un autre. Ensuite, le code résultant est interprété de haut en bas. Pour éviter de faire des inclusions à l'infini, chaque fichier inclus contient un mot-clé particulier à base de pragma once ou d'ifdef. Mais cela masque la structure incomplètement hiérarchique du code, et des boucles empêchant la compilation peuvent apparaître. La solution consiste alors à épurer tous les includes non nécessaires.
Le principe est que si le fichier A inclut B qui inclut C, alors il n'est pas nécessaire techniquement de dire à A d'inclure C. Si chaque fichier d'entête (.h) est le nœud d'un graphe, alors chaque include entre 2 fichiers est une arête. Aussi, s'il existe un lien fonctionnel illogique entre 2 fichiers, il faut pouvoir retirer ce lien sur le plan technique. L'idée est de rendre le graph le plus planaire possible. Ce terme n'est pas exact, mais plus il sera simplifié et plus la logique de compilation sera facilitée. À partir de tout sommet, vous devez pouvoir arriver au point terminal par tout chemin le plus «naturellement» possible. Enfin, la compréhension de votre code n'en sera qu'améliorée.
Après une coloration et un alignement thématique, voici aujourd'hui comment le graphe se présente. Il montre clairement la structure optimisée du programme et les liens fonctionnels logiques entre chaque fichier. Il n'y a qu'une référence circulaire entre vsheet et export, mais elle ne pose pas de problème puisque vsheet n'a qu'une seule sortie vers l'appelant protégé contre les includes récursifs :
Dans la précédente version du programme, plusieurs liens en rouge n'allaient pas et certains fichiers n'étaient pas fonctionnellement reliés. Ce n'est pas pour rien que la restructuration du code a pris plusieurs jours, mais l'exercice est salutaire pour repartir d'une base plus solide. Les versions dites majeures sont synonymes de grands bouleversements techniques internes.
L'objet n'est pas de dire que l'ancien code était mauvais. Pas du tout. Un logiciel suit une certaine logique dans sa construction, mais l'ajout de nouvelles fonctions finit par rendre la structure complexe. Cette approche de simplification des includes avec un graphe est intéressante et facile à mettre en œuvre avec l'outil dot
de GraphViz.