Questions de nomenclature

« The lazy habit of shoving 'get' on the front of method names can encourage ambiguous names, e.g., getEntryNumber instead of numberOfEntries » – Kevlin Henney (source)

Bien nommer les entités qui apparaissent dans nos programmes (variables, constantes, classes, fonctions, etc.) est plus difficile qu'il n'y paraît à première vue. Pourtant, le choix d'un nom est un geste crucial à bien des égards.

Une réflexion personnelle sur la question suivra, quand j'aurai quelques minutes, mais en attendant, voici quelques réflexions d'autres individus. Ceci vous aidera peut-être à vous forger une vision personnelle :

Ce que je fais, personnellement

Tout d'abord, la priorité pour quiconque souhaite un emploi (et le garder!) est de respecter les standards en place (par exemple, celles de Java, celles de .NET, celles de Google, etc.). Parfois, ceux-ci s'imposent d'office, et quelques règles simples peuvent servir de base à la réflexion.

Au fil des ans, mes usages ont changé quant au recours aux majuscules, aux minuscules et aux soulignements (ce qui transparaît sans doute dans les exemples sur ce site, qui ont été écrits sur une période de plusieurs années). Je tends maintenant à me limiter aux minuscules et aux soulignements (pour séparer les mots). Le recours à des mots français ne me pose pas de problème, mais si vous oeuvrez pour une entreprise qui privilégie des noms anglais ou autre chose, évidemment, respectez les normes en place.

En pratique, pour mon propre code, ce que je fais ressemble à ce qui suit.

Fonctions, méthodes, procédures

J'essaie d'utiliser des verbes pour mes noms de fonctions et pour mes noms de méthodes, outre pour des noms consacrés comme sin() pour la fonction de calcul du sinus.

Quelques exemples apparaissent à droite :

  • Remarquez le choix d'un verbe d'état comme préfixe au nom du prédicat est_pair(). Ceci permet des écritures comme if (est_pair(n)) pour un entier n donné, par exemple, qui sont naturelles
  • Dans le cas de calculer_paie(), le recours à un nom composé me paraît plus clair que calculer() ou paie(), des noms derrière lesquels les vocations des fonctions pourraient sembler opaques ou ambiguës
  • Quand un concept peut être nommé, j'en fais habituellement un type, souvent une classe. À droite, la classe Cash porte un nom significatif. Remarquez la correspondance entre les noms des méthodes et les concepts qu'elles représentent :
    • la méthode dollars() expose les dollars d'une instance de Cash, tout comme la méthode sous() expose les sous d'une instance de Cash
    • remarquez l'absence de mutateurs (de méthodes Set()), et le recours à des noms simples pour des accesseurs (dollars() plutôt que GetDollars(), par exemple)
    • la comparaison se fait naturellement avec les opérateurs == et !=
  • Enfin, le nom carre() pour le calcul du carré d'un nombre me semble clair et permet des écritures comme y = carre(x); qui, à mon avis, sont plus évidentes que ne le serait quelque chose comme y = calculer_carre(x); étant donné les us et coutumes mathématiques
bool est_pair(int);
template <class T>
   T carre(T val) {
      return val * val;
   }
class DollarsInvalides {};
class SousInvalide{};
class Cash {
   int dollars_, sous_;
   static constexpr bool est_dollars_valide(int valeur) {
      return !(valeur < 0);
   }
   static constexpr bool est_sous_valide(int valeur) {
      return !(valeur < 0 || 99 < valeur);
   }
   static constexpr int valider_dollars(int valeur) {
      return est_dollars_valides(valeur)? valeur : throw DollarsInvalide{};
   }
   static constexpr int valider_sous(int valeur) {
      return est_sous_valides(valeur)? valeur : throw SousInvalide{};
   }
public:
   int dollars() const {
      return dollars_;
   }
   int sous() const {
      return sous_;
   }
   constexpr Cash(int dollars, int sous)
      : dollars_{valider_dollars(dollars)}, sous_{valider_sous(sous)}
   {
   }
   constexpr Cash() : Cash{0, 0} {
   }
   constexpr bool operator==(const Cash &autre) const {
      return dollars() == autre.dollars() &&
             sous() == autre.sous();
   }
   constexpr bool operator!=(const Cash &autre) const {
      return !(*this == autre);
   }
   // autres membres...
};
Cash calculer_paie
   (int nb_heures, const Cash &salaire_horaire);

Types, classes, enregistrements

Pour les noms de classes, je préfère des noms reflétant des états (Carre, Forme, Couleur, pointeur_unique<T>) ou des capacités (Dessinable, Incopiable, Incompilable).

J'essaie d'éviter de la redondance dans les noms. Avec des classes, mieux vaut selon moi aller à l'essentiel. Ainsi, remarquez le choix du nom Couleur::DEFAUT plutôt que Couleur::COULEUR_DEFAUT pour la valeur par défaut d'une Couleur. Le nom de la classe me semble qualifier suffisamment le concept décrit. Notez d'ailleurs que, si plusieurs valeurs par défaut vous semblent nécessaires dans une classe, il est possible que le découpage de votre code soit perfectible.

Dans un cas où le nom d'un attribut ne compétitionne pas avec un nom de méthode (comme dans le cas de l'attribut p dans pointeur_unique<T>, à droite), je tend à omettre le suffixe _ pour garder le nom le plus naturel possible. Étonamment, je suis de plus en plus souvent capable de procéder ainsi (signe de sagesse, en vieillissant?).

Je tends à utiliser des noms débutant par une majuscule pour le code maison, destiné à des applications ponctuelles, et je tends à utiliser des noms débutant par des minuscules pour des types proches de ce qu'on peut retrouver dans les bibliothèques standards.

Évidemment, je pose un jugement de valeur quand j'écris ainsi; le code qui me semble à peu près de qualité commerciale et de nature réutilisable ressemble, à l'usage, au code des bibliothèques que nous utilisons tous de manière routinière.

Dans la même veine, mes types internes et publics collent le plus possible aux us et coutumes du standard du langage.

class Incopiable {
   // membres...
};
struct Dessinable {
   virtual void dessiner(std::ostream &) const = 0;
   virtual ~Dessinable() = default;
};
class Forme : public Dessinable {
   // membres...
};
class Couleur {
public:
   enum : short value_type {
      Rouge, Vert, Bleu
   };
private:
   value_type valeur_;
   static constexpr const value_type DEFAUT = Bleu;
   // membres...
};
class Carre : public Forme {
   Couleur couleur_
   // membres...
};
template <class T>
   class pointeur_unique : Incopiable {
   public:
      using value_type = T;
   private:
      value_type *p;
   public:
      pointeur_unique(value_type *p)
         : p{p}
      {
      }
      ~pointeur_unique() noexcept {
         delete p;
      }
      // autres membres
   };

Variables, constantes et attributs

