Questions de nomenclature – Notation hongroise

Ce qui suit était autrefois inclus dans Nomenclature.html, mais je l'en ai extrait parce que (a) c'est une section suffisamment massive pour mériter une page à part entière, et (b) parce que je ne souhaite pas que cette pratique, de par l'espace qu'elle occupe, soit confondue avec d'autres que je trouve plus recommandables...

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] »

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.

Qu'est-ce que la notation hongroise?

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à. 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.

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.

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 sous Microsoft Windows l'ont adopté comme standard.

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.

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).

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. 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! ».

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. 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.

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 (voir Nomenclature.html pour plus d'informations).

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.

À 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; 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 (p. ex. : Label, JLabel) indiquant d'entrer un nom à une zone de texte (p. ex. : JTextField, TextBox) 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 (p. ex. : 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) 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++, 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 OO, 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 un éditeur 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.

Lectures complémentaires

Quelques liens pour enrichir le propos.


Valid XHTML 1.0 Transitional

CSS Valide !