例如,局部变量和参数变量的命名约定


13

我正在与高级开发人员讨论编码约定,以适用于我们的项目(主要是Java / JEE项目)。我不同意他提出的一项约定:

实例变量名称应以“ _”开头,局部变量应以“ loc”开头,方法参数应以“ par”开头,因此很容易识别变量的来源和范围。

尽管他提出了关于短期内存和可读性的观点,但我不同意这样的事实,即它会降低可读性,IDE像Eclipse格式变量一样根据类型的不同而不同,并且通过良好的类和方法设计可以避免此问题。

您是否有任何观点,论点或研究支持我的观点(或反对)?


您说您不同意“它会降低可读性的事实”。我并不是说您错了,但是您提供了哪些证据来支持该主张?我没有发现任何会降低可读性的研究(我成为开发人员之前曾在研究生院心理学专业学习认知,因此这是我感兴趣的领域。)
AdamJonR 2012年

我说的很混乱。但是,我并不比我个人的意见等证据
HH

前缀重复了已经包含在代码中并在任何体面的环境中显示的信息。众所周知,重复的信息可能会变得不一致。DRY应该指出您不使用前缀。
朱莉娅·海沃德

Answers:


15

正如Wikipedia所说的那样-Java命名规则,

局部变量,实例变量和类变量也用lowerCamelCase编写。变量名不应以下划线(_)或美元符号($)开头,即使两者都允许。某些编码约定指出,应使用下划线作为所有实例变量的前缀,以提高阅读和程序理解的能力。

根据我在编码标准方面的经验,实例变量名称以“ _”开头并不像维基百科标准所说的那样好。

正如您所说的,使用“ loc”局部变量和使用“ par”局部变量的方法参数,就像您说的那样,很容易识别变量的起源和范围,但这应该由您自己决定,而不是其他程序员有一天可能会通过您的代码进行维护。

根据有关方法的Clean Code规范,这些方法应尽可能简短,以提高可读性,并且变量名称不应与思维方式映射,它们应与方法执行的操作相关。

成员/范围前缀,您也不再需要为成员变量加上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());
}

现在,自己动手看看代码(摘自spring-data-elasticsearch项目的ElasticsearchTemplate-我正在查看的代码促使我在Google上搜索人们对命名约定的看法)。

  • 的代码是什么resultsMapper
  • requestBuilding参数吗?
  • 等等...

这是有关如何命名变量的简单建议:

  • 类的静态属性(即常量):ALL_CAPS_WITH_UNDERSCORES(例如HOST_NAME)。
  • 类属性(即类实例变量):camelCase(例如resultsMapper)。
  • 方法参数:前缀a(如aQueryaClazz)。
  • 局部变量:前缀my(如myIndexNamemyType)。

上面的代码变为:

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:易于阅读,不需要读者在学习之前先了解所有内容。


3

这很大程度上是一个偏好问题,因此没有“正确”的答案。因此,这个问题实际上可能是封闭的。但是在此之前,让我告诉您我完全同意您的观点。就我而言,前缀会降低可见性。更不用说如果有前缀的话,就应该将它们用于更有用的东西,例如匈牙利符号的初衷,而不是用于IDE可以突出显示的东西。

我将SentenceCase用于实例数据(无论是变量还是常量),并将lower_case用于参数和局部变量,因为两者之间的差异实际上很小(如果有的话)。我从来没有使用过headlessCamelCase,因为它很:单组件标识符看起来像小写字母,即使原本打算是headlessCamelCase也是如此。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.