Questions de nomenclature
Si vous cherchez les textes suivants, ils ont été
relocalisés sur des pages à part entière :
« 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)
« On the (mis)naming habit of pasting ever more prefixes and suffixes to create identifiers:
This is like homeopathy. What you've done is you've diluted the meaning until it's all gone » –
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 :
- Étude (très intéressante) faite en
2006 par Alan F. Blackwell sur les pratiques de nommage dans le code
Java standard, dans l'optique de comprendre le sens donné aux entités
programmées : http://www.ppig.org/papers/18th-blackwell.pdf
- Texte fort intéressant de
Rob Pike et P.
J. Weinberger en 1985, examinant en détail les
règles de nommages pour les courriels, les noms de domaines, les répertoires,
etc. :
http://3e8.org/pub/scheme/doc/the-hideous-name.pdf
- À propos de l'importance du nommage, texte de Flávio Ribeiro en 2013 :
http://blog.flavioribeiro.com/naming-things/
- L'importance d'un nom pour une entreprise, par
Paul Graham
en 2015 :
http://paulgraham.com/name.html
- Être capable de bien nommer une fonction signifie typiquement que nous en
avons compris le rôle. Texte de 2016 par Samir
Talwar, qui démontre cette idée par un exemple plutôt « parlant » :
http://monospacedmonologues.com/post/138532840924/naming-things
- En 2015, Reginald Braithwaite se prononce sur le nommage en tant que problème qu'il vaut la peine de résoudre,
en partie parce que ces noms participent à l'interface du code :
http://braythwayt.com/2015/11/11/hard-problems.html
- Nomenclature de fichiers, sur un plan historique, un texte de Thomas
Galvin en 2015 relatant l'histoire du format de
nom de fichiers 8 . 3 de l'époque
DOS et montrant que ce format existe toujours, sous la couverture... :
https://usn.pw/blog/gen/2015/06/09/filenames/
- Compter le nombre d'occurrences de certains mots dans un fichier source
peut être instructif, comme l'indique ce texte de
Jonathan Boccara en
2018 :
https://www.fluentcpp.com/2018/10/09/3-things-that-counting-words-can-reveal-on-your-code/
- Nommage et concepts mathématiques :
Bon ou mauvais nommage
« Pro Tip: don't try and name a function by looking at its implementation as you'll only come up with a name that reflects how it works. Instead look at the call sites and see what they want to know or do » –
Chris Oldwood (source)
Quelques réflexions sur ce qui fait la qualité d'un bon nom :
- Un guide de sain nommage (surtout pour
C++),
proposé par Tony van Eerd :
https://github.com/tvaneerd/isocpp/blob/master/on_naming.md
- http://www.objectmentor.com/resources/articles/naming.htm
- Quand bien nommer les choses compte, et quand cela compte moins, par Tim
Shannon en 2018 :
https://tech.townsourced.com/post/when-naming-is-important-and-when-its-not/
- Quelques conseils pour bien nommer les choses, à l'époque où il y a
tellement de choses que l'on manque de mots, par
Joe Armstrong
en 2015 :
http://joearms.github.io/2015/03/12/The_web_of_names.html
- Court texte d'Eugene Wallingford en 2014 :
http://www.cs.uni.edu/~wallingf/blog/archives/monthly/2014-05.html#e2014-05-23T12_27_58.htm
- Conseils de Jane Street en 2014 :
https://blogs.janestreet.com/notes-on-naming/
- Conseils pour choisir de bons noms, prodigués par Aaron Zimmerman en
2015 :
http://sproutsocial.com/insights/naming-rules-for-coding/
- Exemples de mauvais choix de noms :
- Quelles sont les conséquences d'un mauvais nommage? Ce (douloureux) texte
de 2019 est instructif...
https://thedailywtf.com/articles/temporal-obfuscation
- Bien nommer les variables, texte de 2019 par Taohidul Islam :
https://blog.usejournal.com/naming-your-variables-f9477ba002e9
- Quelqu'un qui donne à ses classes des noms de
schémas de
conception et qui se questionne sur ses propres pratiques : http://www.sandywalsh.com/2010/04/am-i-bad-man-for-naming-my-classes.html
- Lisibilité et nomenclature : http://www.codesimplicity.com/post/readability-and-naming-things/
- Réflexions sur le sujet :
- À juste titre, dans ce texte de 2016,
Sebastian Malaca nous rappelle que des conjonctions (And)
et des disjonctions (Or), ça n'a pas sa place dans
un nom d'identifiant :
https://dzone.com/articles/conjunctions-we-hate
- Peter Hilton, avec ce texte de 2016, parle de
Naming Smells, ces noms qui indique que le code est... suspect :
http://hilton.org.uk/blog/naming-smells
- Conseils pour des pratiques de nommage plus saines, prodigués par
Jonathan Boccara en 2017 :
http://www.fluentcpp.com/2017/01/30/how-to-choose-good-names/
Difficultés inhérentes au nommage
À propos de la difficulté inhérente du nommage :
- Il semble que nommer soit une tâche difficile pour la plupart des
programmeurs, comme l'indique Phil Johnson dans ce texte de 2013 :
http://www.itworld.com/cloud-computing/379566/don-t-go-programming-if-you-don-t-have-good-thesaurus
- Apprendre à bien nommer les choses, démarche par l'absurde proposée par
Erik Dietrich en 2013 :
http://www.daedtech.com/lessons-in-good-naming-through-absurdity
- Nommer est un problème difficile... mais pas toujours, comme le rappelle
Phil Nash en 2015 :
http://www.levelofindirection.com/journal/2015/5/1/naming-is-hard-or-is-it.html
- Selon Eevee (!) en 2016, nommer est ce qu'il
y a de plus ardu en programmation :
https://eev.ee/blog/2016/07/26/the-hardest-problem-in-computer-science/
- Selon Tomasz Kaczmarzyk en 2016, nommer est ce qu'il y a de plus ardu en programmation
(la phrase se répète, mais ce n'est pas un accident) :
http://blog.kaczmarzyk.net/2016/10/03/the-hardest-thing-in-computer-science/
- Texte de Mihai Emil (pas sûr du nom de famille) en
2017, qui souhaite discuter du nommage des objets mais qui, en
pratique, ne discute que du nommage des classes :
https://www.amihaiemil.com/2018/01/07/my-take-on-object-naming.html
- En 2018,
Jonathan Boccara propose quelques
questions à se poser pour cibler un bon nom :
https://www.fluentcpp.com/2018/02/16/right-question-right-name/
- À propos de la cohérence :
Concision ou longueur des noms
À propos de la concision :
- Les noms de variables sont-ils meilleurs lorsqu'ils sont plus courts?
http://www.artima.com/weblogs/viewpost.jsp?thread=266543
- En 2017, Peter Hilton met de l'avant que les
noms de variables qui se limitent à une seule lettre sont plus que suspects...
http://hilton.org.uk/blog/single-letter-names-tale
- Un nom plus long et plus explicite est-il nécessairement plus clair?
Quelques contre-exemples relevés en 2017 :
http://thedailywtf.com/articles/the-longest-method
- Quand est-on trop concis? En 2018, Matt
Bentley pose la question :
https://arne-mertz.de/2018/02/terseness-little-much/
- Profiter du vocabulaire commun des programmeuses et des programmeurs, un
texte (discutable, car c'est très culturel) de
Jonathan Boccara en
2019 :
https://www.fluentcpp.com/2019/04/30/common-vocabulary-software-developers/
- Le « plus court nom qui soit », soit _
selon
Jonathan Boccara
en 2019 :
https://www.fluentcpp.com/2019/06/18/the-shortest-name-there-is/
- Pourquoi utilise-t-on souvent i et
j comme noms de compteurs dans des répétitives? http://stackoverflow.com/questions/4137785/why-are-variables-i-and-j-used-for-counters
- Conseil de POO
par Travis Giggs en 2011 : ne pas
donner aux classes des noms qui, en anglais, terminent par er (comme
Controller, Manager,
Organizer, etc.) : http://objology.blogspot.com/2011/09/one-of-best-bits-of-programming-advice.html?spref=tw
- Texte de Swizec Teller en 2013 sur les
conséquences absurdes d'une économie de bande passante sur la base de la
longueur des identifiants :
http://swizec.com/blog/my-very-own-daily-wtf/swizec/5829
Pratiques de nommage
À propos de diverses pratiques quant au nommage. Notez que
Standards-programmation.html liste
plusieurs guides connus en ce sens :
- James Hague, en 2008, suggère de favoriser
des identifiants composés en partie de symboles non-alphanumériques :
http://prog21.dadgum.com/20.html?Programming
- Réflexion surprenante proposée en 2012
à l'effet d'éliminer les noms (de variables, pas de fonctions)
complètement : http://www.hxa.name/notes/note-hxa7241-20120708T0907Z.html
- Allégorie sur les noms et les verbes au royaume de
Java,
par Steve Yegge en 2006 :
http://steve-yegge.blogspot.ca/2006/03/execution-in-kingdom-of-nouns.html
- Nommer et le code ouvert, un texte de 2014 par
Martin Faasen :
http://blog.startifact.com/posts/on-naming-in-open-source.html
- Texte de 2010 par
Stephen
Wolfram et portant sur la poésie derrière les noms de fonctions :
http://blog.stephenwolfram.com/2010/10/the-poetry-of-function-naming/
- En 2016, Jacob Gabrielson propose un guide pour nommer des
variables :
http://a-nickels-worth.blogspot.ca/2016/04/a-guide-to-naming-variables.html
- Il est possible, en configurant Visual Studio, d'imposer des pratiques
perogrammatiques pour le recours aux majuscules, aux minuscules et aux
caractères de soulignement :
https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-naming-conventions
- En 2015, R. Martinho Fernandes propose le concept d'« ensemble de noms », pour regrouper les pratiques de nommage de C et de
C++ :
http://flamingdangerzone.com/cxx11/2015/03/10/name-sets.html
CamelCase, reverseCamelCase,
snake_case, etc.
« CamelCase is popular because it’s part of
OOP
culture, which was shaped by
Smalltalk, which used CamelCase because it does not allow _
in identifiers, because it used an early version of
ASCII
which had a left-pointing arrow instead of _, and it used the arrow for assignment » – Tony Finch (source)
Il y a des écoles de pensées sur le choix des majuscules, des minuscules, des
soulignements, etc. dans les noms d'identifiants. Évidemment, la plupart des
approches se valent, dans la mesure où elles sont appliquées de manière
cohérente (d'où le volet stylistique des
standards de programmation appliqués par diverses entreprises).
Constantes littérales ou symboliques
À propos des constantes littérales ou symboliques :
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 value_type : short {
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 ».
Lectures complémentaires
Quelques liens pour enrichir le propos.
- Un guide de sain nommage (surtout pour
C++),
proposé par Tony van Eerd :
https://github.com/tvaneerd/isocpp/blob/master/on_naming.md
- En 2015, R. Martinho Fernandes propose le concept d'« ensemble de noms », pour regrouper les pratiques de nommage de C et de
C++ :
http://flamingdangerzone.com/cxx11/2015/03/10/name-sets.html
- Quand bien nommer les choses compte, et quand cela compte moins, par Tim
Shannon en 2018 :
https://tech.townsourced.com/post/when-naming-is-important-and-when-its-not/
- Quelques conseils pour bien nommer les choses, à l'époque où il y a
tellement de choses que l'on manque de mots, par
Joe Armstrong
en 2015 :
http://joearms.github.io/2015/03/12/The_web_of_names.html
- Nomenclature de fichiers, sur un plan historique, un texte de Thomas
Galvin en 2015 relatant l'histoire du format de
nom de fichiers 8 . 3 de l'époque
DOS et montrant que ce format existe toujours, sous la couverture... :
https://usn.pw/blog/gen/2015/06/09/filenames/
- Compter le nombre d'occurrences de certains mots dans un fichier source
peut être instructif, comme l'indique ce texte de
Jonathan Boccara en
2018 :
https://www.fluentcpp.com/2018/10/09/3-things-that-counting-words-can-reveal-on-your-code/
- Constantes littérales ou symboliques :
- Nommage et concepts mathématiques :
- Nommer les choses est difficile :
- À propos de la cohérence :
- À propos de la concision :
- Quelles sont les conséquences d'un mauvais nommage? Ce (douloureux) texte
de 2019 est instructif...
https://thedailywtf.com/articles/temporal-obfuscation
- Bien nommer les variables, texte de 2019 par Taohidul Islam :
https://blog.usejournal.com/naming-your-variables-f9477ba002e9