Соглашения об именах, например, локальные переменные и переменные параметров [закрыто]

13

Я обсуждал со старшими разработчиками соглашения о кодировании, применимые к нашим проектам (главным образом, к проектам Java / JEE). Я не согласен с одним соглашением, которое он предложил:

Имена переменных экземпляра должны начинаться с "_", локальные переменные - с "loc", а параметры метода - с "par", чтобы было легко определить источник и область видимости переменной.

Хотя он выдвигал аргументы в пользу кратковременной памяти и читабельности, я не согласился с тем фактом, что это значительно снижает читабельность, IDE, такие как переменные формата Eclipse, по-разному зависят от их типа, и этой проблемы можно было бы избежать с хорошим дизайном класса и метода.

Есть ли у вас мнение, аргументы или исследования, которые поддерживают мою точку зрения (или противостоят ей)?

HH
источник
Вы говорите, что не согласны с «тем фактом, что это скорее снижает читабельность». Я не говорю, что вы не правы, но какие доказательства вы предоставили в поддержку этого утверждения? Мне неизвестно о каких-либо исследованиях, в которых говорилось бы, что это снизит читабельность (до того, как стать разработчиком, я изучал когнитивную психологию в аспирантуре, поэтому это меня интересует).
AdamJonR
Я имел в виду, как это беспорядок. Но у меня нет никаких доказательств, кроме моего личного мнения
HH
Префиксы дублируют информацию, которая уже содержится в коде и отображается в любой полуприличной среде. И, как мы все знаем, дублирующаяся информация может стать противоречивой. DRY должен указывать на то, что вы не используете префиксы.
Джулия Хейворд,

Ответы:

15

Как Википедия говорит на эту тему - Правила для именования Java,

Локальные переменные, переменные экземпляра и переменные класса также записываются в lowerCamelCase. Имена переменных не должны начинаться с символов подчеркивания (_) или знака доллара ($), даже если разрешены оба. В некоторых соглашениях о кодировании указывается, что подчеркивания следует использовать для добавления префиксов ко всем переменным экземпляра, чтобы улучшить чтение и понимание программы.

Согласно моему опыту со стандартами кодирования, имена переменных экземпляра, начинающиеся с "_", не очень хороши, как говорят стандарты википедии.

локальные переменные с «loc» и параметры метода с «par», как вы сказали, было бы легко идентифицировать источник и область видимости переменной, но это должно быть для вас, а не для других программистов, которые могут когда-нибудь просмотреть ваш код для обслуживания ,

В соответствии со спецификацией Чистого кода о методах, они должны быть короткими, насколько они могут быть сделаны для удобства чтения, а имена переменных не должны быть сопоставлены, они должны иметь отношение к вашей операции, которую выполняет ваш метод.

Префиксы членов / областей действия. Вам также больше не нужно добавлять префиксы членов к m_. Ваши классы и функции должны быть достаточно маленькими, чтобы они вам не нужны. И вы должны использовать среду редактирования, которая выделяет или раскрашивает элементы, чтобы сделать их различимыми.

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;
}
}

Кроме того, люди быстро учатся игнорировать префикс (или суффикс), чтобы увидеть значимую часть имени. Чем больше мы читаем код, тем меньше мы видим префиксы. В конце концов префиксы становятся невидимым беспорядком и маркером старого кода.

Ниранджан Сингх
источник
4

Это старый вопрос, но я все равно отправлю сюда сообщение. У меня есть более 20 лет программирования и работы с чужим кодом.

Я думаю, что наименование вашей переменной с кратким указанием ее области действительно очень полезно для следующего человека (или вас самих), который будет смотреть на ваш код.

Никто еще не смотрит на код в IDE с красивыми цветами (и я не могу вспомнить, что означают цвета, и разные IDE показывают разные цвета и т. Д.).

Правда, методы должны быть достаточно короткими, чтобы они не загружались тоннами переменных и тоннами кода, но даже короткими - когда вы смотрите на код, который совершенно незнаком, иногда трудно сказать, является ли переменная переменной класса, локальной переменная или параметр метода.

Быстрая возможность различить позволяет легко просмотреть код, который вы не знаете.

Возьмите этот пример:

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());
}

Теперь оцените время и посмотрите на код (извлеченный из ElasticsearchTemplate из проекта spring-data -asticsearch - код, который я просматривал, который побудил меня искать в Google то, что люди говорят о соглашениях об именах).

  • Что за масштаб resultsMapper?
  • Это requestBuildingпараметр?
  • и т.д...

Вот мое простое предложение о том, как переменные должны быть названы:

  • Статические атрибуты класса (то есть константы): ALL_CAPS_WITH_UNDERSCORES (например HOST_NAME).
  • Атрибуты класса (т.е. переменные экземпляра класса): camelCase (например resultsMapper).
  • Параметры метода: с префиксом a(например aQuery, aClazz).
  • Локальные переменные: с префиксом my(например myIndexName, myType).

Код выше становится:

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());

}

Это идеально? Я так не думаю. Но вышесказанное, что касается переменных, теперь легче читать. Есть и другие вещи, такие как выравнивание и интервалы, в которые я не буду вдаваться в ответ, поскольку он не связан с вопросом, что также облегчит чтение.

Вам не нравится Кэмел Кейс? Хорошо, используйте подчеркивание и т. Д., Но ставьте префикс локальных переменных и параметров, чтобы они отличались от переменных экземпляра класса.

Вам не нравится aи my- хорошо, просто оставайтесь последовательными в своем проекте и используйте что-то еще ... но используйте что-то.

Правило № 1: последовательность в рамках проекта.

Правило № 2: упрощайте чтение и не требуйте от читателя знания всего, прежде чем он сможет выучить.

ETL
источник
3

Это в основном вопрос предпочтений, и как такового «правильного» ответа нет. Таким образом, этот вопрос на самом деле может быть закрыт. Но прежде, чем это произойдет, позвольте мне сказать вам, что я полностью согласен с вами. Префиксы уменьшают видимость, насколько мне известно. Не говоря уже о том, что если есть какие-либо префиксы, они должны использоваться для более полезных вещей, таких как первоначальное намерение венгерской нотации , а не для вещей, которые ваша IDE может обеспечить подсветкой в ​​любом случае.

Я использую SentenceCase для данных экземпляра (переменных или констант) и нижний регистр для параметров и локальных переменных, поскольку на самом деле разница между ними на самом деле очень мала, если вообще существует. Я никогда не использую headlessCamelCase, потому что он хромает : однокомпонентный идентификатор выглядит как строчные буквы, даже если он предназначен для headlessCamelCase.

Майк Накис
источник