Konwencje nazewnictwa, na przykład zmienne lokalne i parametryczne [zamknięte]


13

Rozmawiałem ze starszymi programistami o konwencjach programistycznych dotyczących naszych projektów (głównie projektów Java / JEE). Nie zgodziłem się z jedną konwencją, którą zaproponował:

Nazwy zmiennych instancji powinny zaczynać się od „_”, zmienne lokalne - „loc”, a parametry metody - „par”, aby łatwo było ustalić pochodzenie i zakres zmiennej.

Chociaż przedstawił argumenty za pamięcią krótkotrwałą i czytelnością, nie zgodziłem się z tym, że raczej zmniejsza ona czytelność, IDE, takie jak zmienne formatu Eclipse, różnią się w zależności od ich typu, a tego problemu można by uniknąć dzięki dobrej konstrukcji klasy i metody.

Czy masz jakieś opinie, argumenty lub analizy, które potwierdzają moją tezę (lub ją sprzeciwiają)?


Mówisz, że nie zgadzasz się z „faktem, że raczej zmniejsza to czytelność”. Nie twierdzę, że się mylisz, ale jakie dowody przedstawiłeś na poparcie tego roszczenia? Nie znam żadnych badań wskazujących, że zmniejszy to czytelność (zanim zostałem programistą, studiowałem psychologię na studiach psychologicznych na studiach podyplomowych, więc jest to obszar, który mnie interesuje.)
AdamJonR

Miałem na myśli to, że jest zagracone. Ale nie mam żadnych dowodów poza moją osobistą opinią
HH

Przedrostki duplikują informacje, które są już zawarte w kodzie i wyświetlane w dowolnym środowisku na wpół przyzwoitym. Jak wszyscy wiemy, zduplikowane informacje mogą stać się niespójne. DRY powinno wskazywać, że nie używasz prefiksów.
Julia Hayward

Odpowiedzi:


15

Jak mówi Wikipedia na ten temat - Zasady nazywania java,

Zmienne lokalne, zmienne instancji i zmienne klas są również zapisywane w lowerCamelCase. Nazwy zmiennych nie powinny zaczynać się od znaku podkreślenia (_) lub znaku dolara ($), nawet jeśli oba są dozwolone. Niektóre konwencje kodowania stanowią, że do prefiksu wszystkich zmiennych instancji należy użyć podkreślników, aby poprawić czytanie i rozumieć program.

Zgodnie z moim doświadczeniem ze standardami kodowania, nazwy zmiennych Instance zaczynające się od „_” nie są zbyt dobre, jak mówią standardy wikipedia.

zmienne lokalne z „loc”, a parametry metody z „par”, jak powiedziałeś, łatwo byłoby zidentyfikować zmienne źródło i zakres, ale powinno to być dla ciebie, a nie dla innych programistów, którzy pewnego dnia mogą przeglądać kod w celu konserwacji .

Zgodnie ze specyfikacją Clean Code dotyczącą metod, powinny one być możliwie krótkie, aby można było je odczytać, a nazwy zmiennych nie powinny być odwzorowywane w myślach, powinny być odpowiednie dla operacji wykonywanej przez tę metodę.

Prefiksy elementów / zakresów, nie musisz już prefiksować zmiennych elementów za pomocą m_. Twoje klasy i funkcje powinny być na tyle małe, że ich nie potrzebujesz. Powinieneś używać środowiska edycyjnego, które wyróżnia lub koloruje członków, aby je wyróżnić.

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

Poza tym ludzie szybko uczą się ignorować prefiks (lub sufiks), aby zobaczyć znaczącą część nazwy. Im więcej czytamy kod, tym mniej widzimy prefiksów. W końcu prefiksy stają się niewidzialnym bałaganem i znacznikiem starszego kodu.


4

To stare pytanie, ale i tak zamierzam tutaj napisać. Mam ponad 20 lat programowania i radzenia sobie z kodem innych osób.

Myślę, że nazywanie twojej zmiennej krótkim wskazaniem co do jej zakresu jest naprawdę przydatne dla następnej osoby (lub ciebie), która spojrzy na twój kod.

Jeszcze nie patrzy się na kod w IDE z ładnymi kolorami (i nie pamiętam, co oznaczają kolory, a różne IDE pokazują różne kolory itp.).

To prawda, że ​​metody powinny być wystarczająco krótkie, aby nie było załadowane tonami zmiennych i tonami kodu, ale nawet na jednym krótkim - kiedy spojrzysz na kod, który jest zupełnie nieznany, czasami trudno jest stwierdzić, czy zmienna jest zmienną klasową, lokalną zmienna lub parametr metody.

Umiejętność odróżnienia na pierwszy rzut oka ułatwia zapoznanie się z nieznanym kodem.

Weź ten przykład:

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

Teraz czas i spójrz na kod (wyodrębniony z ElasticsearchTemplate z projektu spring-data-elasticsearch - kod, który sprawdzałem, co skłoniło mnie do wyszukiwania w Google tego, co ludzie mówią o konwencjach nazewnictwa).

  • Jaki jest tryb resultsMapper?
  • Czy requestBuildingparametr?
  • itp...

Oto moja prosta sugestia, jak należy nazywać zmienne:

  • Atrybuty statyczne klasy (tj. Stałe): ALL_CAPS_WITH_UNDERSCORES (np HOST_NAME.).
  • Atrybuty klas (tj. Zmienne instancji klasy): camelCase (np resultsMapper.).
  • Parametry metody: prefiksem a(np aQuery, aClazz).
  • Zmienne lokalne: prefiksem my(np myIndexName, myType).

Powyższy kod staje się:

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

}

Czy to jest idealne? Nie wydaje mi się Ale powyższe, jeśli chodzi o zmienne, jest teraz łatwiejsze do odczytania. Są inne rzeczy, takie jak wyrównanie i odstępy, do których nie wchodzę w tę odpowiedź, ponieważ nie jest to związane z pytaniem, co ułatwiłoby również czytanie.

Nie lubisz Camel Case? Dobrze, użyj podkreślników itp., Ale poprzedź lokalne zmienne i parametry, aby różniły się od zmiennych instancji klasy.

Nie lubisz ai my- dobrze, po prostu bądź konsekwentny w swoim projekcie i używaj czegoś innego ... ale używaj czegoś.

Zasada nr 1: spójność w ramach projektu.

Zasada nr 2: ułatw czytanie i nie wymagaj od czytelnika, aby wiedział wszystko, zanim będzie mógł się uczyć.


3

Jest to w dużej mierze kwestia preferencji i jako taka nie ma „poprawnej” odpowiedzi. To pytanie może więc zostać zamknięte. Ale zanim to nastąpi, pozwól mi powiedzieć, że całkowicie się z tobą zgadzam. Prefiksy zmniejszają widoczność, jeśli o mnie chodzi. Nie mówiąc już o tym, że jeśli mają być jakieś prefiksy, należy ich używać do bardziej użytecznych rzeczy, takich jak pierwotna intencja notacji węgierskiej , a nie do rzeczy, które IDE może zapewnić wyróżnianie.

Korzystam z SentenceCase na przykład danych (zmiennych lub stałych) i small_case dla parametrów i zmiennych lokalnych, ponieważ naprawdę jest bardzo niewielka, jeśli w ogóle, różnica między nimi. Nigdy, przenigdy nie używam headlessCamelCase, ponieważ jest kiepski : identyfikator jednoskładnikowy wygląda jak małe litery, nawet jeśli miał być bezgłowyCamelCase.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.