Style de code et versions linguistiques

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

Standard

Nous ciblerons C99.

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 de ret == 0

    • raisonnement : ret == 0 se transforme trop facilement en ret = 0 par accident

    • facultatif 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 tout

    • utilisez 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++

Standard

Cibles roulantes C++17.

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 de snake_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 ou std::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éraux

    • Les 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 commentaires

    • Les 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 de char* c; ou char *c; à cause de ce scénario char* c, *d, *e;

Mots-clés de confidentialité de classe

  • Ne mettez pas 1 espace avant public:, private: ou protected:, il est plus cohérent que toutes les indentations soient un multiple de 2

    • justification : 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:, ou protected:, ou 2 espaces

    • Si 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: ou protected: 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> > ou set< list<string> >

Utilisez toujours des accolades

  • Utilisez toujours des accolades après if, else, do, while et for, 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 et struct, mais mettez des accolades sur if, else, while` `, ``pour, etc…

    • Exception : lorsqu’une condition if (ou while, 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 (et while, 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

Version

Nous ciblerons Python 3 pour notre développement.

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é :

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

Version

Nous ciblerons CMake 3.8.

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

  • Utilisez les identifiants snake_case (variables, fonctions, macros).

  • Utilisez les commandes vides else() et end...().

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