J'ai tendance à utiliser des noms en majuscules pour les constantes connues à la compilation (et jamais pour les variables ou pour les types), mais pas nécessairement pour les constantes connues à l'exécution ou pour les paramètres const.

Vous aurez sans doute remarqué que, tel que recommandé par Boost et par messieurs Sutter et Alexandrescu dans leur livre C++ Coding Standards, je tends à apposer le suffixe _ aux noms de mes attributs. Cette écriture me semble claire et élégante, et facilite à la fois l'écriture d'initialisations à la préconstruction et celle d'accesseurs. Quand cela s'y prête, comme dans le cas du foncteur Afficher à droite, j'utilise même des noms d'attributs sans suffixe.

Je suis à l'aise avec des noms abstraits comme i ou j pour des compteurs entiers, x et y pour des nombres à virgule flottante, n pour une quantité entière ou encore p ou q pour des pointeurs. Cependant, je m'attends à ce que ces noms soient utilisés dans un espace très local (le plus localement possible), donc qu'ils aient une durée de vie très courte, à l'intérieur de laquelle leur rôle est évident. Une variable dont le rôle est plus défini ou dont la portée dépasse celle d'une fonction très générale de deux ou trois lignes mérite en général un nom plus défini.

const float PI = 3.14159f;
#include <iosfwd>
class entier {
public:
   using value_type = int;
private:
   value_type val = {};
public:
   entier() = default;
   constexpr entier(value_type val) : valeur{val} {
   }
   constexpr value_type valeur() const {
      return val;
   }
   std::ostream& operator<<
      (std::ostream&, const entier&);
};
class Afficher {
   std::ostream &os;
public:
   Afficher(std::ostream &os) : os{os} {
   }
   template <class T>
      void operator()(const T &val) {
         os << val << ' ';
      }
};
#include <iostream>
int main() {
   using namespace std;
   enum { N = 10 };
   for(int i = 0; i < N; ++i)
      cout << entier{i} << endl;
}

Jargon

Certains termes font école, en programmation comme ailleurs. Sans que je ne sois un expert de la question, voici quelques listes de termes qu'on pourrait associer à du « jargon de programmeuse » ou à du « jargon de programmeur ».

Petit guide de nomenclature appliquée

Avertissement : ce qui suit liste des conseils écrits au début des années 2000. Conséquemment, bien que l'essence de ce qui suit demeure raisonnable, je vous recommande de lire le tout d'un oeil aiguisé et de prendre soin de discriminer ce qui a bien vieilli de ce qui a un peu souffert.

Remarques préliminaires

Nous utiliserons des noms à consonance francophone. Libre à vous d'angliciser chacun si telle est la pratique de votre entreprise, vous souvenant ce faisant que la structure des phrases anglaises diffère de celles énoncées en français (p. ex. : DEFAULT_NOTE au lieu de NOTE_DEFAUT).

Règle générale, les différences entre les nomenclatures dues à des différences de langue sont moindres qu'on ne le croirait, les termes techniques tendant à se ressembler d'une langue à l'autre, sous l'influence de l'anglais.

L'orthographe joue un rôle important dans le vécu informatique. Veillez à sauver temps et argent à votre firme, et prenez soin d'utiliser l'orthographe la plus juste possible, et d'insister auprès de vos employé(e)s pour qu'ils/ elles en fassent autant.

Peu importe la significativité de la nomenclature employée, il ne faut en aucun cas oublier à quel point l'emploi systématique de commentaires, au moins à la déclaration de chaque variable, chaque constante, chaque sous-programme, etc. est essentiel, surtout pour la maintenance à long terme du code d'un projet informatique.

D'autres réflexions sur la question de la nomenclature dans les programmes sont disponibles ici.

Pour un texte sur le bon usage des constantes et sur la nomenclature bien choisie, voir ces quelques textes de Peter Vogel :

On demande souvent (en fait, toujours!) aux gens devant mettre la main à la pâte lors du développement informatique d'utiliser des noms significatifs pour leurs variables, constantes, sous-programmes, types, classes, instances, méthodes, modules, etc.

L'emploi systématique de commentaires judicieux, la rigueur quant à la nomenclature, et le respect des standards en place sont trois des éléments fondamentaux menant à une autodocumentation des programmes.

Certains doivent appliquer ces standards; il s'agit surtout des gens devant programmer, tester ou aider à la documentation d'un logiciel. D'autres doivent veiller à établir des standards, à les faire respecter, à vérifier occasionnellement leur application, et (surtout, quoiqu'on en pense) à les vendre à leurs collègues et employés.

Vous risquez fort de vous retrouver dans le second groupe. Cela dit, vous devrez connaître autant (sinon plus!) que vos développeurs les normes à appliquer dans votre entreprise, et les moteurs derrière les décisions menant à l'application de ces normes.

Tout chambarder?

Certaines firmes ont des standards particuliers et précis, alors que d'autres prennent une approche plus relaxe, mais donnent quand même des standards généraux auxquels les équipes de développement devront se conformer.

L'objectif derrière ce document est d'aider à la réflexion et de présenter quelques points de vue communs ou répandus. Il est clair que, si vous devez vous intégrer à une firme existante, les standards déjà en place seront probablement pour vous ceux à privilégier d'abord et avant tout; à moins que votre tâche ne soit de refondre les standards en place, il est probable que vous soyez d'abord appelé(e) à comprendre et à assimiler les façons de faire locales d'abord, puis (peut-être un jour) à les réexaminer si elles ne vous semblent plus adéquates.

Qu'est-ce qui constitue un nom significatif de constante?

Sur le plan programmatique, la norme usuelle veut que les constantes symboliques portent des noms écrits entièrement en majuscules. Ceci tient principalement d'une tradition liée aux usages en pseudocode, qui cousine celle des langages de Niklaus Wirth, et de l'époque des macros du langage C. Notez que cette pratique est remise en question par certains, dont Jonathan Wakely dans http://accu.org/var/uploads/journals/Overload121.pdf aux pages 13-14.

En pseudocode, où on omet de typer les données dans le but de se détacher de la technique pour réfléchir en termes algorithmiques, l'emploi de lexèmes entièrement en majuscules simplifie l'identification de ces données invariantes et importantes que sont les constantes.

Les constantes ont, toujours selon la tradition, une valeur « brûlée » à la compilation. Un compilateur peut alors utiliser le caractère invariant et littéral de ces données pour optimiser certaines partie d'un programme, par exemple, ou pour réserver l'espace associé à des tableaux.

Avec l'approche objet, où une instance doit être construite et détruite mais peut quand même être constante, et où des constantes locales à un sous-programme peuvent parfois être spécifiées sans que leur valeur ne soit connue à la compilation, la définition de bas niveau d'une constante s'élargit un peu.

Noms historiques ou associés à un objet courant

