CodeGym /Blog Java /Random-FR /Règles de codage : le pouvoir des noms corrects, des bons...
John Squirrels
Niveau 41
San Francisco

Règles de codage : le pouvoir des noms corrects, des bons et des mauvais commentaires

Publié dans le groupe Random-FR
Règles de codage : le pouvoir des noms corrects, des bons et des mauvais commentaires - 1Combien de fois avez-vous dû fouiller dans le code de quelqu'un d'autre ? Au lieu de deux heures, vous pouvez passer deux jours à comprendre simplement la logique de ce qui se passe. Le plus drôle, c'est que pour la personne qui a écrit le code, tout est clair et entièrement transparent. Ce n'est pas surprenant : après tout, le code parfait est un concept très vague, car chaque développeur a sa propre vision du monde et du code aussi. Plus d'une fois, j'ai été dans une situation où un collègue et moi avons regardé le même code et avions des opinions différentes sur son exactitude et sa propreté.Règles de codage : le pouvoir des noms corrects, des bons et des mauvais commentaires - 2Cela semble familier, n'est-ce pas? Pourtant, il existe des principes éprouvés qui doivent être respectés. Au final, ils vous seront avantageux, car si vous laissiez votre code dans l'état dans lequel vous aimeriez vous-même le recevoir, alors le monde deviendrait un peu plus heureux et plus propre. Dans notre précédent article(ou plutôt, petit guide) sur les règles de codage, nous avons eu une petite idée des recommandations pour écrire un système dans son ensemble et ses éléments constitutifs, tels que les objets, les interfaces, les classes, les méthodes et les variables. Dans ce même article, j'ai mentionné avec désinvolture la dénomination correcte de certains éléments. J'aimerais en parler aujourd'hui, car des noms corrects rendent le code beaucoup plus facile à lire. Nous terminerons le sujet du code correct avec quelques réflexions, de petits exemples de commentaires dans le code et une réflexion pour savoir si c'est bon ou pas si bon. Eh bien, commençons.

Noms corrects

Les noms corrects améliorent la lisibilité du code, réduisant ainsi le temps nécessaire pour se familiariser avec le code, car l'utilisation d'une méthode est beaucoup plus facile lorsque son nom décrit approximativement sa fonctionnalité. Tout dans le code est composé de noms (variables, méthodes, classes, objets, fichiers, etc.), ce point devient donc très important lors de la création d'un code correct et propre. Sur la base de ce qui précède, le nom doit transmettre une signification, par exemple, pourquoi la variable existe, ce qu'elle fait et comment elle est utilisée. Je noterai plus d'une fois que le meilleur commentaire pour une variable est de lui donner un bon nom.Règles de codage : le pouvoir des noms corrects, des bons et des mauvais commentaires - 3

de la série télévisée "Sherlock" (2010-2017)

Interfaces de nommage

Les interfaces ont généralement des noms qui commencent par une majuscule et sont écrits en CamelCase. Lors de l'écriture d'une interface, il était autrefois considéré comme une bonne pratique d'ajouter le préfixe "I" pour la désigner comme une interface (par exemple, IUserService), mais cela semble assez moche et gênant. Dans de tels cas, il est préférable d'omettre le préfixe (UserService) et d'ajouter "Impl" comme suffixe au nom de son implémentation (par exemple UserServiceImpl). Ou éventuellement, en dernier recours, ajouter un préfixe "C" au nom de l'implémentation (par exemple CUserService).

Noms de classe

Tout comme les interfaces, les noms de classe sont en majuscules et utilisent CamelCase. Peu importe si nous sommes confrontés à une apocalypse zombie, peu importe si la fin est proche - jamais, jamais, jamais le nom d'une classe ne devrait être un verbe ! Les noms de classe et d'objet doivent être des noms ou des noms composés (UserController, UserDetails, UserAccount, etc.). Vous ne devez pas coller l'abréviation de l'application à la fin du nom de chaque classe, car cela ne ferait qu'ajouter une complexité inutile. Par exemple, si nous avons une application de migration des données utilisateur, veuillez ne pas ajouter "UDM" à chaque classe, c'est-à-dire UDMUserDetails, UDMUserAccount, UDMUserController.

Noms de méthode

Habituellement, les noms de méthodes commencent par une lettre minuscule, mais ils utilisent également le style camel case (camelCase). Ci-dessus, nous avons dit que les noms de classe ne devraient jamais être des verbes. Ici, la situation est tout à fait opposée : les noms des méthodes doivent être des verbes ou des phrases verbales : findUserById, findAllUsers, createUser, etc. Lors de la création d'une méthode (ainsi que de variables et de classes), utilisez donc une convention de dénomination cohérente afin d'éviter toute confusion. Par exemple, pour rechercher un utilisateur, une méthode peut être nommée getUserById ou findUserById. Et encore une chose : n'utilisez pas d'humour dans les noms des méthodes, car d'autres pourraient ne pas comprendre la blague. En conséquence, ils peuvent ne pas comprendre ce que fait la méthode.

