Conventions de dénomination, par exemple, variables locales et paramètres [fermé]

13

Je discutais avec un développeur senior des conventions de codage à appliquer à nos projets (principalement les projets Java / JEE). Je suis en désaccord avec une convention qu'il propose:

Les noms de variables d'instance doivent commencer par "_", les variables locales par "loc" et les paramètres de méthode par "par", il serait donc facile d'identifier l'origine et la portée d'une variable.

Bien qu'il ait avancé des arguments pour la mémoire à court terme et la lisibilité, je n'étais pas d'accord sur le fait que cela diminue plutôt la lisibilité, les IDE comme les variables de format Eclipse différemment selon leur type, et ce problème serait évité avec une bonne conception de classe et de méthode.

Avez-vous une opinion, des arguments ou des études qui soutiennent mon argument (ou s'y opposent)?

HH
la source
Vous dites que vous n'êtes pas d'accord sur "le fait que cela diminue plutôt la lisibilité". Je ne dis pas que vous vous trompez, mais quelles preuves avez-vous fournies pour étayer cette affirmation? Je ne suis au courant d'aucune recherche qui indique que cela réduira la lisibilité (j'ai étudié la psychologie cognitive avant de devenir développeur, c'est donc un domaine qui m'intéresse.)
AdamJonR
Je le pensais car il est encombrant. Mais je n'ai aucune preuve autre que mon opinion personnelle
HH
Les préfixes dupliquent les informations déjà contenues dans le code et affichées dans n'importe quel environnement semi-décent. Et comme nous le savons tous, les informations en double peuvent devenir incohérentes. DRY devrait vous indiquer de ne pas utiliser les préfixes.
Julia Hayward

Réponses:

15

Comme Wikipedia le dit sur le sujet - Règles pour nommer java,

Les variables locales, les variables d'instance et les variables de classe sont également écrites dans lowerCamelCase. Les noms de variable ne doivent pas commencer par des caractères de soulignement (_) ou de signe dollar ($), même si les deux sont autorisés. Certaines conventions de codage stipulent que les traits de soulignement doivent être utilisés pour préfixer toutes les variables d'instance, pour une meilleure lecture et une meilleure compréhension du programme.

D'après mon expérience avec les normes de codage, les noms de variables d'instance commençant par "_" ne sont pas très bons comme le disent les normes wikipedia.

les variables locales avec "loc", et les paramètres de méthode avec "par", comme vous l'avez dit, il serait facile d'identifier l'origine et la portée d'une variable, mais cela devrait être pour vous, pas pour les autres programmeurs qui pourraient passer un jour votre code pour la maintenance .

Conformément à la spécification Clean Code sur les méthodes, celles-ci doivent être aussi courtes que possible pour la lisibilité et les noms de variables ne doivent pas être mappés, ils doivent être pertinents pour votre opération que votre méthode effectue.

Préfixes de membre / portée, vous n'avez plus besoin de préfixer les variables de membre avec m_. Vos classes et fonctions doivent être suffisamment petites pour que vous n'en ayez pas besoin. Et vous devez utiliser un environnement d'édition qui met en évidence ou colorise les membres pour les distinguer.

public class Part {
private String m_dsc; // The textual description
void setName(String name) {
m_dsc = name;
}
}

public class Part {
String description;
void setDescription(String description) {
this.description = description;
}
}

De plus, les gens apprennent rapidement à ignorer le préfixe (ou suffixe) pour voir la partie significative du nom. Plus nous lisons le code, moins nous voyons les préfixes. Finalement, les préfixes deviennent un encombrement invisible et un marqueur de code plus ancien.

Niranjan Singh
la source
4

C'est une vieille question, mais je vais quand même poster ici. J'ai plus de 20 ans de programmation et de gestion du code d'autres personnes.

Je pense que nommer votre variable avec une brève indication quant à leur portée est vraiment très utile pour la prochaine personne (ou vous-même) qui examinera votre code.

On ne regarde pas déjà le code dans un IDE avec de jolies couleurs (et je ne me souviens pas ce que les couleurs signifient et différents IDE montrent des couleurs différentes, etc.).

Certes, les méthodes doivent être suffisamment courtes pour ne pas être chargées de tonnes de variables et de tonnes de code, mais même sur une courte - lorsque vous regardez du code qui ne vous est pas familier, il est parfois difficile de dire si une variable est une variable de classe, locale variable ou paramètre de méthode.

