의도를 분명하게 밝혀라
변수나 함수, 클래스명은 다음과 같은 굵직한 질문에 모두 답할 수 있어야 한다.
존재 이유는? 수행 기능은? 사용 방법은?
좋은 코드는 맥락이 드러나야 한다.
예를 들어 다음과 같은 코드가 존재한다. 무슨 의도인지 단번에 이해할 수 있는가?
public void change(List<Car> list) {
for (Car i : list) {
i.move(1);
}
}
좋은 코드는 아래와 같이 맥락이 잘 드러나야 한다.
public final int FORWARD = 1;
public void moveForward(List<Car> cars) {
for (Car car : cars) {
car.move(FORWARD);
}
}
그릇된 정보를 제공하지 마라
코드에서 그릇된 단서를 유추할 수 있도록 하지 마라. 즉, 본인만 알아볼 수 있는 (본인도 모를 수 있다) 표현을 지양해라.
예를 들어, 변수명에 자료형을 사용하는 것은 그릇된 정보를 제공하는 것의 한 예이다. 자료형은 특수한 의미를 가진다. 이름에 자료형이 들어가는 경우 이후 구현이 바뀌었을 때 그릇된 정보를 제공할 수 있다.
List<Car> carList = new ArrayList<>();
// 만약 이후 구현이 바뀌어 car가 중복되지 않는 조건이 추가되었다면?
HashSet<Car> carList = new HashSet<>();
// 위 코드는 그릇된 정보를 내포한다.
마찬가지로 비슷한 이름을 사용하지 마라. 이름마다 고유하게 인식할 수 있도록 영역을 보장해라.
의미 있게 구분해라
a1, a2, a3... 이런 이름은 사용하지 마라. 아무런 정보도 내포하지 않는다. 단, for문에서 관행적으로 사용되는 i 라는 변수는 예외일 수 있다. 그러나 일반적으로 대부분의 경우에서는 의미를 내포하지 않기에, 사용하지 않아야 한다.
또한, 불용어를 사용하지 마라.
stopwords 또는 불용어 란, 우리가 언어를 분석할 때, 의미가 있는 단어와, 의미가 없는 단어나 조사 등이 있다. 이렇게 의미가 없는 것들을 불용어라고 한다.
a, the, data, info 등을 이름이 넣고 싶다면, 이것이 정말 명확한 의미를 제공해주는지, 이것이 없다면 객체의 의미가 손상되는지 확인해라. 그런 경우라면 앞서 이야기한 것들을 사용해도 좋다. 무조건적으로 사용하지 말라는 것이 아니다. 요지는 개념을 구분하지 못한 채 이름만 달리하는 경우를 방지하자는 것.
다음은 의미있게 구분하지 못한 대표적인 예시이다.
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
// 차이점을 알 수 없다. 의미 있게 구분하라.
발음하기 쉬운 이름을 사용하라
좋은 이름이란 발음하기도 좋아야 한다. 다른 개발자와 "asdsbdh" 라는 변수에 대해 이야기하고자 한다면, 토의에 소요되는 오버헤드가 쓸데 없이 클 것이다.
검색하기 쉬운 이름을 사용하라
이름은 검색하기 쉬워야 한다. 즉, 길수록 좋다. 짧은 이름일수록 여러 군데에서 등장할 가능성이 높다. 예를 들어 a, b 와 같은 경우를 이름으로 사용하는 경우가 이렇다. IDE에서 a 라는 변수를 찾고 싶다면, 어떻게 찾을 것인가? 몇백개의 a가 검색 결과로 등장할 것이다.
무분별한 인코딩을 피하라
유형이나 범위 정보를 이름에 인코딩하지 마라. 여기서 인코딩이라는 의미는, 정보를 새겨넣는다는 것을 의미한다. 앞서 언급한 예시이지만, carList와 같이 자료형이 이름에 들어가는 경우가 그렇다. 불필요한 정보를 제공하지 마라. 오도할 가능성만 커진다.
인터페이스와 구현 클래스가 이름이 같아지는 경우, 구현 클래스에 인코딩해라. 인터페이스에 I 등의 접두사를 붙이는 건 과도한 정보를 제공한다. 차라리 구현 클래스의 이름에 Imp 와 같은 접미사를 붙여라.
클래스 이름
클래스 이름은 명사나 명사구가 적합하다. 동사는 사용하지 않는다. 마찬가지로 클래스명에 불용어가 들어가는 건 피하도록 한다.
Customer, WikiPage, Account, AddressParser (좋은 예)
Manager, Processor, Data, Info (나쁜 예)
메서드 이름
메서드 이름은 동사나 동사구가 적합하다. 또한 접근자(Accessor), 변경자(Mutator), 조건자(Predicate)는 javabean 표준에 따라 값 앞에 get, set, is 를 붙인다.
// 좋은 예, bean 표준 역시 따르고 있다.
string name = employee.getName();
customer.setName("Mike");
if (paycheck.isPosted()) {
...
}
한 개념에 한 단어를 사용해라
추상적인 개념 하나마다 단어 하나를 선택해 이를 고수한다. 똑같은 메소드를 fetch, retrieve, get 등으로 부르지 않는다. 독자적이고 일관적으로 이름을 작성하라. 마찬가지로 controller, manager 등도 혼란스러움을 야기할 수 있는 대표적인 예시이다.
다만 주의해야 할 것은,
계산기 객체에서 제공하는 덧셈 기능은 add라고 정했다면, 리스트에 값을 넣는 기능을 add라고 해서는 안된다. insert나 append라고 부르자. 한 개념에 한 단어를 사용하는 것이지, 개념이 분리될 수 있다면 같은 단어로 사용하면 안된다.
해법 영역에서 이름을 가져와 사용해라
코드를 읽는 사람도 프로그래머다. 전산 용어, 알고리즘 이론, 패턴 이름 등을 사용해도 괜찮다. 모든 이름을 도메인 영역에서 가져올 필요는 없다.
문제 영역에서 이름을 가져와 사용해라
적절한 '프로그래밍 용어'가 없다면 문제 영역에서 이름을 가져온다. 그러면 코드를 보수하는 프로그래머가 분야 전문가에게 의미를 물어 파악할 수 있다.
의미 있는 맥락을 추가해라
클래스, 함수, 네임스페이스에 맥락을 부여해라. 모든 방법이 실패하면 마지막 방법으로 접두어를 붙인다.
firstName, lastName, street, city, state
// 위 그룹은 주소를 구성한다는 것을 짐작할 수 있다.
// 그러나 특정 요소만 하나 뽑아놓고 보면, 주소라는 것을 알지 못한다.
addrFirstName, addrLastName, addrStreet ...
// 위처럼 맥락을 부여해라.
불필요한 맥락을 없애라
앞서 긴 이름이 의미를 명확하게 한다고 이야기했다. 그러나 사실은 짧은 이름이 긴 이름보다 좋다. 단, 의미가 명확한 경우에 한해서다.
따라서 긴 이름이 좋다는 맹목적인 판단 아래, 이름에 불필요한 맥락을 추가하지 않도록 한다.
accountAddress는 Address의 인스턴스 이름으로는 훌륭하다. 단, accountAddress는 클래스 이름으로는 적합하지 못하다. Address가 적합하다. 불필요한 의미를 제거해라.
'클린 코드' 카테고리의 다른 글
[클린 코드] 7장: 오류 처리 (0) | 2022.12.02 |
---|---|
[클린 코드] 6장: 객체와 자료 구조 (0) | 2022.11.29 |
[클린 코드] 5장: 형식 맞추기 (0) | 2022.11.29 |
[클린 코드] 4장: 주석 (0) | 2022.11.28 |
[클린 코드] 3장: 함수 (0) | 2022.11.27 |