Certaines constantes ont des noms à caractère historique. On pense par exemple à PI, qui est traditionnellement associé à l'usage fait en mathématiques de la lettre grecque du même nom; à NULL pour un pointeur vers l'adresse 0 en langage C (mais pas en C++); ou à des constantes comme TPS ou TVQ qui, contrairement à PI, ont une valeur précise délimitée dans le temps et sujette à des changements occasionnels.

Les constantes systèmes, connues telles quelles des langages de programmation (plutôt que définies dans une bibliothèque), sont parfois en minuscules. On pense ici au null de Java (pour identifier une référence non instanciée) ou aux true et false de Java et de C++, qui sont les littéraux acceptables pour une donnée booléenne, pour ne donner que des exemples communs.

Remarquez que ces « constantes » ont fréquemment en commun le fait... de ne pas tant être des constantes symboliques que des littéraux d'un type donné. Un autre objectif visé par cet emploi des minuscules est de réduire les risques de conflits avec les noms utilisés dans les programmes écrits à l'aide de ces langages.

Dénombrement, bornes et énumération

D'autres constantes servent à des fins d'énumération, quand la cardinalité des énumérables est finie (et, idéalement, assez brève) et quand chaque élément énumérable peut se faire attribuer, en propre, un nom significatif. On peut penser ici à des constantes pour les jours de la semaine (LUNDI à DIMANCHE, par exemple), les mois de l'année, les signes du zodiaque, etc.

On séparera par des caractères de soulignement les mots distincts qui composeront un nom de constante (p. ex:  JOURS_FERIES); c'est là une coutume à peu près universelle.

L'emploi d'une stratégie OO permet de compartimenter les noms de manière à limiter le recours à de tels préfixes.

En effet, si une classe Note contient des constantes MIN et MAX, et s'il est clair qu'il s'agit des valeurs minimum et maximum pour une Note, alors la classe peut parfois jouer le rôle de qualificateur. Après tout, Note::MAX est aussi clair que NOTE_MAX.

On visera habituellement à ce que les constantes portent un nom qui dénote bien ce qu'elles représentent. Pour les constantes de spécification de taille ou de quantité, par exemple celles exprimant la taille d'une tableau, on préfixera généralement le nom de la constante par un vocable comme MAX ou NB. Pensez à NB_ELEVES pour les élèves d'une classe, ou à MAX_ELEMENTS pour une collection de taille bornée.

Dénoter une valeur maximale ou minimale, comme dans le cas où on voudrait spécifier les bornes de validité d'un type de données, l'usage veut qu'on utilise plutôt MAX et MIN comme suffixes. Si on veut indiquer la note minimale et la note maximale acceptables pour un type Note, on pensera souvent à NOTE_MIN et NOTE_MAX.

Cas particuliers

Dans le même ordre d'idées, on choisira souvent d'identifier la valeur par défaut pour un type de données par une constante dont le nom est suffixé par DEFAUT. Dans le cas d'une Note, on reconnaîtra immédiatement NOTE_DEFAUT comme la valeur par défaut utilisée (ou à utiliser) pour ce type.

Groupement de constantes et nomenclature

Lorsque des constantes peuvent être groupées, comme par exemple lorsqu'on liste des constantes qui serviront à la spécification du texte apparaissant sur des contrôles pour une interface personne/ machine, on voudra généralement les regrouper.

Regroupement en modules

Regrouper ces constantes se fera à la fois logiquement (placer dans un même module les constantes vouées à une même tâche ou à une même structure de données) et par une forme d'homophonie.

On pourrait suffixer toutes les constantes d'un groupe de la même manière (par exemple, par MENU_MNE pour des mnémoniques de menus), mais on tendra généralement plutôt à regrouper les constantes à l'aide de préfixes. Ceci facilite la recherche et les tris par ordre alphabétique, entre autres choses.

Regroupement par classes

L'approche objet nous donne aussi un outil de classement intéressant pour le regroupement de constantes à proximité logique les unes des autres: les classes et les membres de classe.

Cette stratégie est prise à plein par Java, et un peu moins par C++[1], quoique la tendance C++ ISO vers les espaces nommés a implicitement procédé à un regroupement logique de toute entité présente dans toute unité de code C++, qu'on en profite pleinement ou non.

Selon cette stratégie, donc, on spécifiera des classes ayant entre autres pour rôle de regrouper des constantes de classe publiques de vocation connexe et, le plus souvent, des méthodes de classe servant à convertir des données, valider des données, et autrement manipuler à la fois les constantes en question et les variables qui leur sont apparentées.

Exemple concret : la classe Integer de Java

Par exemple, Java propose la classe Integer, dont chaque instance représente (sous forme objet) un entier (un int du langage Java). Avoir une version objet de chaque type primitif est nécessaire, en Java, pour un ensemble de raisons techniques[2].

Dans la classe Integer, on trouve :

On y trouve aussi des constructeurs et des méthodes d'instance, bien sûr. Cela n'est par contre pas une condition d'application de la stratégie de regroupement dont nous discutons ici: on pourrait imaginer sans peine une classe ne servant qu'à exposer, de manière publique, un ensemble de constantes logiquement associées, et qui ne serait pas vouée à être instanciée.

Les méthodes de classe sont l'alternative Java aux fonctions globales de C++; les constantes groupées par classe y sont l'alternative plus localisée aux constantes globales de C++.

De son côté, C++ a choisi de regrouper d'abord les données qui étaient globales avant la norme ISO dans des espaces nommés[3], sans empêcher qui que ce soit d'utiliser plutôt des classes à des fins de regroupement.

Qu'est-ce qui constitue un nom significatif de variable?

Les problèmes informatiques ayant tendance à s'étendre sur des problèmes vastes et où apparaît la nécessité de gérer une masse d'identificateurs (constantes, variables, etc.) très importante, on évitera le plus possible les noms de variables d'une seule lettre ou les monosyllabiques, et dans les rares cas où on les utilisera, on fera en sorte que l'usage soit de portée très locale.