Noms des variables

Dans la plupart des cas, les noms de variables commencent par une lettre minuscule et utilisent également camelCase, sauf lorsque la variable est une constante globale. Dans ce cas, toutes les lettres du nom sont écrites en majuscules et les mots sont séparés par un trait de soulignement ("_"). Pour plus de commodité, vous pouvez utiliser un contexte significatif lorsque vous nommez des variables. En d'autres termes, lorsqu'une variable existe dans le cadre de quelque chose de plus grand, par exemple, firstName, lastName ou status. Dans ce cas, vous pouvez ajouter un préfixe qui indique l'objet auquel appartient cette variable. Par exemple : userFirstName, userLastName, userStatus. Vous devez également éviter les noms similaires pour les variables lorsqu'elles ont des significations complètement différentes. Voici quelques antonymes fréquemment rencontrés dans les noms de variables :
  • début/fin
  • premier Dernier
  • verrouillé/déverrouillé
  • min max
  • suivant précédent
  • ancien nouveau
  • ouvert/fermé
  • visibles/invisibles
  • cible Source
  • origine/destination
  • haut/bas

Noms courts des variables

Lorsque nous avons des variables comme x ou n ou quelque chose comme ça, nous ne voyons pas immédiatement l'intention de la personne qui a écrit le code. Ce que n fait n'est pas évident. Comprendre cela nécessite une réflexion plus approfondie (et cela signifie du temps, du temps, du temps). Par exemple, supposons que nous ayons un champ qui représente l'identifiant de l'utilisateur responsable. Au lieu d'un nom de variable comme x ou simplement id, nous nommerons cette variable "responsibleUserId", ce qui améliore immédiatement la lisibilité et le contenu de l'information. Cela dit, les noms courts comme n ont une place en tant que variables locales dans les petites méthodes, où le bloc de code impliquant cette variable ne fait que quelques lignes et le nom de la méthode décrit parfaitement ce qui s'y passe. En voyant une telle variable, un développeur comprend qu'elle est d'importance secondaire et a une portée très limitée. Par conséquent, la portée dépend dans une certaine mesure de la longueur du nom d'une variable : plus le nom est long, plus la variable est globale et vice versa. À titre d'exemple, voici une méthode pour trouver le dernier utilisateur enregistré par date :

public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("No user exists"));
}
Ici, nous utilisons des variables abrégées x et y pour trier le flux, puis nous les oublions.

Longueur optimale

Continuons avec le sujet de la longueur du nom. La longueur de nom optimale se situe quelque part entre n et maximumNumberOfUsersInTheCurrentGroup. En d'autres termes, les noms courts souffrent d'un manque de sens, tandis que les noms trop longs allongent le programme sans ajouter de lisibilité, et nous sommes tout simplement trop paresseux pour les écrire à chaque fois. Hormis le cas décrit ci-dessus pour les variables avec un nom court comme n, vous devez vous en tenir à une longueur d'environ 8 à 16 caractères. Ce n'est pas une règle stricte, juste une ligne directrice.

Petites différences

Je ne peux manquer de mentionner de subtiles différences dans les noms. C'est également une mauvaise pratique, car ces différences peuvent être simplement déroutantes ou nécessiter de passer beaucoup de temps supplémentaire pour les remarquer. Par exemple, la différence entre InvalidDataAccessApiUsageException et InvalidDataAccessResourceUsageException est difficile à repérer en un coup d'œil. La confusion peut également souvent survenir lors de l'utilisation de L et O minuscules, car ils peuvent facilement être confondus avec 1 et 0. Dans certaines polices, la différence est plus évidente, dans d'autres, elle l'est moins.

Le sens

Nous devons rendre les noms significatifs, mais ne pas créer d'ambiguïté par des synonymes, puisque, par exemple, UserData et UserInfo ont en fait la même signification. Dans ce cas, nous devrions approfondir le code pour comprendre de quel objet particulier nous avons besoin. Évitez les mots qui ne transmettent pas d'informations utiles. Par exemple, dans firstNameString, pourquoi avons-nous besoin du mot String ? Serait-ce vraiment un objet Date ? Bien sûr que non. Donc, nous utilisons simplement firstName. Je voudrais également mentionner les variables booléennes. Par exemple, prenons un booléen nommé flagDeleted. Le mot drapeau n'a pas de sens. Il est plus raisonnable de l'appeler isDeleted.

