이름을 잘 짓는 몇 가지 규칙을 알아보자.
- 변수나 함수 그리고 클래스의 이름은 다음의 질문에 모두 답해야 한다.
- 변수(혹은 함수나 클래스)의 존재 이유는?
- 수행 기능은?
- 사용 방법은?
const getThem = () => {
const list1 = [];
for (const x of theList) {
if (x[0] === 4) list1.push(x);
}
return list1;
};
도당체 먼코든지 알아보기가 힘들다
const getFlaggedCells = () => {
const flaggedCells = [];
for (const cell of gameBoard) {
if (cell[STATUS_VALUE] === FLAGGED) flaggedCells.push(cell);
}
return flaggedCells;
};
네이밍을 통해 최소한의 유추를 할 수 있다.
-
여러 계정을 그룹으로 묶을 때, 실제
List
형이 아니라면accountList
라 명명하면 안된다.List
자료형이라 오해할 수 있음.accountGroup
등으로 하자.
-
서로 흡사한 이름을 사용하지 않는다.
XYZControllerForEfficientHandlingOfStrings
XYZControllerForEfficientStorageOfStrings
- WTF?
-
유사한 개념은 유사한 표기법을 사용한다.
- '일관성'이 중요하다.
- 자동완성 기능에서 큰 이득을 볼 수 있음.
말도 안되는 단어(a1
) 혹은 클래스에 불용어를 붙이지 마라(Info
).
a1, a2, a3
PersonData
,PersonInfo
: 정확한 개념 구분이 되지 않음.Name
vsNameString
getActivateAccount()
vsgetActiveAccounts()
vsgetActiveAccountInfo()
- 이들이 혼재할 경우 서로의 역할을 구분하기 너무 어렵다.
money
vsmoneyAmount
message
vstheMessage
발음이 불편한 단어는 많은 회의에서 불편함을 준다.
// Bad
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
/* ... */
};
// Good
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId = "102";
/* ... */
};
어떠한 상수 값 7
을 사용하는 코드에서 오류가 있을 때 7
을 검색하는 것은 너무 큰 고역이다.
MAX_CLASSES_PER_STUDENT
와 같이 숫자의 의미를 알려주고 검색을 쉽게 하라.
이때 변수의 이름 길이는 범위 크기에 비례해야 한다.(로컬 < 함수 < 글로벌)
변수에 부가 정보를 덧붙여 표기하지 마라.
PhoneNumber phoneString;
타입 시스템에서 의미없는 정보이다. 예전에는 컴파일러가 타입을 점검하지 않아 헝가리언 표기법
으로 타입을 기억할 단서가 필요했다. 하지만 요즘은 컴파일러가 타입을 기억하고 강제한다.
m_dsc
와 같이 접두사를 붙일 필요가 없다. 코드를 읽을수록 접두어는 관심 밖으로 밀려난다. 클래스와 함수는 접두어가 필요없을 정도로 작아야 한다.(기능의 분리) 또한 IDE 차원에서 변수들의 색상을 보여주므로 구분자를 사용하지 않는 것이 좋다.
인터페이스 클래스와 구현 클래스가 나뉜다면 구현 클래스의 이름에 정보를 인코딩 하라.
IShapeFactory
와 ShapeFactory
로 나누어서 사용하는 것이 좋을까?
- 저자는 인터페이스 이름은 접두어를 붙이지 않는 편이 좋다고 생각한다.
- 클래스가 인터페이스라는 사실을 굳이 알리고 싶지 않다.
구분 | Interface Class | Concrete(Implementation) Class |
---|---|---|
Don't | IShapeFactory | ShapeFactory |
Do | ShapeFactory | ShapeFactoryImp |
아주 작은 범위의 루프에서 i,j,k
는 보편적 합의로 괜찮다.(하지만 l
은 NO)
똑똑한 프로그래머는 r
이라는 변수가 호스트와 프로토콜을 제외한 소문자 URL 이라는 것을 안다. 하지만 전문가 프로그래머는 명료함이 최고라는 사실을 이해한다.
즉 자신이 아는 용어/단어보단 보편적 단어로 남들이 이해하는 코드를 작성하는 것이 중요하다.
클래스 이름과 객체 이름은 명사나 명사구가 적합하다. 동사는 사용하지 않는다.
- Good:
Customer
,WikiPage
,Account
- Bad:
Data
,Info
동사 혹은 동사구를 사용한다.
- Good:
postPayment
,deletePage
접근자, 변경자, 조건자는 javabean
표준에 따라 get, set, is
를 붙인다.
- Good:
isPosted
,getName
생성자를 오버로드 할 경우 정적 팩토리 메서드를 사용한다. 이때 메서드는 인수를 설명하는 이름을 사용한다. 생성자를 제한하려면 생성자를 private
으로 선언한다.
- Good:
Complex fulcrumPoint = Complex.fromRealNumber(23.0)
- Bad:
Complex fulcrumPoint = new Complex(23.0)
보편적 언어로 대화하라
똑같은 메서드를 클래스마다 fetch
, get
, retrieve
로 나누어 부르면 혼란스럽다.
조금 더 넓은 범위로 동일 코드 기반에서 controller
, manager
, driver
를 섞어 쓰지 말자. DeviceManager
와 ProtocolController
는 근본적으로 어떻게 다른가?
이름이 다르면 당연히 클래스와 타입도 다르다 생각하게 된다.
바로 위에서 설명한 '한 개념에 한 단어'를 따르기 위해 같은 맥락이 아님에도 '일관성'을 고려해 작성할 경우 혼란이 생긴다. 명확히 구분하라.
// case 1
const add = (n: number, m: number): number => n + m;
const sum = add(3, 4);
// case 2
const list = [];
const add = (n: number) => list.push(n);
add(3);
case1
과 case2
는 '다르다'. case2
의 경우 insert
로 표현하라.
개발자라면 당연히 알고 있는 JobQueue
등과 같은 전산용어, 알고리즘 이름, 수학 용어 등은 적극 사용하자.(커뮤니케이션 비용을 오히려 줄임)
위의 해법영역에서 해결되지 않는다면(적절한 프로그래머 용어가 없다면) 해당 문제 영역의 용어를 사용한다.
우수한 설계자는 해법 영역과 문제 영역을 구분할 줄 알아야 한다.
클래스, 함수, namespace 등으로 감싸 맥락을 표현한다. 그럼에도 불분명 하다면 접두어를 붙인다.
// Bad
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);
}
함수를 처음부터 끝까지 다 읽어야 이해가 가능하다.
// Good
public class GuessStatisticsMessage {
private String number;
private String verb;
private String pluralModifier;
public String make(char candidate, int count) {
createPluralDependentMessageParts(count);
return String.format("There %s %s %s%s", verb, number, candidate, pluralModifier );
}
private void createPluralDependentMessageParts(int count) {
if (count == 0) {
thereAreNoLetters();
} else if (count == 1) {
thereIsOneLetter();
} else {
thereAreManyLetters(count);
}
}
private void thereAreManyLetters(int count) {
number = Integer.toString(count);
verb = "are";
pluralModifier = "s";
}
private void thereIsOneLetter() {
number = "1";
verb = "is";
pluralModifier = "";
}
private void thereAreNoLetters() {
number = "no";
verb = "are";
pluralModifier = "s";
}
}
GSD
라는 어플리캐이션을 만들 때 GSDAccountAddress
와 같이 작성하면 너무 불필요한 단어가 많이 포함된다.
맥락이 잘 나누어져 있다면 Address
로 충분하다.
코드를 지적하는 것에 두려워 하지 말라. 서로의 시간은 소중하다.