Dans les cas où la tradition les motive (on pense immédiatement au cas des boucles for avec un compteur d'itérations comme i, j ou k), on s'assurera de ne jamais utiliser des variables globales portant un nom non significatif[4].

On suggère généralement aussi d'utiliser des noms qui seront familiers aux gens susceptibles d'oeuvrer auprès du même code source, dans l'immédiat comme dans le futur envisageable. On voudra éviter l'emploi de terminologie échappant au commun des gens appelés à collaborer à un module, à moins bien sûr que ladite terminologie ne soit de nature technique et qu'elle soit intimement liée au projet en développement.

Cela dit, même dans un tel cas, il ne faut pas négliger l'importance des commentaires accompagnant la déclaration, qui devront donner une chance aux gens appelés à contribuer au projet de saisir le rôle de la variable malgré un bagage a priori différent.

Nom ou verbe?

Les variables tendent à désigner des états; de ce fait, on espère d'une variable que son nom donne une idée immédiate de son rôle dans le contexte où elle est destinée à servir[5]. On évitera de donner à une variable le nom d'un verbe d'action, et même (si possible) d'un verbe d'état[6]. En effet, les verbes ayant un sens plus dynamique, on les réservera généralement pour les noms de sous-programmes.

Les majuscules

On évitera bien sûr les noms de variables écrits strictement en majuscules, fuyant les ambiguïtés avec les conventions en place pour les constantes. Si un programme devait calculer une approximation de π plutôt que le la prendre pour acquis, utilisant ainsi une variable plutôt qu'une constante, on s'attendrait à voir cette variable nommée Pi et non pas PI.

Plusieurs firmes suggèrent que, même dans les langages où les lettres majuscules et les minuscules sont considérées comme des symboles différents[8], on évite d'utiliser deux variables portant exactement le même nom aux majuscules et aux minuscules près (cette suggestion s'étend au couple variable/ constante aussi, de manière évidente).

De l'emploi du caractère de soulignement

L'emploi du caractère de soulignement est chose débattue dans certains cercles. Les uns aiment, les autres détestent. Certains séparent tous les mots compris dans un même nom par des soulignements, d'autres ne les utilisent qu'à certains endroits, et d'autres encore ne les utilisent jamais.

Ma recommandation personnelle serait de ne pas en abuser. En prenant pour acquis que les constantes soient rédigées à l'aide de lettres majuscules seulement, le recours àdes caractères de soulignement y est chose raisonnable du fait qu'on ne peut alors pas se fier aux lettres majuscules pour marquer le début des mots.

L'utilisation du soulignement pour des raisons techniques est aussi recommandable (p. ex. : pour marquer la séparation entre un préfixe et un nom, comme lorsqu'on applique une règle telle que préfixer les noms d'attributs par m ou par un m_), du fait que cela accroît la lisibilité du code et y facilite le repérage pour les lectrices et les lecteurs.

Dans le cas de noms de variables, de classes, de sous-programmes ou autres, une majuscule pour marquer le début d'un mot suffit habituellement pour la plupart des gens et la plupart des usages.

Clarté et concision

L'emploi de noms significatifs doit être balancé par un souci de clarté et de concision. Entre CompteurDuNombreDEleves et CompteurEleves (ou, si la pratique locale le permet, CptEleves), on ne remarque pas de réelle perte de sens – il est clair dans chaque cas qu'on utilise cette variable pour compter ou énumérer des élèves. Les formules brèves entraînent ici une présentation plus claire pour le code pris dans son ensemble, et sont plus directement accessibles à la lecture.

Remarquez, par opposition, que les noms Cpt_E ou i ne véhiculent pas du tout un sens aussi clair et complet.

La modération et l'équilibre sont des qualités recherchées ici pour supporter les efforts de clarté, pas pour aller à leur encontre. Si plusieurs langages supportent des noms d'identificateurs d'une longueur maximale de 127 ou de 255 caractères, on voudra idéalement se limiter à moins de 30 caractères.

Composition de noms

On le voit avec l'exemple du compteur d'élèves ci-dessus: il arrive fréquemment qu'un nom de variable soit en fait un composé de plusieurs noms. On essaiera d'utiliser, pour nommer ces variables, un standard qui mette en relief les noms qui les composent. Ceci peut signifier séparer les mots par des caractères de soulignement, utiliser une majuscule pour débuter chaque mot, ou une combinaison des deux.

Selon les standards locaux, on utilisera parfois une majuscule pour débuter un nom de variable, et parfois une minuscule. L'important ici est (a) de respecter les standards locaux, et (b) qu'il existe ou non des standards locaux, d'être constant(e) et conséquent(e) dans la démarche choisie.

Variables jetables

Certaines firmes recommandent aussi de définir des standards pour les variables dites jetables (en anglais : les Throwaway Variables). On verra souvent des variables préfixées par le terme dummy, par exemple, ou par spare pour des variables servant à réserver de l'espace en vue d'ajouts à un système dont la taille ne doit pas, pour différentes raisons, varier trop souvent.

Préfixes et autres décorations

Lorsque le besoin de variables globales survient, ce qui survient à l'occasion pour des raisons techniques, plusieurs ont pris l'habitude de préfixer leur nom par g_, s'inspirant ainsi des standards de facto en vigueur pour les noms d'attributs. Les variables globales étant à éviter le plus possible, on vise à les repérer avec aisance dans un programme.

Conséquemment, on évitera pour les variables locales les préfixes comme s_, m_ ou g_, du fait que plusieurs les réservent pour spécifier des attributs de classe, d'instance ou des variables globales. Ceci que votre firme fasse partie ou non des utilisateurs de ce standard – l'idée est de réduire les risques de conflit et d'ambiguïté.

La notation hongroise

Les remarques qui suivent, exception faite bien sûr des notes historiques propres à la notation hongroise en tant que telle, s'appliquent de manière générale à toute notation avec laquelle on inscrit, à même les noms d'identificateurs, des données descriptives de type.

Je sais que je pose un regard sévère sur cette pratique. Pour un regard plus « partagé », je vous suggère ce texte de 2004 par Larry Osterman. Par contre, en 2015, dans un tweet, John Carmack fait remarquer :

« Hungarian notation is broadly reviled in C, but there is somewhat more attraction for it in a language like Scheme without static type [declarations] »

Vous avez peut-être entendu parler d'un standard de nomenclature nommé notation hongroise (certains l'appellent aussi la notation polonaise inversée, pour des raisons exposées plus bas), notation qui a des dérivés ça et là[9]. Sans être le seul standard du genre, il s'agit (pour plusieurs raisons dont nous discuterons ici) de l'un de ceux que vous êtes le plus susceptible de rencontrer à courte échéance.

Il vaut la peine de faire ici une courte digression à ce sujet, question d'expliquer (a) de quoi il s'agit, (b) ses avantages, et (c) ses inconvénients dans un contexte orienté objet. L'idée ici est de vous aider à vous forger un point de vue sur le sujet, pour éviter de tomber malgré vous dans des guerres de clocher à son sujet.

Ce que vous ne trouverez pas ici, c'est une position préfabriquée du genre c'est la meilleure chose au monde ou c'est une tare à éviter. Comme c'est souvent le cas, une position réaliste se situe quelque part entre les deux.

Ce qu'est la notation hongroise

La notation hongroise est une manière d'identifier chaque variable par un préfixe qui en spécifie le type; d'indiquer le type d'une donnée à même son nom. Clairement, on parle ici d'une pratique vouée à aider les développeurs à se souvenir des types en jeu lorsqu'ils manipulent des variables, et ce sans avoir à reculer jusqu'à leur déclaration.

Ce standard a été développé par un hongrois (d'où le nom de la notation, on s'en doute) nommé Charles Simonyi, né à Budapest en 1948.