Pour pouvoir distinguer en un coup d'œil, il est très facile de revoir le code que vous ne connaissez pas.

Prenez cet exemple:

public <T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz) {
    int startRecord = 0;
    ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
    String indexName = isNotBlank(query.getIndexName()) ? query.getIndexName() : persistentEntity.getIndexName();
    String type = isNotBlank(query.getType()) ? query.getType() : persistentEntity.getIndexType();

    Assert.notNull(indexName, "No 'indexName' defined for MoreLikeThisQuery");
    Assert.notNull(type, "No 'type' defined for MoreLikeThisQuery");
    Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");

    MoreLikeThisRequestBuilder requestBuilder = client.prepareMoreLikeThis(indexName, type, query.getId());

    if (query.getPageable() != null) {
        startRecord = query.getPageable().getPageNumber() * query.getPageable().getPageSize();
        requestBuilder.setSearchSize(query.getPageable().getPageSize());
    }
    requestBuilder.setSearchFrom(startRecord);

    if (isNotEmpty(query.getSearchIndices())) {
        requestBuilder.setSearchIndices(toArray(query.getSearchIndices()));
    }
    if (isNotEmpty(query.getSearchTypes())) {
        requestBuilder.setSearchTypes(toArray(query.getSearchTypes()));
    }
    if (isNotEmpty(query.getFields())) {
        requestBuilder.setField(toArray(query.getFields()));
    }
    if (isNotBlank(query.getRouting())) {
        requestBuilder.setRouting(query.getRouting());
    }
    if (query.getPercentTermsToMatch() != null) {
        requestBuilder.setPercentTermsToMatch(query.getPercentTermsToMatch());
    }
    if (query.getMinTermFreq() != null) {
        requestBuilder.setMinTermFreq(query.getMinTermFreq());
    }
    if (query.getMaxQueryTerms() != null) {
        requestBuilder.maxQueryTerms(query.getMaxQueryTerms());
    }
    if (isNotEmpty(query.getStopWords())) {
        requestBuilder.setStopWords(toArray(query.getStopWords()));
    }
    if (query.getMinDocFreq() != null) {
        requestBuilder.setMinDocFreq(query.getMinDocFreq());
    }
    if (query.getMaxDocFreq() != null) {
        requestBuilder.setMaxDocFreq(query.getMaxDocFreq());
    }
    if (query.getMinWordLen() != null) {
        requestBuilder.setMinWordLen(query.getMinWordLen());
    }
    if (query.getMaxWordLen() != null) {
        requestBuilder.setMaxWordLen(query.getMaxWordLen());
    }
    if (query.getBoostTerms() != null) {
        requestBuilder.setBoostTerms(query.getBoostTerms());
    }

    SearchResponse response = requestBuilder.execute().actionGet();
    return resultsMapper.mapResults(response, clazz, query.getPageable());
}

Maintenant, chronométrez-vous et regardez le code (extrait d'ElasticsearchTemplate du projet spring-data-elasticsearch - le code que je révisais qui m'a incité à rechercher sur Google ce que les gens disent à propos des conventions de dénomination).

  • Quel est le scode de resultsMapper?
  • Est requestBuildingun paramètre?
  • etc...

