我正在与高级开发人员讨论编码约定,以适用于我们的项目(主要是Java / JEE项目)。我不同意他提出的一项约定:
实例变量名称应以“ _”开头,局部变量应以“ loc”开头,方法参数应以“ par”开头,因此很容易识别变量的来源和范围。
尽管他提出了关于短期内存和可读性的观点,但我不同意这样的事实,即它会降低可读性,IDE像Eclipse格式变量一样根据类型的不同而不同,并且通过良好的类和方法设计可以避免此问题。
您是否有任何观点,论点或研究支持我的观点(或反对)?
我正在与高级开发人员讨论编码约定,以适用于我们的项目(主要是Java / JEE项目)。我不同意他提出的一项约定:
实例变量名称应以“ _”开头,局部变量应以“ loc”开头,方法参数应以“ par”开头,因此很容易识别变量的来源和范围。
尽管他提出了关于短期内存和可读性的观点,但我不同意这样的事实,即它会降低可读性,IDE像Eclipse格式变量一样根据类型的不同而不同,并且通过良好的类和方法设计可以避免此问题。
您是否有任何观点,论点或研究支持我的观点(或反对)?
Answers:
正如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;
}
}
此外,人们很快学会了忽略前缀(或后缀)来查看名称的有意义部分。我们读的代码越多,我们看到的前缀就越少。最终,前缀变得杂乱无章,成为旧代码的标记。
这是一个老问题,但是我还是要在这里发布。我有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
参数吗?这是有关如何命名变量的简单建议:
HOST_NAME
)。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:易于阅读,不需要读者在学习之前先了解所有内容。
这很大程度上是一个偏好问题,因此没有“正确”的答案。因此,这个问题实际上可能是封闭的。但是在此之前,让我告诉您我完全同意您的观点。就我而言,前缀会降低可见性。更不用说如果有前缀的话,就应该将它们用于更有用的东西,例如匈牙利符号的初衷,而不是用于IDE可以突出显示的东西。
我将SentenceCase用于实例数据(无论是变量还是常量),并将lower_case用于参数和局部变量,因为两者之间的差异实际上很小(如果有的话)。我从来没有使用过headlessCamelCase,因为它很:脚:单组件标识符看起来像小写字母,即使原本打算是headlessCamelCase也是如此。