La notation hongroise est surtout connue aujourd'hui parce que son inventeur a oeuvré une dizaine d'années comme programmeur senior à Microsoft, et que les programmes écrits en langage C[10] sous Microsoft Windows l'ont adopté comme standard[11].

Par intérêt historique, notons l'un des premiers volumes expliquant comment programmer sous Microsoft Windows, titré Charles Petzold's Programming Windows, utilisait massivement un dialecte de la notation hongroise, ce qui a sûrement motivé beaucoup de gens à faire de même.

L'intention

L'inventeur de la notation, donc, était d'opinion que l'emploi systématique de noms de variables préfixés de leur type entraînerait une diminution des erreurs sur ces variables dues à des manipulations impropres – il est en effet difficile de justifier devant un patron d'avoir mal compris le rôle d'une variable contenant du texte si le nom de cette variable indique clairement qu'il s'agit de texte, et pas d'un entier par exemple.

Son poste chez Microsoft lui a permis de tester son modèle, l'imposant comme standard de travail pour son équipe[12].

La confusion de nom avec celui de notation polonaise inversée tient d'un système mathématique du même nom et servant à faciliter, surtout dans des calculatrices, l'entrée d'expressions sans parenthèses ou ponctuation. Cette notation tend à donner des «mots» pleins de consonnes.

À la base, la notation hongroise telle qu'employée communément aujourd'hui ressemble à ceci :

Préfixe Type Exemple
b
bool (ou, en langage C pré-1999, int servant de booléen)
bool bPoursuivre;
c
char
char cNoteUniversitaire;
str
std::string de C++
std::string strPrenom;
si
short int
short siNbChaises;
i
int
int iNbVoitures;
li
long int
long liNbEtoiles;
f
float
float fPourcentage;
d
double
double dKilometrage;
ld
long double
long double ldAnneesLumieres;
sz
Chaîne ASCIIZ brute
char szNom[TAILLE_NOM];
if
Flux d'entrée (sur un fichier)
std::ifstream ifFichierEntree;
is
Flux d'entrée (général)
std::istream isFlotEntree;
of
Flux de sortie (sur un fichier)
std::ofstream fFichierSortie;
os
Flux de sortie (général)
std::ostream isFlotSortie;
h
HANDLE (pointeur opaque)
HANDLE hThreadLecture;
hwnd
HANDLE vers une fenêtre
HANDLE hwndMaFenetre;
S
Déclaration d'un struct
struct SPoint;
C
Déclaration d'une class
class CPersonne;
Nom ou abréviation d'un struct ou d'une class Instance de ...
SPoint pointGauche;        // ou
SPoint ptGauche;

CPersonne personneTrouvee; // ou
CPersonne perTrouvee;

Il est commun de voir des ajouts locaux à la liste de préfixes[13].

On peut préfixer ces préfixes des pré préfixes suivants :

Pré préfixe Type Exemple
u
unsigned
unsigned short usiNbEtudiants;
k
Paramètre constant
void ListerGalaxies(const long kliNbGalaxies);
r
Paramètre par référence
void CompterGalaxies(long &rliNbGalaxies);
s
static
static char scChoix;
rg
Tableau (le rg signifie Range, ou intervalle)
float rgfNotes[NB_NOTES];
m_
Membre de (utilisé pour un attribut). Évidemment, les gens utilisent soit l'un, soit l'autre (pas les deux).
int m_iNbNotes;
m
int miNbNotes;
g_
Variable globale
long g_lVerrou;
p
Pointeur de/ pointeur vers
int *piIdentificateur;
prg
Tableau alloué dynamiquement (fusion des préfixes p et rg).
int *prgiNotes;

Notation hongroise et problèmes de décision de nomenclature

Selon l'auteur de la notation, le problème fréquent qu'est le choix d'un nom pertinent et utile pour une variable mène les développeurs à considérer les critères suivants :

La notation hongroise se veut un standard permettant de répondre à l'ensemble de ces critères, mécanisant ainsi en grande partie la génération de noms et standardisant d'office les noms en regroupant les variables selon leur type.

Raison d'être et avantages

L'avantage premier de l'emploi de la notation hongroise, comme de l'emploi de toute notation, est que son déploiement systématique introduit de facto une normalisation au niveau des règles programmatiques locales.

Une telle discipline tend à faciliter la formation des gens et à diminuer le temps requis pour former des individus familiers avec ces règles lorsque celles-ci ou ceux-ci doivent aborder un nouveau produit. On peut ne pas aimer un standard ou l'autre, pris individuellement, mais il est généralement bien, dans un domaine aussi vaste et mouvant que l'informatique, d'appliquer des standards. Même les plus individualistes et les plus rebelles du domaine reconnaissent les bienfaits d'une démarche de standardisation[14].

Les partisanes et les partisans de la notation hongroise apprécient le surcroît d'information immédiate que leur apporte l'ajout d'informations de type à chaque nom de variable. Particulièrement pour qui n'a pas intégré une discipline de nomenclature implicite à même ses méthodes de travail, un rappel continu, formel et explicite des choix d'implantation faits à même le nom de chaque variable peut accélérer le développement, en diminuant le temps de recherche et de déverminage associé à cette tâche.

Une certaine simplification de la documentation d'un programme peut être apportée par l'emploi rigoureux d'une norme de nomenclature comme la notation hongroise, du fait que les types de données en jeu peuvent être considérés comme implicites – donc, à la limite, ne pas devoir être mentionnés en propre en support à la description des variables – ou encore être extraits avec facilité par des utilitaires de documentation automatique[15].

À ne pas négliger, parce qu'il faut être réaliste (même si c'est, moralement, très irritant): le standard en question est véhiculé par une firme dont le poids, sur le marché, est considérable. Les idées de cette firme, qu'elles soient bonnes ou mauvaise, dangereuses comme avantageuses, tendent à se frayer un chemin dans le public, entre autres à travers les nombreuses PME qui dépendent de ladite firme pour leurs propres produits. Le momentum apporté par l'adhésion de ce poids lourd à la notation hongroise a déjà joué un grand rôle dans la dissémination et l'acceptation de cette dernière.

Les défenseurs de la notation hongroise (et de ses dérivés locaux) indiqueront que, dans la mesure où cette notation est utilisée de manière conséquente et cohérente, elle évitera aux développeurs de la rédaction de code inutilement long, les noms de variables devenant relativement compacts, et diminuera ainsi le nombre d'erreurs de frappe.

Évidemment, il faut veiller à ce que la correspondance entre nom et type demeure véridique en tout temps. Tout changement au type d'une variable doit entraîner une modification immédiate de son nom, et ceci partout où elle est utilisée, pour la notation hongroise demeure utile.

