이름은 어디서든 쓰인다. 많이 사용하기 때문에 잘지으면 편하다. 몇 가지의 규칙을 알아보자.
말하기는 쉽지.. 어렵거든?
저자도 안다. 하지만 이 의도가 분명한 이름을 짓는 것은 정말로 중요하다. 결국 최종적으로 절약하는 시간이 더 많기 때문이다. 나 포함해 미래에 행복해진다. 주석이 필요하면 의도를 분명히 드러내지 못했다는 것이다.
//Bad
int d; // elapsed time in days
//Good
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
// Bad
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList) {
if (x[0] == 4) {
list1.add(x);
}
}
return list1;
}
// Good
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
for (int[] cell : gameBoard) {
if (cell[STATUS_VALUE] == FLAGGED) {
flaggedCells.add(cell);
}
}
return flaggedCells;
}
두 예시에서 핵심은, 나쁜 코드의 경우 독자에게 "가정"을 바라고 있다는 점에 있다. 좋은 코드의 경우 이름하나를 변경하게 됨으로써 어떤 의도인지 명확하게 드러난다.
accountList
: List? 자료구조가 List인건가?accountGroup
, bunchOfAccounts
, accounts
로 변경XYZControllerOfStrings
, XYZControllerOfContainerStrings
: 뭘 써야할지 헷갈리네..[a1, a2, …]
써야지book
이라는 변수가 있는데 이 이름을 쓰고 싶어. theBook
이렇게 하면 되겠지?Name
VS NameString
getActiveAccount()
VS getActiveAccounts()
VS getActiveAccountInfo()
money
VS moneyAmount
, message
VS theMessage
프로그래밍은 사회적 활동이다. 발음하기 쉬운 단어는 소통에 유용하다.
// 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";
/* ... */
};
아무래도 많은 의미를 담은 단어를 사용할수록 좋다. 위의 경우 뭐라고 하는지 알 수가 없다. 지적인 대화가 가능한가?
단일 문자, 숫자를 변수명으로 하지 마라.
일단 찾기 힘들다. 중복 처리되는 경우가 많아서 검색이 안된다. (숫자: 상수? 변수?) 오히려 긴 이름이 훨씬 좋다.
변수에 부가 정보를 더하지 마라.
m_property
, m_method
와 같은 식으로 할 필요가 없다.m_
은 지워버리고 읽어버린다.Do / Don't | Interface class | Concrete(Implementation) class |
---|---|---|
Don't | IShapeFactory | ShapeFactory |
Do | ShapeFactory | ShapeFactoryImp |
Do | ShapeFactory | CShapeFactory |
음 내 지적 능력을 과시해야 겠어. 아무도 모르게 변태같은 변수를 써야지.
c
독자가 머리속으로 한번 더 생각해 변환해야 할만한 변수명을 쓰지 말자. 전문가는 명료함을 기반으로 남들이 이해하는 코드를 내놓는다.
명사 혹은 명사구를 사용하라. 동사는 안된다.
Good | Bad |
---|---|
Customer , WikiPage , Account , AddressParser | Manager , Processor , Data , Info |
postPayment
, deletePayment
, deletePage
, save
// 첫번째 보다 두 번째 방법이 더 좋다.
Complex fulcrumPoint = new Complex(23.0);
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
특정 문화에서만 사용되는 재미있는 이름보다 의도를 분명히 표현하는 이름을 사용하자. 자칫하면 유머감각이 뛰어난 사람만 변수 의도를 파악할 수 있다.
HolyHandGrenade → DeleteItems
whack() → kill()
추상적인 개념 하나에 단어 하나를 사용하자.
fetch
, retrieve
, get
controller
, manager
, driver
도대체 무슨 차이지? 구분해서 작성한다면, 읽을 때, 차이점을 한번에 확인할 수 있다.
한 단어를 두 가지 목적으로 사용하지 말자.
public static String add(String message, String messageToAppend) // A + B의 의미
public List<Element> add(Element element) // 기존 것에 "추가"한다는 의미
의미론적으로 행동이 다른 상황이나, 일반적으로 부르는 이름이 같아 발생한 문제이다. 행위가 다르다면 다른 단어를 사용하는 것이 좋다. 위 경우 insert
, append
와 같은 단어를 사용하는 것이 좋겠다.
전산용어, 알고리즘 이름, 패턴 이름, 수학 용어 등은 사용하자.
개발자라면 당연히 알고 있을 JobQueue, AccountVisitor(Visitor pattern)등을 사용하지 않을 이유는 없다.
적절한 프로그래머 용어가 없거나 문제영역과 관련이 깊은 용어의 경우 문제 영역 용어를 사용하자.
우수한 프로그래머/설계자라면 해법 영역과 문제 영역을 구분할 수 있어야 한다. 그 중 어떤 것이 더 옳은 판단인지 결론을 내릴 수 있는 판단력을 가져야 한다.
클래스, 함수, namespace등으로 감싸서 맥락(Context)을 표현하라
그래도 불분명하다면 접두어를 사용하자.
// 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";
}
}
음, 이 A 프로젝트니까 Class 앞에 A를 달아서 관리하면 좋겠지?
응 큰일난다. IDE에서 A를 입력하자마자 관련된 모든 클래스를 열거하게 될 것이다. 그 뿐이 아니다. a처럼 접두어를 붙이는 것은 모듈의 재사용 관점에서도 좋지 못하다. 재사용하려면 이름을 바꿔야 한다. GSDAccountAddress 대신 Address로만 해도 충분하다. 어떻게 보면 필요없는 추가 단어가 들어가게 된 것이다.
쫄지말고 말하자.
좋은 이름은 여러 능력을 요구하는 일이다.
즉, 교육적인 측면이 가장 강하다. 이름을 바꾸지 않으려는 이유는 사회적 이유가 가장 크다. 다른 개발자가 반대할까봐. 하지만 오히려 반갑고 고마워해야 하는 것에 가깝다. 두려워하지 말고 서로의 명명을 지적하고 고치자. 그렇게 하면 이름을 외우는 것에 시간을 빼앗기지 않고 "자연스럽게 읽히는 코드"를 짜는 데에 더 집중할 수 있다.