Désinformation

Je voudrais également dire quelques mots sur les conventions de nommage incorrectes. Disons que nous avons une variable nommée userActivityList, mais au lieu d'être une liste, cet objet est un autre type de conteneur ou un objet de stockage personnalisé. Cela pourrait confondre le programmeur moyen : il est préférable de l'appeler quelque chose comme userActivityGroup ou userActivities.

Recherche

L'un des inconvénients des noms courts et simples est qu'ils sont difficiles à trouver dans un grand corps de code — Quel serait le plus facile à trouver : "name" ou "NAME_FOR_DEFAULT_USER" ? La deuxième option, bien sûr. Nous devons éviter les mots (lettres) fréquemment rencontrés dans les noms, car ils ne feront qu'augmenter le nombre de fichiers correspondants lors d'une recherche, ce qui n'est pas bon. Je tiens à vous rappeler que les programmeurs passent plus de temps à lire du code qu'à l'écrire, alors soyez malin quant au nommage des éléments de votre application. Mais que se passe-t-il si un bon nom ne peut tout simplement pas être trouvé ? Que faire si le nom d'une méthode ne décrit pas bien sa fonctionnalité ? C'est là que les commentaires entrent en scène.

commentaires

Règles de codage : le pouvoir des noms corrects, des bons et des mauvais commentaires - 4Il n'y a rien de mieux qu'un commentaire pertinent, mais rien n'encombre un module comme des commentaires vides de sens, périmés ou faux. Ils peuvent être une épée à double tranchant, non ? Néanmoins, vous ne devez pas traiter les commentaires comme étant incontestablement bons, mais plutôt comme un moindre mal. Après tout, un commentaire est essentiellement un moyen de compenser une réflexion qui n'apparaît pas clairement dans le code. Par exemple, nous les utilisons pour transmettre d'une manière ou d'une autre l'essence d'une méthode, si la méthode elle-même s'avère trop déroutante. Dans cette situation, il vaut mieux refactoriser correctement le code que d'écrire des notes descriptives. Plus le commentaire est ancien, plus le commentaire est mauvais, car le code a tendance à grandir et à évoluer, mais les commentaires peuvent rester les mêmes. Plus le temps s'est écoulé depuis la création d'un commentaire, plus il peut être discutable. Les commentaires inexacts sont bien pires que l'absence de commentaires du tout, car ils sont déroutants et trompeurs, donnant de fausses attentes. Et même si nous avons du code très délicat, nous devrions le réécrire plutôt que de le commenter.

Types de commentaires

  • Commentaires juridiques — Commentaires au début de chaque fichier source pour des raisons juridiques, par exemple :

    
    * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    

  • Commentaires informatifs — Commentaires représentant une explication du code (fournissant des informations supplémentaires ou expliquant l'intention d'une section donnée du code).

    Par exemple:

    
    /*
    * Combines the user from the database with the one passed for updating
    * When a field in requestUser is empty, it is filled with old data from foundUser
    */
    private User mergeUser(User requestUser, User foundUser) {
           return new User(
           foundUser.getId(),
           requestUser.getFirstName() == null ? requestUser.getFirstName() : foundUser.getFirstName(),
           requestUser.getMiddleName() == null ? requestUser.getMiddleName() : foundUser.getMiddleName(),
           requestUser.getLastName() == null ? requestUser.getLastName() : foundUser.getLastName(),
           requestUser.getAge() == null ? requestUser.getAge() : foundUser.getAge()
           );
           }
    

    Dans ce cas, vous pouvez vous passer de commentaires, puisque le nom de la méthode et ses paramètres, couplés à des fonctionnalités très transparentes, se décrivent bien.

  • Commentaires d'avertissement — Commentaire destiné à avertir les autres développeurs des conséquences indésirables d'une action (par exemple, les avertir de la raison pour laquelle un test a été marqué comme @Ignore) :

    
    // Takes too long to run
    // Don't run if you don't have a lot of time
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
    

  • TODO — Commentaires qui sont une note sur quelque chose qui doit être fait à l'avenir mais qui, pour une raison quelconque, ne peut pas être fait maintenant. Il s'agit d'une bonne pratique, mais ces commentaires doivent être examinés régulièrement afin de supprimer ceux qui ne sont pas pertinents et d'éviter l'encombrement.

    Un exemple serait :

    
    // TODO: Add a check for the current user ID (when the security context is created)
    
    @Override
    public Resource downloadFile(File file) {
           return fileManager.download(file);
           }
    

    On note ici le fait qu'il faut ajouter une comparaison de l'utilisateur effectuant l'opération de téléchargement (dont nous allons extraire l'ID du contexte de sécurité) avec celui qui a effectué l'opération de sauvegarde.

  • Commentaires de renforcement — Commentaires soulignant l'importance d'une circonstance qui, à première vue, peut sembler insignifiante.

    À titre d'exemple, considérons un élément d'une méthode qui remplit une base de données de test avec des scripts :

    
    Stream.of(IOUtils.resourceToString("/fill-scripts/" + x, StandardCharsets.UTF_8)
           .trim()
           .split(";"))
           .forEach(jdbcTemplate::update);
    // The trim() call is very important. It removes possible spaces at the end of the script
    // so that when we read and split into separate requests, we don't end up with empty ones
    

  • Commentaires Javadoc — Commentaires qui décrivent l'API pour certaines fonctionnalités. Il y a probablement les commentaires les plus utiles, car l'API documentée est beaucoup plus facile à utiliser. Cela dit, ils peuvent aussi être obsolètes comme tout autre type de commentaire. Alors, n'oubliez jamais que la principale contribution à la documentation n'est pas faite par des commentaires, mais par un bon code.

    Voici un exemple de méthode assez courante pour mettre à jour un utilisateur :

    
    /**
    * Updates the passed fields for a user based on its id.
         *
    * @param id id of the user to be updated
    * @param user user with populated fields for updating
    * @return updated user
    */
           User update(Long id, User user);
    