À ce sujet, mêmes les amateurs de la notation hongroise sont conscients que cette manière de nommer les variables est, essentiellement, un standard de documentation, équivalent fonctionnel des commentaires. Et comme c'est le cas pour les commentaires, la conformité du nom d'une variable à son type de donnée n'est pas validée par les compilateurs[16]; conséquemment, les développeurs sont à 100% responsables d'assurer cette conformité, ce qui – surtout lorsque les échéances de livraison d'un produit approchent – peut être difficile à faire.

Le cas particulier des interfaces personne/ machine

Dans certains cas, comme par exemple celui du développement d'interfaces personne/ machine (IPM), l'emploi de standards de notation préfixée est presque une nécessité.

On pensera en particulier aux outils RAD (Rapid Application Development) prémunis d'outils de prototypage rapide, comme VB, pour lesquels existent souvent des normes locales pour les noms de contrôles.

Dans une IPM, on trouvera presque toujours plusieurs contrôles voués, chacun à sa façon, à un mandat commun.

Par exemple, si on joint une étiquette de texte statique[17] indiquant d'entrer un nom à une zone de texte[18] permettant d'entrer ce nom, on obtient deux contrôles voués à l'entrée d'un nom.

L'emploi de préfixes normalisés[19] permet une différenciation immédiate de chacun des contrôles, et est d'ailleurs probablement le modèle de standard le plus simple possible pour arriver à une telle différenciation compte tenu que des noms dépendant des rôles des contrôles ne suffirait pas.

La contrepartie : inconvénients

La lisibilité initiale de code rédigé selon les règles de la notation hongroise ou de toute autre stratégie de décoration manuelle des noms est ardue. Les préfixes sont faits d'une ou de plusieurs consonnes, et rebutent la plupart des gens qui, tout en gagnant l'information de types qu'elle véhicule, y perdent souvent le sens de la variable, du moins pendant leur période d'acclimatation. Cela dit, comme toute norme, on s'y habitue.

Sur le plan programmatique, on peut mettre en doute l'utilité de cette notation pour plusieurs raisons. Entre autres :

Plus irritant est le fait que la notation hongroise est une norme de nomenclature liée à un langage (le langage C) et qui utilise des préfixes qui ont du sens d'abord et avant tout pour ce langage.

Des dérivés existent pour C++[21], qui se rapproche de C à plusieurs égards pour le nom de ses types primitifs, incluant l'apposition du préfixe C pour une classe (CRectangle pour une classe représentant un rectangle, par exemple).

Cela dit, la notation hongroise n'est pas directement transportable à d'autres langages, et on peut se retrouver, dans une firme où le développement se fait à l'aide de plusieurs langages distincts, avec une multiplicité de normes.

Microsoft, chez qui la notation hongroise est bien ancrée, a en partie contourné le problème dans son architecture .NET en uniformisant les types de données à même un standard binaire commun à tous leurs langages de programmation (le CLR, pour Common Language Runtime). C'est une stratégie intéressante, sur laquelle on peut dire beaucoup de bien... et de moins bien. Mais cela nous ferait déborder du sujet discuté ici.

Plus irritant, si on prend le point de vue orienté objet maintenant, est que l'emploi de noms variables incluant une information de type va à l'encontre de notre objectif d'abstraction des types. Les langages comme C++ visent à rendre opérationnellement équivalents les types complexes et les types simples. On l'a vu avec les opérateurs, la mécanique derrière les constructeurs par copie, le fait que l'allocation automatique de tableaux d'objets fait en sorte d'appeler spontanément le constructeur par défaut de chaque instance créée, et ainsi de suite.

L'emploi d'une notation stigmatisant les objets d'un préfixe (le lettre C) est, dans un contexte objet, fort questionnable. Dans un contexte vraiment orienté objet, ce que C++ et Java (des hybrides) ne sont pas, une notation comme la notation hongroise perd totalement son sens: il n'existe alors pas de types primitifs, toute opération se faisant pas échange de messages avec un objet, et on perd les avantages que nous conférerait la connaissance du type d'une variable.

Mais même avec les hybrides, utiliser la notation hongroise est, purement et simplement, un bris d'encapsulation. Plutôt que d'utiliser une instance pour ce qu'elle peut faire et ce qu'elle peut apporter à un programme, en pensant simplement aux opérations qu'on peut réaliser sur elle ou avec elle, il devient nécessaire de se préoccuper en tout temps de son type.

Même en langage C, dès les années '70, on avait perçu le besoin d'abstraction pour faciliter la maintenance du code à long terme. Les tailles standard du langage C sont de type size_t, un type non signé défini dans <cstddef> et capable de représenter le nombre d'éléments dans un tableau; on ne voit pas là s'il s'agit d'un unsigned short, d'un unsigned int ou d'un unsigned long. Le choix d'éviter de camper les tailles dans un type ou l'autre est délibéré, et de motiver les gens à manipuler les types à l'aide d'opérations (fonctions, en langage C) définies sur eux.

Les détracteurs de la notation hongroise s'amusent à faire remarquer que, même au coeur de Microsoft Windows, le maintien de la conformité des variables aux standards de la notation hongroise n'a pas passé la rampe de la migration du produit Windows de sa version 16 bits à sa version 32 bits.

En effet, le prototype de la fonction centrale de traitement des messages d'une fenêtre, WinProc(), reçoit entre autres choses deux paramètres, nommés wParam et lParam.

Il se trouve que le préfixe w tient pour WORD, un entier 16 bits selon la tradition sur cette plateforme. Or ce paramètre est maintenant fait d'un entier encodé sur 32 bits, et aurait dû être renommé dwParam.

Ceci met en relief la difficulté d'adapter une notation comme la notation hongroise à un contexte évolutif de mise à jour de produit.

À réfléchir

À noter que, dans les livres de Microsoft Press® portant sur la stratégie .NET, on mentionne maintenant que la notation hongroise devrait être considérée obsolète.

Tristement, les raisons énoncées sont très mauvaises: la position de la firme qui a moussé la notation hongroise en premier lieu est que la technologie IntelliSense®, qui met en relief des données sur chaque variable dans l'éditeur .NET alors que le pointeur de souris les survole, rendrait à leur avis l'emploi d'une notation préfixée redondante.

Pour est-ce là une mauvaise raison? Entre autres :

La véritable raison pour rejeter une notation préfixée, si on la rejette effectivement, n'est pas une raison technologique, mais bien une raison de démarche :

On peut comprendre l'emploi d'une notation préfixée dans un milieu d'apprentissage, où ces méthodes de travail ne sont pas encore bien ancrées (parce qu'on les développe). Et on doit aussi comprendre que l'ajout de technologies de support n'est pas un palliatif valable à une démarche rigoureuse de développement.

Qu'est-ce qui constitue un nom significatif d'attribut?

Dans une approche objet, on vise à décourager l'accès direct aux attributs d'une instance. L'emploi de la spécification privé va bien sûr en ce sens; il se trouve que dans le passé pas si lointain, certaines expériences orientées objet à vocation commerciale ne supportaient pas, à l'origine, l'encapsulation stricte à même le langage.

