2장에서는 의미있는 이름에 대해서 다룬다.
우리는 변수, 함수, 인수, 클래스, 패키지, 소스파일, 디렉토리, war, jar 등 많은 곳에 이름을 붙인다. 이름을 잘 지으면 여러모로 편하다는 것과 몇가지 규칙을 소개하고 있다.
의도가 분명한 이름을 지으면 절약하는 시간이 많아질것이고 자신을 포함한 코드를 읽는 사람이 행복해 질것이라고 말하고 있다.
변수, 함수, 클래스 등의 이름은 다음과 같은 굵직한 질문에 모두 답할 수 있어야한다.
따로 주석이 필요하다면 의도를 분명히 드러내지 못한 것이다.
d 자체는 아무런 의미가 드러나지 않는다.
int d; // 경과 시간(단위: 날짜)
의도가 분명해 보인다.
int elapsedTimeDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays
코드 맥락이 코드 자체에 명시적으로 드러나지 않는다. 이 코드는 코드를 읽는 사람이 다음과 같은 정보를 안다고 가정해야지 코드의 의도를 알 수 있다.
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
코드의 단순성은 달라지지 않았지만 의미가 명확해졌다.
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if(cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
그릇된 단서는 코드 의미를 흐리고 나름 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용해서도 안된다.
ex - hp, aix, sco (hp는 유닉스 플랫폼이나 유닉스 변종을 가리키는 이름이기 때문)
직각 삼각형의 빗변(hypotenuse)을 hp와 같은 약어를 사용하는 것은 위와 같은 의미와 혼동되기 때문에 적합하지 않다.
프로그래머에게 List라는 단어는 특수한 의미다. accountList의 자료형(컨테이너)가 List가 아니라면 적합하지 않다. accounts, accountGroup, bunchOfAccounts가 적합하다.
A모듈에서 XYZControllerForEfficientHandlingOfStrings라는 이름을 사용하고
B모듈에서 XYZControllerForEfficientStorageOfStrings라는 이름을 사용한다면 차이가 모호해 알아챌 수가 없다.
소문자 l은 숫자 1처럼 보이고 대문자 O는 숫자 0처럼 보인다.
글꼴을 바꿔 해결할 수도 있겠지만 그것보다는 이름만 바꾸면 해결된다.
연속된 숫자를 덧붙이거나 불용어를 추가하는 방식은 적절하지 못하다.
s1을 source, a2를 destination으로만 고쳐도 더 읽기 좋은 코드가 된다.
public static void copychars(char a1[], char a2[]) {
for (int i = 0; i < a1.length; i++) {
a2[i] = a1[i];
}
}
모두 정확히 구분이 가지 않는다. 읽는 사람이 차이를 알도록 지어야한다.
genymdhms(generate date, year, month, day, hour, minute, second)와 같은 단어를
"젠 와이 엠 디 에이취 엠 에스"라고 발음하는 것은 적합하지 않다.
genymdhms는 generationTimeStamp
modymdhms는 modificationTimeStamp
pszqint는 recordId 등으로 변경하는것이 좋다.
문자 하나를 사용하는 이름과 상수는 텍스트 코드에서 쉽게 눈에 띄지 않는다.
MAX_CLASSES_PER_STUDENT는 쉽게 찾을 수 있지만 숫자 7은 찾기 어렵다.
필자는 이름 길이는 범위 크기에 비례해야한다고 주장한다. 변수나 상수를 코드 여러 곳에서 사용한다면 검색하기 쉬운 이름이 바람직하다.
문제 해결에 집중하는 개발자에게 인코딩은 불필요한 부담이고 발음하기 어려우며 오타가 발생하기 쉬우므로 피해야한다.
'r' 이라는 변수가 " 호스트와 프로토콜을 제외한 소문자 URL" 이라는 의미이며 이와 비슷한 맥락의 수많은 변수를 모두 기억할 수 있겠는가? 적절하지 않다.
클래스 이름과 객체 이름은 명사나 명사구가 적합하다.
동사나 동사구가 적합하다.
Complex fulcrumPoint Complex.FromRealNumber(23.0); // O
Complex fulcrumPoint = new Complex(23.0) // △
재미난 이름, 특정 문화에서만 사용하는 농담, 구어체, 속어 등은 피하는게 좋다.
똑같은 메서드를 클래스마다 fetch, retrieve, get으로 제각각 부르면 혼란스럽다.
controller, manager, driver도 마찬가지다. 이름이 다르면 클래스도 다르고 타입도 다르다고 생각하기 마련이다.
코드를 읽을 사람도 프로그래머다. 전산 용어, 알고리즘 이름, 패턴 이름, 수학 용어 등을 사용해도 괜찮다.
기술 개념에는 기술 이름이 가장 적합한 선택이다.
적절한 '프로그램 용어'가 없다면 문제 영역에서 이름을 가져온다.
문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져와야 한다.
대다수의 이름은 스스로의 의미가 분명하지 않다. 그러므로 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다. 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.
private void printGuessStatistics(char candidate, int count)
{
String number;
String verb;
String pluralModifier;
if (count == 0) {
number = "no";
verb = "are";
pluralModifier = "s";
} else if (count == 1) {
number = "1";
verb = "is";
pluralModifier = "";
} else {
number = Integer.toString(count);
verb = "are";
pluralModifier = "s";
}
String guessMessage = String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
print(guessMessage);
}
Gas Station Deluxe 라는 애플리케이션을 짠다고 가정할때 모든 클래스의 이름이 GSD로 시작하는것은 옳지않다. MailingAddress 클래스를 추가하면서 GSDAccountAddress로 이름을 바꿨다고 했을 때 다른 고객 관리 프로그램에서 고객 주소가 필요하다면 GSDAccountAddress의 이름으로 가져다 쓰는건 적합하지 않다.