Mauvais commentaires

  • commentaire marmonné — Commentaires généralement écrits à la hâte et dont le sens n'est compréhensible que pour le développeur qui les a rédigés, car lui seul perçoit la situation nuancée à laquelle le commentaire fait référence.

    Considérez cet exemple :

    
    public void configureSomeSystem() {
           try{
           String configPath = filesLocation.concat("/").concat(CONFIGURATION_FILE);
           FileInputStream stream = new FileInputStream(configPath);
           } catch (FileNotFoundException e) {
           // If there is no configuration file, the default configuration is loaded 
          }
    }
    

    Qui charge ces paramètres ? Sont-ils déjà chargés ? Cette méthode est-elle censée intercepter les exceptions et charger les paramètres par défaut ? Trop de questions se posent auxquelles on ne peut répondre qu'en approfondissant une enquête sur d'autres parties du système.

  • Commentaires redondants - Commentaires qui ne portent aucune charge sémantique, car ce qui se passe dans une section donnée du code est parfaitement clair. En d'autres termes, le commentaire n'est pas plus facile à lire que le code.

    Voyons un exemple :

    
    public class JdbcConnection{
    public class JdbcConnection{
       /**
        * The logger associated with the current class
        */
       private Logger log = Logger.getLogger(JdbcConnection.class.getName());
    
       /**
        * Creates and returns a connection using the input parameters
        */
       public static Connection buildConnection(String url, String login, String password, String driver) throws Exception {
           Class.forName(driver);
           connection = DriverManager.getConnection(url, login, password);
           log.info("Created connection with db");
           return connection;
       }
    

    Quel est l'intérêt de tels commentaires ? Tout ce qu'ils expliquent est déjà parfaitement clair.

  • Commentaires non fiables — Commentaires qui sont faux et seulement trompeurs (désinformation). Par exemple, en voici un.

    
    /**
    * Helper method. Closes the connection with the scanner if isNotUsing is true
    */
    private void scanClose(Scanner scan, boolean isNotUsing) throws Exception {
       if (!isNotUsing) {
           throw new Exception("The scanner is still in use");
       } scan.close();
    }
    

    Quel est le problème avec ce commentaire ? Le fait que cela nous mente un peu, en ce sens que la connexion est fermée si isNotUsing est faux, et non l'inverse, comme nous l'indique le commentaire.

  • Commentaires obligatoires — Les commentaires qui sont considérés comme obligatoires (par exemple les commentaires Javadoc), mais qui s'accumulent parfois de manière excessive et sont peu fiables et inutiles (vous devez vous demander si ces commentaires sont réellement nécessaires).

  • Exemple:

    
    /**
    * Create a user based on the parameters
    * @param firstName first name of the created user
    * @param middleName middle name of the created user
    * @param lastName last name of the created user
    * @param age age of the created user
    * @param address address of the created user
    * @return user that was created
    */
    User createNewUser(String firstName, String middleName, String lastName, String age, String address);
    

    Seriez-vous capable de comprendre ce que fait la méthode sans ces commentaires ? Très probablement, oui, donc les commentaires deviennent inutiles ici.

  • Commentaires du journal — Commentaires qui sont parfois ajoutés au début d'un module chaque fois qu'il est modifié (quelque chose comme un journal des modifications).

    
    /**
    * Records kept since January 9, 2020;
    **********************************************************************
    * 9 Jan 2020: Providing a database connection using JDBC Connection;
    * 15 Jan 2020: Adding DAO-level interfaces for working with the database;
    * 23 Jan 2020: Adding integration tests for the database;
    * 28 Jan 2020: Implementation of DAO-level interfaces;
    * 1 Feb 2020: Development of interfaces for services,
    * in accordance with the requirements specified in user stories;
    * 16 Feb 2020: Implementation of service interfaces
    * (implementation of business logic related to the work of the database);
    * 25 Feb 2020: Adding tests for services;
    * 8 Mar 2020: Celebration of International Women's Day (Terry is drunk again);
    * 21 Mar 2020: Refactoring the service layer;
    */
    

    Cette approche était autrefois justifiée, mais avec l'avènement des systèmes de contrôle de version (par exemple, Git), elle est devenue un encombrement inutile et une complication du code.

  • Commentaires d'auteur — Commentaires dont le but est d'indiquer la personne qui a écrit le code, afin que vous puissiez la contacter et discuter du comment, du quoi et du pourquoi, par exemple :

    
    * @author Bender Bending
    

    Encore une fois, les systèmes de contrôle de version se souviennent exactement de qui a ajouté un morceau de code et quand, cette approche est donc superflue.

  • Code commenté — Code qui a été commenté pour une raison ou une autre. C'est l'une des pires habitudes, car ce qui se passe, c'est que vous commentez quelque chose et que vous l'oubliez, et que les autres développeurs n'ont tout simplement pas le courage de le supprimer (après tout, et si c'était quelque chose de précieux ?).

    
    //    public void someMethod(SomeObject obj) {
    //    .....
    //    }
    

    En conséquence, le code commenté s'accumule comme des déchets. Vous ne devez en aucun cas laisser un tel code. Si vous en avez vraiment besoin, n'oubliez pas le système de contrôle de version.

  • Commentaires non évidents — Commentaires qui décrivent quelque chose d'une manière excessivement compliquée.

    
    /*
        * Start with an array large enough to store
        * all the data bytes (plus filter bytes) with a cushion, plus 300 bytes
        * for header data
        */
    this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];
    

    Un commentaire devrait expliquer le code. Il ne devrait pas lui-même avoir besoin d'explication. Alors qu'est-ce qui ne va pas ici? Que sont les "octets de filtre" ? Qu'est-ce que c'est que "+ 1" ? Pourquoi exactement 300 ?