Pour motiver les programmeuses et les programmeurs à éviter l'accès direct aux attributs, les gens se sont alors mis à les préfixer systématiquement de caractères de soulignement. Un, puis deux, parfois même trois, toujours dans l'optique où on voulait mettre en relief que les accesseurs et les manipulateurs, eux, portaient des noms stables et effectuaient les bonnes opérations de la bonne façon. Une forme d'encapsulation par la force brute, disons.

Avec la généralisation du support à l'encapsulation stricte à même les langages de programmation, on a développé l'habitude de préfixer les noms d'attributs d'instance de m ou de m_, au sens de membre, et cela même si le mot membre s'applique tout autant aux méthodes qu'aux attributs[22] (on ne préfixe pas les méthodes de cette façon).

Certains ont pris l'habitude de préfixer les membres de classe en Java et en C++ d'un s_, bien qu'il s'agisse là d'une habitude de travail beaucoup moins répandue. La plupart des attributs de classe tendent en effet à être des constantes, pour lesquelles un préfixe du genre n'a pas vraiment de pertinence.

Cette pratique, relativement rare pour l'instant, a un côté assez agaçant: le terme static pour un membre de classe est un terme technique qui n'évoque pas clairement le caractère membre de classe de ce qui lui est associé. Le préfixe s_ est donc très lié à une culture locale, et qui est difficilement transférable sans perte de sens.

Pour le reste, on essaiera de lier la nomenclature des attributs aux conventions de nomenclature en vogue dans l'entreprise.

Qu'est-ce qui constitue un nom significatif de sous-programme?

Le premier critère de bonne nomenclature pour un sous-programme est de s'assurer que le nom soit un reflet fidèle de la tâche que ce sous-programme doit réaliser. Ceci peut sembler évident, mais un examen sommaire des pratiques en entreprise montre que la plupart des sous-programmes existants sont déficients en ce sens.

Les divergences entre nom et vocation pour un sous-programme tiennent surtout de deux facteurs, chacun important à sa façon :

On essaiera d'utiliser des verbes d'action pour débuter la plupart des noms de sous-programmes, ces entités étant pour la plupart des unités de code actives, quoiqu'on puisse imaginer des fonctions dont le nom est bien choisi mais débute par un verbe d'état (par exemple la fonction EstPair(n) qui retourne vrai si et seulement si n est un entier pair).

On a longtemps choisi des fonctions portant des préfixes similaires pour faciliter la documentation et l'organisation du code. Avec les langages orientés objet, on tend à ne plus se préoccuper autant de considérations du genre, du fait que, spontanément, les méthodes soient groupées par objet.

Lorsqu'un projet est réfléchi selon l'approche objet mais à l'aide de langages qui, eux, ne sont pas des langages orientés objet, on fera souvent attention de préfixer les fonctions destinées à devenir des méthodes par le nom de ce qui, selon la conception de l'équipe de développement, deviendra la classe à laquelle ces méthodes seront rattachées. Cela facilitera la migration vers un outil orienté objet lorsque celle-ci sera entreprise.

Les fonctions globales et les méthodes publiques ont ceci en commun qu'une fois livrées, elles doivent être maintenues par la firme qui en est responsable. Ceci peut devenir une entrave au progrès, alors que les changements philosophiques et technologiques peuvent amener les gens à réclamer des changements à des fonctions existantes alors que d'autres peuvent réclamer d'elle une stabilité à toute épreuve.

Certaines firmes motiveront alors l'emploi de suffixes dénotant clairement le passage à une nouvelle génération du sous-programme. Ce suffixe peut être numérique (p. ex. : la nouvelle version de SousProgChic() devenant SousProgChic2()) ou dénoter le caractère extensionnel du sous-programme le plus récent (p. ex. : la nouvelle version de SousProgChic() devenant SousProgChicEx()). Dans les cas où le nouveau sous-programme dépasse le seuil de la simple extension fonctionnelle à l'original, on cherchera alors un nouveau nom, tout simplement.

Les règles pour joindre plusieurs mots en un même nom son en général les mêmes que celles appliquées pour les noms de variables.

Qu'est-ce qui constitue un nom significatif de méthode?

Les règles de sous-programmes s'appliquent, dans l'ensemble, aux méthodes. Certains standards locaux existent (chez Oracle, avec Java, on commencera le nom des méthodes par une minuscule, alors que chez Microsoft, pour la bibliothèque MFC, on commencera plutôt par une majuscule), qui se valent à peu près tous dans la mesure où ils sont respectés de manière rigoureuse et sont respectueux de la culture des gens en place comme de celle de leurs clients.

La grande particularité des méthodes, par opposition aux sous-programmes globaux, est leur caractère subjectif. En effet, un sous-programme global est une opération qui s'applique à des entités qui lui sont fournies de l'extérieur. C'est un agent externe. Ceci est aussi en grande partie vrai pour la plupart des méthodes de classe.

Une méthode d'instance, par contre, opère d'abord et avant tout sur l'instance qui en est propriétaire, l'instance active. Les Get et les Set réfèrent à des données propres à l'objet possesseur de la méthode elle-même; cette méthode a ainsi un accès privilégié et implicite aux attributs en question.

Là où on nommera souvent un sous-programme global par une combinaison verbe/mot, comme dans AfficherDessin(d) ou AvancerVoiture(v), on simplifiera souvent le nom d'une méthode en se limitant à un verbe, l'objet de l'opération devenant un sujet, et préfixant lors de l'appel la méthode (d.Afficher() ou v.Avancer(), présumant que d soit un Dessin et v une Voiture).

Prenant le virage objet, cette simplification a l'avantage périphérique de ne pas lier le nom d'une méthode à un seul type de données mais plutôt à toute une hiérarchie d'objets. Ainsi, avec v.Avancer(), le nom de méthode Avancer() s'applique peut-être subjectivement à tout véhicule, qu'il s'agisse d'un Avion, d'une Voiture, d'un Bateau... la mécanique du polymorphisme fera en sorte de laisser le véhicule qu'est v, quel que soit son type réel, avancer de la manière la plus appropriée.

Une étrange conséquence

Il est important de noter que l'orientation objet a, parmi ses conséquences naturelles, celle de mener les langages à supporter plusieurs sous-programmes portant le même nom. La principale (mais pas la seule) raison pour ceci est la mécanique de construction des instances qui demande généralement qu'on puisse avoir plusieurs constructeurs distincts portant le même nom.

Sur le plan du code généré à la compilation, les noms doivent toutefois être uniques pour qu'on puisse différencier les sous-programmes à l'édition des liens. Pour arriver à des noms effectifs distincts mais reconnaissables, les compilateurs génèrent dans le code objet des noms de sous-programmes qui incluent de l'information quant aux types de leurs paramètres.

