Un code lisible se remarque d'abord par les noms des variables et des fonctions utilisées. En Fortran, il y a 20 ou 25 ans, alors que certains de nos parents s'occupaient de nous faire naître (c'est pour situer...), d'autres se creusaient la tête pour trouver des noms de variables et de fonctions car ils n'avaient que six lettres maximum. L'écriture d'un grand programme nécessitait soit une excellente mémoire, soit des normes très rigoureuses sur les noms des fonctions, les deux étant le mieux. A cette époque, une personne maîtrisant le code de son programme avait un emploi assuré tant que le logiciel fonctionnait car personne d'autre n'était capable de reprendre le logiciel facilement. A cette époque, il était nécessaire d'écrire un descriptif pour chaque fonction, avec le nom de la fonction, son rôle en une ligne (pour les recherches), son principe de fonctionnement et autres éventuels commentaires.
Aujourd'hui, avec des langages plus évolués comme le C, le C++, le Java, Perl, Python et d'autres, ces noms de variables et de fonctions ont une longueur au choix du programmeur, et les caractères admis sont nombreux. Il est donc maintenant facile de suivre au moins deux règles:
utiliser des noms explicites, qui résument le rôle de la variable ou de la fonction rien que par leur nom;
utiliser des normes pour ces noms, comme la norme GNU qui consiste à tout mettre en minuscules et de séparer les mots par le caractère de soulignement "_", ou comme la norme Java qui attache tous les mots, mais dont chaque mot sauf le premier commence par une majuscule.
La première règle implique de plus qu'une fonction exécute l'action décrite dans le nom et rien de plus ni de moins. Ainsi, la fonction int file_exists(char*) doit tester si le fichier existe ou non, mais ne doit en aucun cas l'ouvrir. Mais on pourra avoir aussi FILE* fopen_file_if_it_exists(char*) qui teste si le fichier existe, et qui dans ce cas ouvre le fichier et renvoit le descripteur.
Utilisez donc des noms longs, mais ne tombez pas dans l'exces non plus. Une variable locale à un bloc d'instructions ou à une petite fonction n'a pas forcement besoin d'un nom long. C'est le cas des variables i et j qu'on trouve dans les boucles: gardes i et j. C'est aussi le cas d'un descripteur de fichier pour un fichier qu'on ouvre et qu'on referme 5 lignes plus bas. Utilisez fd comme nom de variable pour le descripteur, pas un nom de 15 caracteres!
Un piège en C est la gestion des pointeurs et de la mémoire. Si vous passez un pointeur (une chaîne de caractères est un pointeur en C) à une fonction, il est hors de question que cette fonction libère la mémoire allouée sur laquette pointe le pointeur. A moins bien sur que ce ne soit le rôle de cette fonction (desctructeur de structure par exemple: void free_mystruct(mystruct*)). Inversement, certaines fonctions renvoient des pointeurs sur des structures de données. Et certaines de ces fonctions ont elles-même alloué la mémoire alors que d'autres utilisent de la mémoire déjà allouée. Il faut donc bien identifier les deux types de fonctions pour savoir quand libérer la mémoire et quand ne surtout pas la libérer. Le C nous aide partiellement dans cette identification en définissant les types const *. Ainsi, const char * renvoit_chaine(void) renvoit une chaîne de caractères dont il ne faut pas libérer l'espace alloué.
Un autre point où la cohérence est primodiale se trouve lors de l'écriture de librairies. Quand on commence un projet (par exemple, l'excellentissime the gimp, on écrit des fonctions, qui un jour, sont séparées du programme pour faire partie d'une librairie. Petit cours d'histoire abrégé: la librairie en question s'appelle maintenant gtk+, mais contenait gdk, gtk et glib. Puis glib a elle-même été détachée de gtk+ pour en faire une librairie indépendante. Revenons-en à nos moutons: pour avoir un minimum de cohérence, toutes les fonctions de gtk+ ont du commencer par le préfixe gtk_ (ou gdk_ pour gdk et g_ pour glib). Cela a permis de savoir quand une fonction faisait partie de gtk+ ou du gimp. Dans vos programmes, si vous utilisez glib ou gtk+, les fonctions de ces librairies sont facilement reconnaissables par rapport aux votres grâce à leur préfixe. Si vous écrivez votre propre librairie ou que vous êtes amené à en écrire une avec les fonctions d'un programme distinct, vérifiez que toutes les fonctions (même celles qui ne sont pas visibles dans le fichier d'en-tête) commencent par un préfixe propre à votre librairie. Et vérifiez aussi que votre programme dont est extraite la librairie si c'est le cas, ne contient plus de fonctions avec ce préfixe.
La cohérence apparaît encore là où vous écrivez des commentaires. En effet, il existe plusieurs types de commentaires. Si le fond est différent, il faut que la forme soit différente. Ainsi, les commentaires temporaires sont à éviter, et si l'on ne peut s'en passer (petit mémo pour la prochaine séance de programmation), il faut lui donner une forme bien particulière. /* MEMO: mon memo */ peut faire l'affaire. Idem, un autre commentaire, temporaire aussi, mais malheureusement moins temporaire: les commentaires sur un aspect du code qui devrait être amélioré ou réécrit. On trouve couramment ceci: /* FIXME: l'algo precedent ne traite pas tel cas rare */. Avoir une telle cohérence permet ensuite une recherche plus facile de ces commentaires. Un autre type de commentaire est la description d'une fonction et de ses paramètres. Plusieurs analyseurs de code proposent leur propre syntaxe de commentaires et génèrent des feuilles de documentation dans divers formats. Je vous laisserait pas sans citer le projet Doxygen qui propose une syntaxe simple et génère du html assez agréable à utiliser. Il propose plusieurs syntaxes de commentaire, et ma préférée est celle ci: /** commentaire pour doxygen */. Cette syntaxe consiste juste à ajouter une étoile aux commentaires classiques en C. Mais d'autres syntaxes sont plus appropriées aux autres langages comme C++ par exemple. Puis certains mots-clefs sont à apprendre pour plus d'efficacité, mais trois suffisent largement pour un début: \brief, \param et \return. Ainsi, une fonction pourra ressembler à ceci:
/** \brief renvoit le maximum de deux entiers ou 0 si demande. \param a entier \param b entier \param use_0 si non null, renvoit 0 si max(a,b) < 0 \return max(a,b) ou max(a,b,0) si use_0 est non null */ int max_0(int a, int b, int use_0) { etc.
Je vous laisser vous reporter au site de doxygen http://www.doxygen.org pour de plus amples informations sur la syntaxe ou sur l'installation: c'est libre!
© 2001 Yves Mettier