Style de code et versions linguistiques
Table des matières
Afin d’obtenir un produit cohérent, nous suivrons tous (si possible) des directives de style définies en externe pour chaque langue. Pour d’autres choses comme la mise en page du package ou la mise en page de la documentation, nous devrons proposer nos propres directives, en nous appuyant sur les styles actuels et populaires actuellement utilisés.
De plus, dans la mesure du possible, les développeurs doivent utiliser des outils intégrés pour leur permettre de vérifier que ces directives sont suivies dans leurs éditeurs. Par exemple, tout le monde devrait avoir un vérificateur PEP8 intégré à son éditeur pour réduire les itérations de révision liées au style.
Aussi, dans la mesure du possible, les packages doivent vérifier le style dans le cadre de leurs tests unitaires pour aider à la détection automatisée des problèmes de style (voir ament_lint_auto).
C
Style
Nous utiliserons Python’s PEP7 pour notre guide de style C, avec quelques modifications et ajouts :
Nous ciblerons C99, car nous n’avons pas besoin de prendre en charge C89 (comme le recommande PEP7)
justification : entre autres choses, cela nous permet d’utiliser à la fois les commentaires de style
//
et/* */
justification: C99 est à peu près omniprésent maintenant
Les commentaires
//
de style C++ sont autorisés(facultatif) Placez toujours les littéraux à gauche des opérateurs de comparaison, par ex.
0 == ret
au lieu deret == 0
raisonnement :
ret == 0
se transforme trop facilement enret = 0
par accidentfacultatif car lors de l’utilisation de
-Wall
(ou équivalent), les compilateurs modernes vous avertiront lorsque cela se produira
Toutes les modifications suivantes ne s’appliquent que si nous n’écrivons pas de modules Python :
N’utilisez pas
Py_
comme préfixe pour toututilisez plutôt une version CamelCase du nom du package ou un autre préfixe approprié
Les trucs sur les chaînes de documentation ne s’appliquent pas
Nous pouvons utiliser le module python pep7 pour la vérification du style. L’intégration de l’éditeur semble mince, nous devrons peut-être examiner plus en détail la vérification automatisée du C.
C++
Style
Nous utiliserons le Google C++ Style Guide, avec quelques modifications :
Longueur de la ligne
Notre longueur de ligne maximale est de 100 caractères.
Extensions de fichiers
Les fichiers d’en-tête doivent utiliser l’extension .hpp.
justification : Autoriser les outils à déterminer le contenu des fichiers, C++ ou C.
Les fichiers d’implémentation doivent utiliser l’extension .cpp.
justification : Autoriser les outils à déterminer le contenu des fichiers, C++ ou C.
Dénomination des variables
Pour les variables globales, utilisez des minuscules avec des traits de soulignement préfixés par
g_
justification : conserver la cohérence de la casse des noms de variables tout au long du projet
justification : facile à déterminer la portée d’une variable en un coup d’œil
cohérence entre les langues
Dénomination des fonctions et des méthodes
Le guide de style de Google indique
CamelCase
, mais le style desnake_case
de la bibliothèque C++ std est également autoriséjustification : les packages de base ROS 2 utilisent actuellement
snake_case
raison : soit un oubli historique, soit une préférence personnelle qui n’a pas été vérifiée par le linter
raison de ne pas changer : changer rétroactivement serait trop perturbateur
autres considérations:
cpplint.py
ne vérifie pas ce cas (difficile à appliquer autrement qu’avec révision)snake_case
peut entraîner une plus grande cohérence entre les langues
conseils spécifiques :
pour les projets existants, préférez le style existant
pour les nouveaux projets, l’un ou l’autre est acceptable, mais une préférence pour les projets existants connexes est conseillée
la décision finale est toujours à la discrétion du développeur
des cas particuliers comme les pointeurs de fonction, les types appelables, etc. peuvent nécessiter de contourner les règles
Notez que les classes doivent toujours utiliser
CamelCase
par défaut
Contrôle d’accès
Abandonnez l’exigence que tous les membres de la classe soient privés et nécessitent donc des accesseurs
justification : cela est trop contraignant pour la conception de l’API utilisateur
nous devrions préférer les membres privés, ne les rendant publics que lorsqu’ils sont nécessaires
nous devrions envisager d’utiliser des accesseurs avant de choisir d’autoriser l’accès direct aux membres
nous devrions avoir une bonne raison d’autoriser l’accès direct aux membres, autre que parce que c’est pratique pour nous
Des exceptions
Les exceptions sont autorisées
justification : il s’agit d’une nouvelle base de code, donc l’argument hérité ne s’applique pas à nous
justification : pour les API orientées utilisateur, il est plus idiomatique de C++ d’avoir des exceptions
Les exceptions dans les destructeurs doivent être explicitement évitées
Nous devrions envisager d’éviter les exceptions si nous avons l’intention d’envelopper l’API résultante en C
logique : cela facilitera l’encapsulation en C
justification : la plupart de nos dépendances dans le code que nous avons l’intention d’envelopper en C n’utilisent pas d’exceptions de toute façon
Objets de type fonction
Aucune restriction sur Lambda ou
std::function
oustd::bind
Augmenter
Le boost doit être évité à moins qu’il ne soit absolument nécessaire.
Commentaires et commentaires de documentation
Utilisez les commentaires
///
et/** */
à des fins de documentation et les commentaires de style//
pour les notes et les commentaires générauxLes commentaires de classe et de fonction doivent utiliser les commentaires de style
///
et/** */
justification : ceux-ci sont recommandés pour Doxygen et Sphinx en C/C++
logique : mélanger
/* */
et//
est pratique pour bloquer le code qui contient des commentairesLes descriptions du fonctionnement du code ou les notes dans les classes et les fonctions doivent utiliser des commentaires de style
//
Alignement de la syntaxe du pointeur
Utilisez
char * c;
au lieu dechar* c;
ouchar *c;
à cause de ce scénariochar* c, *d, *e;
Mots-clés de confidentialité de classe
Ne mettez pas 1 espace avant
public:
,private:
ouprotected:
, il est plus cohérent que toutes les indentations soient un multiple de 2justification : la plupart des éditeurs n’aiment pas les indentations qui ne sont pas un multiple de la taille de l’onglet (soft)
Utilisez zéro espace avant
public:
,private:
, ouprotected:
, ou 2 espacesSi vous utilisez 2 espaces avant, indentez les autres instructions de classe de 2 espaces supplémentaires
Préférez zéro espace, c’est-à-dire
public:
,private:
ouprotected:
dans la même colonne que la classe
Modèles imbriqués
Ne jamais ajouter d’espace aux modèles imbriqués
Préférez
set<list<string>>
(fonctionnalité C++11) àset<list<string> >
ouset< list<string> >
Utilisez toujours des accolades
Utilisez toujours des accolades après
if
,else
,do
,while
etfor
, même lorsque le corps est une seule ligne.justification : moins de possibilités d’ambiguïté visuelle et de complications dues à l’utilisation de macros dans le corps
Bretelles ouvertes ou douillettes
Utilisez des accolades ouvertes pour les définitions de
function
,class
,enum
etstruct
, mais mettez des accolades surif
,else
,while` `, ``pour
, etc…Exception : lorsqu’une condition
if
(ouwhile
, etc.) est suffisamment longue pour nécessiter un retour à la ligne, utilisez une accolade ouverte (c’est-à-dire, ne vous blottissez pas).
Lorsqu’un appel de fonction ne peut pas tenir sur une ligne, placez-le à la parenthèse ouverte (pas entre les arguments) et commencez-les sur la ligne suivante avec un retrait de 2 espaces. Continuez avec le retrait de 2 espaces sur les lignes suivantes pour plus d’arguments. (Notez que le Google style guide est contradictoire en interne sur ce point.)
Il en va de même pour les conditions
if
(etwhile
, etc.) qui sont trop longues pour tenir sur une seule ligne.
Exemples
C’est acceptable:
int main(int argc, char **argv)
{
if (condition) {
return 0;
} else {
return 1;
}
}
if (this && that || both) {
...
}
// Long condition; open brace
if (
this && that || both && this && that || both && this && that || both && this && that)
{
...
}
// Short function call
call_func(foo, bar);
// Long function call; wrap at the open parenthesis
call_func(
foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar,
foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar);
// Very long function argument; separate it for readability
call_func(
bang,
fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo,
bar, bat);
Ce n’est pas OK :
int main(int argc, char **argv) {
return 0;
}
if (this &&
that ||
both) {
...
}
Utilisez des accolades ouvertes plutôt qu’une indentation excessive, par ex. pour distinguer le code du constructeur des listes d’initialisation du constructeur
C’est acceptable:
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
Type par_name1, // 2 space indent
Type par_name2,
Type par_name3)
{
DoSomething(); // 2 space indent
...
}
MyClass::MyClass(int var)
: some_var_(var),
some_other_var_(var + 1)
{
...
DoSomething();
...
}
Ce n’est pas OK, même bizarre (à la manière de Google ?) :
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
Type par_name1, // 4 space indent
Type par_name2,
Type par_name3) {
DoSomething(); // 2 space indent
...
}
MyClass::MyClass(int var)
: some_var_(var), // 4 space indent
some_other_var_(var + 1) { // lined up
...
DoSomething();
...
}
Linters
Nous vérifions ces styles avec une combinaison de cpplint.py et uncrustify de Google.
Nous fournissons des outils de ligne de commande avec des configurations personnalisées :
Certains formateurs tels que ament_uncrustify et ament_clang_format prennent en charge les options --reformat
pour appliquer les modifications sur place.
Nous exécutons également d’autres outils pour détecter et éliminer autant d’avertissements que possible. Voici une liste non exhaustive des choses supplémentaires que nous essayons de faire sur tous nos forfaits :
utiliser des drapeaux de compilateur comme
-Wall -Wextra -Wpedantic
exécuter une analyse de code statique comme
cppcheck
, que nous avons intégré dans ament_cppcheck.
Python
Style
Nous utiliserons les directives PEP8 pour le format du code.
Nous avons choisi la règle plus précise suivante où PEP 8 laisse une certaine liberté :
Nous autorisons jusqu’à 100 caractères par ligne (cinquième paragraphe).
Nous préférons les retraits suspendus pour les lignes de continuation.
Des outils tels que le package Python (ament_)pycodestyle
doivent être utilisés dans les tests unitaires et/ou l’intégration de l’éditeur pour vérifier le style de code Python.
La configuration pycodestyle utilisée dans le linter est ici.
Intégration avec les éditeurs :
CMake
Style
Puisqu’il n’y a pas de guide de style CMake existant, nous définirons le nôtre :
Utilisez des noms de commande en minuscules (
find_package
, et nonFIND_PACKAGE
).Utilisez les identifiants
snake_case
(variables, fonctions, macros).Utilisez les commandes vides
else()
etend...()
.Pas d’espace avant
(
“s.Utilisez deux espaces d’indentation, n’utilisez pas de tabulations.
N’utilisez pas d’indentation alignée pour les paramètres d’invocations de macros multilignes. N’utilisez que deux espaces.
Préférez les fonctions avec
set(PARENT_SCOPE)
aux macros.Lorsque vous utilisez des macros, préfixez les variables locales avec
_
ou un préfixe raisonnable.
Markdown / Texte restructuré / docblocks
Style
Les règles suivantes pour formater le texte sont destinées à augmenter la lisibilité ainsi que la gestion des versions.
[.md, .rst uniquement] Chaque titre de section doit être précédé d’une ligne vide et suivi d’une ligne vide.
Justification : Il est plus rapide d’avoir une vue d’ensemble de la structure lors de la sélection du document.
[.rst uniquement] Dans le texte restructuré, les titres doivent suivre la hiérarchie décrite dans le guide de style Sphinx :
#
avec surlignement (une seule fois, utilisé pour le titre du document)*
avec surlignement=
-
^
"
Justification : Une hiérarchie cohérente permet d’avoir une idée du niveau d’imbrication lors du filtrage du document.
[.md uniquement] Dans Markdown, les en-têtes doivent suivre le style ATX décrit dans la documentation de la syntaxe Markdown
Les en-têtes de style ATX utilisent 1 à 6 caractères de hachage (
#
) au début de la ligne pour indiquer les niveaux d’en-tête 1 à 6.Un espace entre les hachages et le titre de l’en-tête doit être utilisé (comme
# Titre 1
) pour faciliter leur séparation visuelle.La justification de la préférence de style ATX provient du guide de style Google Markdown
Justification : les en-têtes de style ATX sont plus faciles à rechercher et à gérer, et rendent les deux premiers niveaux d’en-tête cohérents avec les autres niveaux.
[any] Chaque phrase doit commencer sur une nouvelle ligne.
Justification : Pour les paragraphes plus longs, un seul changement au début rend le diff illisible car il se poursuit dans tout le paragraphe.
[any] Chaque phrase peut éventuellement être enveloppée pour garder chaque ligne courte.
[any] Les lignes ne doivent pas avoir d’espaces blancs à la fin.
[.md, .rst uniquement] Un bloc de code doit être précédé et suivi d’une ligne vide.
Justification : Les espaces blancs ne sont significatifs que directement avant et directement après les blocs de code clôturés. Le respect de ces instructions garantira que la mise en surbrillance fonctionne correctement et de manière cohérente.
[.md, .rst uniquement] Un bloc de code doit spécifier une syntaxe (par exemple,
bash
).