Voici ma simple suggestion sur la façon de nommer les variables:

  • Attributs statiques de classe (c'est-à-dire constantes): ALL_CAPS_WITH_UNDERSCORES (par exemple HOST_NAME).
  • Attributs de classe (ie variables d'instance de classe): camelCase (par exemple resultsMapper).
  • Paramètres de méthode: préfixé avec a(par exemple aQuery, aClazz).
  • Variables locales: préfixées avec my(par exemple myIndexName, myType).

Le code ci-dessus devient:

public <T> Page<T> moreLikeThis(MoreLikeThisQuery aQuery, Class<T> aClazz) {
  int myStartRecord = 0;
  ElasticsearchPersistentEntity myPersistentEntity = getPersistentEntityFor(aClazz);
  String myIndexName = isNotBlank(aQuery.getIndexName()) ? aQuery.getIndexName() : myPersistentEntity.getIndexName();
  String myType = isNotBlank(aQuery.getType()) ? aQuery.getType() : myPersistentEntity.getIndexType();

  Assert.notNull(myIndexName, "No 'indexName' defined for MoreLikeThisQuery");
  Assert.notNull(myType, "No 'type' defined for MoreLikeThisQuery");
  Assert.notNull(aQuery.getId(), "No document id defined for MoreLikeThisQuery");

  MoreLikeThisRequestBuilder myRequestBuilder = client.prepareMoreLikeThis(myIndexName, myType, aQuery.getId());

  if (aQuery.getPageable() != null) {
     myStartRecord = aQuery.getPageable().getPageNumber() * aQuery.getPageable().getPageSize();
     myRequestBuilder.setSearchSize(aQuery.getPageable().getPageSize());
  }
  myRequestBuilder.setSearchFrom(myStartRecord);

  if (isNotEmpty(aQuery.getSearchIndices())) {
     myRequestBuilder.setSearchIndices(toArray(aQuery.getSearchIndices()));
  }
  if (isNotEmpty(aQuery.getSearchTypes())) {
     myRequestBuilder.setSearchTypes(toArray(aQuery.getSearchTypes()));
  }
  if (isNotEmpty(aQuery.getFields())) {
     myRequestBuilder.setField(toArray(aQuery.getFields()));
  }
  if (isNotBlank(aQuery.getRouting())) {
     myRequestBuilder.setRouting(aQuery.getRouting());
  }
  if (aQuery.getPercentTermsToMatch() != null) {
     myRequestBuilder.setPercentTermsToMatch(aQuery.getPercentTermsToMatch());
  }
  if (aQuery.getMinTermFreq() != null) {
     myRequestBuilder.setMinTermFreq(aQuery.getMinTermFreq());
  }
  if (aQuery.getMaxQueryTerms() != null) {
     myRequestBuilder.maxQueryTerms(aQuery.getMaxQueryTerms());
  }
  if (isNotEmpty(aQuery.getStopWords())) {
     myRequestBuilder.setStopWords(toArray(aQuery.getStopWords()));
  }
  if (aQuery.getMinDocFreq() != null) {
     myRequestBuilder.setMinDocFreq(aQuery.getMinDocFreq());
  }
  if (aQuery.getMaxDocFreq() != null) {
     myRequestBuilder.setMaxDocFreq(aQuery.getMaxDocFreq());
  }
  if (aQuery.getMinWordLen() != null) {
     myRequestBuilder.setMinWordLen(aQuery.getMinWordLen());
  }
  if (aQuery.getMaxWordLen() != null) {
     myRequestBuilder.setMaxWordLen(aQuery.getMaxWordLen());
  }
  if (aQuery.getBoostTerms() != null) {
     myRequestBuilder.setBoostTerms(aQuery.getBoostTerms());
  }

  SearchResponse myResponse = myRequestBuilder.execute().actionGet();
  return resultsMapper.mapResults(myResponse, aClazz, aQuery.getPageable());

}

C'est parfait? Je ne pense pas. Mais ce qui précède, en ce qui concerne les variables, est maintenant plus facile à lire. Il y a d'autres choses telles que l'alignement et l'espacement, que je n'entrerai pas dans cette réponse car elles ne sont pas liées à la question, ce qui faciliterait également la lecture.

Vous n'aimez pas Camel Case? Bien, utilisez des traits de soulignement, etc., mais préfixez vos variables locales et vos paramètres pour les rendre différents des variables d'instance de classe.

Vous n'aimez pas aet my- bien, restez cohérent dans votre projet et utilisez autre chose ... mais utilisez quelque chose.

Règle n ° 1: cohérence au sein du projet.

Règle n ° 2: facilite la lecture et n'exige pas du lecteur qu'il sache tout avant de pouvoir apprendre.

ETL
la source
3

C'est en grande partie une question de préférence, et en tant que telle il n'y a pas de réponse «correcte». Donc, cette question pourrait être fermée. Mais avant cela, permettez-moi de vous dire que je suis totalement d'accord avec vous. Les préfixes diminuent la visibilité en ce qui me concerne. Sans parler du fait que s'il doit y avoir des préfixes, ils doivent être utilisés pour des choses plus utiles, comme l'intention originale de la notation hongroise , et non pour des choses que votre IDE peut de toute façon mettre en évidence.

J'utilise PhraseCase pour les données d'instance (variables ou constantes) et lower_case pour les paramètres et les variables locales, car il y a vraiment très peu, voire aucune, différence entre les deux. Je n'utilise jamais, headlessCamelCase parce qu'il est boiteux : un identifiant à un seul composant ressemble à des minuscules, même s'il était destiné à être headlessCamelCase.

Mike Nakis
la source