의미있는 이름
목차
- 의도를 분명히 밝혀라
- 그릇된 정보를 피하라
- 의미 있게 구분하라
- 발음하기 쉬운 이름을 사용하라
- 검색하기 쉬운 이름을 사용하라
- 인코딩을 피하라
- 자신의 기억력을 자랑하지 마라
- 클래스 이름
- 메서드 이름
- 기발한 이름은 피하라
- 한 개념에 한 단어를 사용하라
- 말장난을 하지마라
- 해법 영역에서 가져온 이름을 사용하라
- 문제 영역에서 가져온 이름을 사용하라
- 의미 있는 맥락을 추가하라
- 불필요한 맥락을 없애라
의도를 분명히 밝혀라
이름을 지을 때 아래의 질문들을 고려해야 한다.
- 변수(혹은 함수나 클래스)의 존재 이유는?
- 수행 기능은?
- 사용 방법은?
Bad
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
복잡한 코드는 아니지만 해당 메서드가 무엇을(them) 가져오는 것인지, List에 담기는 int[] 배열은 무슨 데이터인지, 4는 무슨 의미를 가지는지를 알 수 없다. 이 말은 곧 각 변수들의 정보를 모르는 경우 코드의 맥락을 완전히 이해 할 수 없다는 뜻이다.
각 변수들의 정보를 모르더라도 이해할 수 있도록 아래와 같이 수정할 수 있다.
Good
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
그릇된 정보를 피하라
- 약어를 지양하자
- 여러 계정을 그룹으로 묶을 때 List와 같은 특정 컨테이너의 사용을 지양하라 (e.g., accountList -> Accounts)
- 네이밍은 서로 비슷한 이름을 사용하지 말자
- 유사한 개념은 유사한 표기법을 사용하자, 일관성이 떨어지는 표기법은 그릇된 정보이다.
- 다른 글자와 혼동되는 단일 알파벳을 피하자 (e.g., 소문자 L <-> 1, 대문자 I)
의미 있게 구분하라
한 scope에서 동일 이름을 사용할 수 없으니 컴파일러를 통과하기 위한 무의미한 철자 변경의 오류를 범하지 않도록 해야 한다. 무의미한 철자 변경의 대표적인 두가지 예시는 아래와 같다.
-
연속된 숫자를 덧붙이기
Bad :public static void copyChars(char a1[], char a2[])
Good :
public static void copyChars(char souce[], char destination[])
-
불용어(noise word) 추가
불용어란? 없어도 의미 전달에 영향이 없는 단어- 접두어 사용을 조심하자
a, an, the와 같은 접두어는 의미가 분명히 다를 때만 사용하도록 한다. (e.g., 모든 지역변수는 a 접두사 사용, 모든 함수 인수는 the 접두사 사용) - 불용어를 사용하여 중복을 발생시키지 말자
product라는 클래스가 존재 할 때 ProductInfo, ProductData와 같은 개념이 구분되지 않는 클래스를 생성하여 중복을 발생시키지 않도록 한다. (e.g., Money & MoneyAccaount, CustomerInfo & Customer, AccountData & Account)
- 접두어 사용을 조심하자
발음하기 쉬운 이름을 사용하라
발음하기 어려운 단어는 커뮤니케이션에도 영향을 끼친다. 이는 실제 존재하는 단어를 사용하는 것만으로도 해결이 된다.
Bad :
아 래의 변수는 generate date, year, month, day, hour, minute, second 의 줄임말이다.
Date genymdhms
Good :
Date generationTimetamp
검색하기 쉬운 이름을 사용하라
-
상수
상수값에 버그가 있을 경우 검색으로 찾아낼 수 없다. 그러나 상수값의 의미를 나타내는 변수로 정의하여 사용하면 검색에 용의하다. -
변수
알파벳 하나를 변수로 사용하면 검색이 어렵다.
Bad :
int s = 0;
for (int i = 0; i < 30; i++)
s += i * 4;
Good :
int maxIndex = 30;
const int MULTIPLICATION_CONDITION = 4;
int sum = 0;
for (int i = 0; i < maxIndex; i++) // 하나의 메서드에서만 쓰이며, 다시 쓰이지 않는다면 한 문자 변수도 나쁘지 않다
sum += i * MULTIPLICATION_CONDITION;
인코딩을 피하라
-
헝가리식 표기법을 지양하라
과거 프로그래밍 언어는 변수 및 함수의 인자 이름 앞에 데이터 타입을 명시하는 헝가리식 표기법을 사용하였으나 현대의 프로그래밍 언어는 많은 컴파일러가 타입을 기억하고 강제하므로 네이밍 시 타입을 직접 명시하는 것을 피하는 것이 좋다. 오히려 아래와 같은 문제가 발생 할 수 있다.PhoneNumber phoneString; // 이러한 경우 타입이 바뀌게 되었을 때 변수명도 바꿔주어야 하는 문제가 생긴다.
-
멤버 변수 접두어
멤버 변수임을 명시하기 위해 "m_" 접두어를 붙이는 것을 지양하고 클래승와 함수는 접두어가 필요없을 정도로 작게 구현해야 한다. -
인코딩이 필요한 경우?
Abstract Factory를 구현하는 경우, 인터페이스 클래스 이름보다는 구현 클래스의 이름을 인코딩 하는 것이 좋다.
Bad :public interface IShapeFactory; // 인터페이스 클래스 public class ShapeFactory; // 구현 클래스
Good :
public interface ShapeFactory; // 인터페이스 클래스 public class ShapeFactoryImp; // 구현 클래스 public class CShapeFactory; // 구현 클래스
자신의 기억력을 자랑하지 마라
- 하나의 문자만 사용하는 것을 지양하라
- 루프에서 반복 횟수 변수는 전통적으로 한 글자만을 사용
보통 i, j, k를 사용 (소문자 l은 대문자 I와 헷갈리므로 절대 안됨!) - 이외에는 대부분 적절하지 않다
- 루프에서 반복 횟수 변수는 전통적으로 한 글자만을 사용
- 나만 이해할 수 있는 변수명이 아닌 모두가 이해할 수 있는 명료한 네이밍을 지향하자
클래스 이름
- 동사가 들어가지 않는 명사/명사구가 적합하다.
- 불용어를 지양하자 (e.g., Manager, Processor, Data, Info)
Good :
public class Customer
public class WikiPage
public class AddressParser
메서드 이름
-
동사/동사구가 적합하다.
-
접근자(Accessor), 변경자(Mutator), 조건자(Predicate)는 javabean 표준에 따라 get, set, is를 붙인다.
e.g.,String name = employee.getName(); customer.setName("mike"); if (paycheck.isPosted());
-
생성자의 중복정의 시 정적 팩토리 메서드를 사용한다. (이때, 생성자 사용을 제한하려면 해당 생성자를 private으로 사용한다.)
- 해당 내용의 상세한 특징은 Effective Java 3/E 기준 Item1을 참고한다.
Bad :
Complex fulcrumPoint = new Complex(23.0);
Good :
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
기발한 이름은 피하라
- 특정 문화, 배경지식이 있어야 이해할 수 있는 이름이 아닌 명료한 이름을 선택하여 의도를 분명하고 솔직하게 표현하라
한 개념에 한 단어를 사용하라
- 똑같은 기능을 하는 메서드는 모든 클래스에서 하나의 이름으로 통일한다.
(e.g., 각 클래스마다 fetch, retrieve, get으로 다르게 구현하지 않도록 한다.) - 주석이 필요하지 않도록 메서드 이름은 독자적이고, 일관적이어야 한다.
- 동일 layer의 클래스는 하나의 이름으로 통일한다.
(e.g., 하나의 프로젝트에서 DeviceManager, ProtocolController와 같이 같은 의미지만 다른 단어의 혼용을 피한다.)
말장난을 하지마라
- 한 개념에 한 단어를 사용하라 규칙을 따르되, 일관성을 고려한다.
- 같은 맥락일때만 같은 이름을 사용하여 코드 내용을 확인하지 않아도 기능이 보장되도록 해야 한다.
해법 영역에서 가져온 이름을 사용하라
- 모든 이름에 도메인 영역의 단어를 사용하지 않는다. 기술 개념에는 기술 이름이 가장 적합한 선택이다. (e.g., JobQueue, AccountVisitor)
문제 영역에서 가져온 이름을 사용하라
- 적절한 기술 이름이 없는 경우 또는 도메인 영역과 관련이 깊은 코드에 도메인 영역의 이름을 사용한다.
- 우수한 프로그래머라면, 해법(기술) 영역과 문제(도메인) 영역을 구분할 줄 알고 각 영역에 알맞은 네이밍을 정해야 한다.
의미 있는 맥락을 추가하라
- 네이밍은 독자적으로 문맥을 가지기 보단 클래스, 메서드, name space의 위치에 따라 맥락을 부여한다.
- 접두어는 최후의 수단으로 붙인다.
- 특정 문맥을 가지는 클래스를 생성하면 컴파일러에게도 문맥이 분명해진다.
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 maek(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() {
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";
}
}
불필요한 맥락을 없애라
-
모든 클래스를 아우르는 맥락을 굳이 접두어로 사용하지 않는다.
- IDE에서 해당 접두어를 입력하는 순간 수많은 클래스가 열거되어 정말 필요한 클래스를 찾기 어려워진다.
- 굳이 접두어를 붙임으로서 이름이 불필요하게 너무 길어진다. 긴 이름이 짧은 이름보다 좋지만 의미가 분명한 경우에 한해서이다.
Bad :
package com.gsd; public class GsdAccountAddress
Good :
package com.gsd; public class AccountAddress
- 클래스의 이름으로 좋은 것과 인스턴스의 이름으로 좋은 것은 다르다.
마치면서
좋은 이름을 선택한다는 것은 결국 가독성을 높이기 위한 것
참고하면 좋을 문서
'Dev > Books' 카테고리의 다른 글
[CleanCode] 7장. 예외 처리 (0) | 2020.05.16 |
---|---|
[CleanCode] 6장. 객체와 자료 구조 (0) | 2020.05.15 |
[CleanCode] 5장. 형식 맞추기 (0) | 2020.05.12 |
[CleanCode] 4장. 주석 (0) | 2020.05.12 |
[CleanCode] 3장. 함수 (0) | 2020.05.06 |