Ceci ajoute une strate de complexité à l'édition des liens, surtout lorsque survient le besoin de lier entre eux des fichiers objets générés à partir de langages de programmation et de compilateurs différents, puisque les standards d'encodage sont locaux aux technologies individuelles.

Pour faciliter les choses dans de tels cas, il arrivera qu'on introduise des sous-programmes globaux qui seront compilés selon les standards C (nom unique, nom dans le code objet correspondant directement au nom dans le code source) et qui serviront de lien entre les modules orientés objets et ceux qui ne le sont pas. Ceci résulte à l'occasion, côté orienté objet, en de curieux hybrides, mais tel est parfois le prix à payer pour assurer l'interopérabilité binaire.

Lectures complémentaires

Quelques liens pour enrichir le propos.


[1] À cause du lourd héritage du langage C, sans doute, et par souci d'interopérabilité avec des langages de programmation qui ne serait pas orientés objet.

[2] En particulier, Java ne propose que le passage de paramètres par valeur. Des procédures comme Echanger(x,y) y donc sont a priori impossibles à implanter à l'aide de types primitifs. Par contre, en Java, toute instanciation doit se faire à l'aide de new, et tous les objets ainsi alloués sont gérés par référence (Java n'offre pas l'accès direct aux adresses et aux pointeurs). Une référence est une adresse qu'on ne peut accéder que de manière sécurisée; passer une copie d'une référence fait en sorte de donner au sous-programme appelé un accès à la donnée telle qu'elle est connue du sous-programme appelant, sauvant ainsi la mise.

[3] Toute donnée, classe, fonction, constante, etc. n'étant pas spécifiquement dans une espace nommé est, en C++ ISO, dans l'espace nommé anonyme (drôle de nom, soit, mais correct tout de même). Ainsi, la fonction main() porte le nom effectif ::main() (le préfixe :: sans nom de namespace signifie que main() est dans l'espace anonyme.

[4] Les cas documentés de problèmes importants abondent: des gens qui oublient de déclarer un compteur nommé i et qui ne s'en aperçoivent pas, du fait que leur programme compile – parce qu'il existe une variable globale nommée i – et qui, par inadvertance, modifient ainsi un compteur global utilisé dans un autre sous-programme, ce qui introduit un bug majeur et très, très difficile à identifier.

[5] De manière complémentaire à la mathématique, où l'humain est penseur et acteur principal de la recherche d'une solution, d'une stratégie ou d'une démonstration, l'informatique vise souvent les tâches et problèmes où l'automatisation doit primer sur l'intervention humaine, incluant les situations où le volume de données ou la taille du problème dépassent les capacités des humains. On remarque aussi que les mathématiciennes et les mathématiciens sont souvent appelés à résoudre des problèmes d'ordre général, s'appliquant à une classe de situations très large, et à amener des solutions opérant de fait à un niveau d'abstraction élevé si on le compare aux situations réelles dans lesquelles elles seront, concrètement, appliquées. La signification des noms de variables est alors souvent détachée des contextes d'application, ce qui est raisonnable et compréhensible. Les problèmes auxquels s'attaquent l'informaticienne et l'informaticien sont parfois de cet ordre, mais peuvent plus souvent être liées à des situations pour lesquelles des variables aux noms monosyllabiques ou écrites d'un ou deux caractères seulement serait moins approprié. On recommande donc fortement, en informatique, de faire usage pour une variable de noms significatifs à son rôle dans le contexte de son utilisation.

[6] Des exceptions sont possibles, comme celui d'une variable booléenne nommée DoitPoursuivre ou Poursuivre et servant à contrôler la poursuite de l'itération d'une répétitive. Cela dit, on pourrait y aller par la négative et utiliser plutôt la négation d'une variable nommée Fini ou Termine (Terminé si votre langage accepte les caractères accentués; Done ou Completed en anglais) pour signifier précisément la même chose.

[8] Les langages C, C++, Java, mais pas VB6 ou Pascal par exemple.

[9] On connaît une notation tchèque, ou czech notation, entre autres choses.

[10] Le langage C impose la déclaration de variables au début de blocs seulement, contrairement à C++ qui permet la déclaration de variables à peu près n'importe où dans un programme, et il arrive que, dans un sous-programme de longueur importante, la déclaration d'une variable donnée soit loin de l'endroit où elle est utilisée.

[11] La notation elle-même, par contre, n'a pas été mise au point durant le passage de son inventeur chez Microsoft, mais alors qu'il travaillait à l'université Berkeley; il la raffina ensuite alors qu'il oeuvrait aux laboratoires de recherche PARC (de Xerox).

[12] Ses collègues, voyant les noms de variables préfixées par un tas de consonnes (comme par exemple lpszFile pour un nom de fichier) auraient lancé, en boutade : « ça pourrait être du grec... ou du hongrois! ».

[13] Par exemple w pour le type WORD, un entier 16 bits sous Microsoft Windows, ou dw pour DWORD, entier 32 bits sous cette même plateforme.

[14] C'est la raison d'être de ce document que de discuter standards et normes de notation, n'est-ce pas?

[15] Remarquez qu'un utilitaire de documentation automatique peut, s'il est capable de décoder la structure d'un programme – donc s'il connaît les règles grammaticales du langage de programmation en jeu – extraire l'information de type d'une variable de par sa déclaration, surtout si le langage est fortement typé. Par contre, certains peuvent trouver plus simple, à certains égards, de rédiger un utilitaire déduisant les types des variables de par leur nom que d'en écrire un autre qui doive comprendre plus en détail la structure d'un programme. Ce qui est sûr, c'est que de combiner la notation hongroise à des utilitaires de validation et de documentation automatiques peut aider au dépistage d'erreurs sémantiques dans un programme.

[16] Ceci n'est pas incontournable, remarquez bien.

[17] Un Label en VB6, un JLabel en Java (avec Swing).

[18] Un JTextField en Java (avec Swing), un TextBox en VB6.

[19] Ceux de VB6 sont lbl pour une étiquette et txt pour une zone de texte. Ici, par exemple, on aurait lblNom et txtNom, ce qui donne immédiatement le rôle de chacun de ces contrôles.

[20] Prudence tout de même: la philosophie de certaines firmes fait qu'on y motive les bris d'encapsulation, prétendant ainsi simplifier ou accélérer le code. C'est faux, de manière évidente et démontrable d'office, mais il faut faire avec si on compte utiliser leurs produits.

[21] D'ailleurs, la version de la notation qui est proposée plus haut est, clairement, une version C++.

[22] Historiquement, les présentation de C++ utilisent les vocables member variable et member function pour parler respectivement d'un attribut ou d'une méthode; ceci pour faciliter la transition vers C++ des programmeurs structurés, surtout ceux – nombreux – qui sont d'abord habitués au langage C.


Valid XHTML 1.0 Transitional

CSS Valide !