Si vous avez déjà décidé d'écrire des commentaires, voici quelques conseils :
  1. Utilisez des styles faciles à entretenir : entretenir des styles trop fantaisistes et exotiques est ennuyeux et chronophage.
  2. N'utilisez pas de commentaires de fin de ligne faisant référence à une seule ligne : le résultat est une grande pile de commentaires. De plus, il est difficile d'imaginer un commentaire significatif pour chaque ligne.
  3. Lorsque vous rédigez un commentaire, essayez de répondre à la question "pourquoi", pas "comment".
  4. Évitez les informations abrégées. Comme je l'ai dit plus haut, nous n'avons pas besoin d'explication pour un commentaire : le commentaire lui-même est l'explication.
  5. Vous pouvez utiliser des commentaires pour noter les unités et les plages de valeurs.
  6. Placez les commentaires à proximité du code qu'ils décrivent.
Enfin, je tiens toujours à vous rappeler que le meilleur commentaire n'est pas un commentaire, mais plutôt l'utilisation d'un nommage habile tout au long de votre application. En règle générale, la plupart du temps, nous travaillerons avec du code existant, en le maintenant et en l'étendant. C'est beaucoup plus pratique lorsque ce code est facile à lire et compréhensible, car un mauvais code est un obstacle. C'est comme jeter une clé dans les travaux, et la hâte est sa fidèle compagne. Et plus nous avons de mauvais code, plus les performances baissent. Cela signifie que nous devons refactoriser de temps en temps. Mais si dès le départ vous essayez d'écrire du code qui ne poussera pas les prochains développeurs à vouloir vous trouver et vous tuer, alors vous n'aurez pas besoin de le refactoriser aussi souvent. Mais cela sera toujours nécessaire, car les conditions et les exigences du produit changent constamment avec l'ajout de nouvelles dépendances et connexions. Eh bien, je suppose que c'est tout pour moi aujourd'hui. Merci à tous ceux qui ont lu jusqu'ici :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION