클린코드2 -의미있는 이름
이름은 어디에서나 쓰이므로, 잘 짓으면 많은 도움이 될것.
1. 의도를 분명히 밝혀라
의도가 분명하게 이름을 짓는 것이 중요하다.
왜?
코드 이해와 변경이 쉬워지기 때문에
따로 주석이 필요한 경우는 의도전달이 부족했다는 뜻이라고 생각한다고 함.
int d // 경과 시간(단위 : 날짜)
int daysSinceCreation
코드의 이름에 의도가 없으면 코드의 맥락이 드러나지 않는다.
암묵적으로 독자가 특정 정보를 안다고 가정한다.
if(x[0] == 4)
list1.add(x);
return list1;
if(cell[STATUS_VALUE]==FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
위에만 보면 단순히 '4일때 리스트에 값을 넣는다' 이지만,
칸의 값이 깃발이 꽃혀있음(4) 라면
깃발이 꽃혀있는 칸 리스트에 추가한다
라는 코드로 변신한다.
이름만 고쳤음에도 코드가 좀더 이해하기 쉽다.
2. 그릇된 정보를 피하라
그릇된 단서는 지양하자.
널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하는 것도 지양하자.
- hp는 유닉스 플랫폼등을 가리키는 이름이라서 다른 의미로 사용해도 그릇된 정보를 제공할 수 있다.
- 여러 계정을 묶을때, 실제로 계정을 담는 컨테이너가 List가 아니라면 accountList 대신 Accounts를 쓰자. List는 프로그래머한테는 특수한 의미라서.
흡사한 이름도 지양하자. 둘의 차이를 알아채기 어려우므로.
- XYZHandlingOfStrings
- XYZStorageOfStrings
매우 안좋았던 예시
소문자 L이나 대문자 O 변수.
l은 숫자 1과 비슷하고 대문자 O는 숫자 0처럼 보여서 가독성이 최악.
3. 의미 있게 구분하라
지양해야 할 방식
- 연속된 숫자를 덧붙이는 방식
- 불용어를 추가하는 방식
- ProductInfo와 ProductData는 의미 차이가 불분명하다,
- moneyAmount와 money는 구분이 어렵다.
읽는 사람이 차이를 알도록 이름을 짓자.
불용어
사라져도 의미전달에 무리가 없는 단어
4. 발음하기 쉬운 이름 사용하기
왜 발음하기 쉬운 단어를 쓰는게 좋을까?
토론하기 좋으므로
사람들은 단어에 능숙하기 때문에.
Date genymdhms;
Date generationTimestamp;
위에는 발음하기도 힘들다보니 뇌에서 인식하기에도 시간도 걸리고 아쉬웠다.
5. 검색하기 쉬운 이름 사용하기
문자 하나만 사용하는 이름이나 그냥 상수는 왜 안좋을까?
- 검색이 너무 어려워지거나 못찾을 수도 있다.
- 설령 검색을 하더라도 상수의 경우 의미가 맞는지 분석해야 하는 비효율성이 존재한다.
int MAX_STUDENT = 7;
int i =7;
MAX_STUDENT는 검색도 쉽고 의미 파악도 쉽다.
6. 인코딩 피하기
인코딩언어는 익힐 필요까지는 없는 불필요한 정신적 부담. 오타생기기도 쉬움
1. 헝가리식 표기법
변수 및 함수의 인자 이름 앞에 데이터 타입을 명시하는 코딩규칙.
이게 있었던 이유는 초창기에서는 IDE가 타입을 점검하지 않았기 때문에
프로그래머가 타입을 기억할 단서가 필요했다고 한다.
지금은 너무나도 성능이 좋아졌기 때문에 불필요하다.
오히려 읽기 불편하고 쉽게 변수,함수, 클래스명을 바꾸기 어려워지는 단점이 있다.
PhoneNumber phoneString
2. 접두어
다른 타입 접두어 앞에 붙인다.
클래스의 멤버변수면 m_....
요새는 IDE 테마에서 변수등을 다른 색상으로 잘 표시해주고 있기 때문에 굳이 불필요한 접두어를
붙일 필요가 없다.(접미어도)
+저자는 개인적으로는 인코딩을 한다면 인터페이스 보다는 구현 클래스에 접두어,접미어를 붙이는걸 권장한다.
ex : ShapeFactoryImpl
7. 자신의 기억력을 자랑하지 마라
독자가 코드를 읽을때 변수 이름을 바로 이해할 수 있도록 짓자.
(문제영역이나 해법영역에서 사용되는 이름을 선택해보자.)
해법영역 : 전산 지식, 알고리즘, 디자인패턴 등
문제영역 : 도메인, 고객 요구사항, 비즈니스 로직
r이라는 변수가 url을 의미한다고 가정했을때, 본인은 기억한다고 자랑할 수 있겠지만,
다른 사람들은 그것의 의미를 모른다.(불필요하게 시간 소요됨)
전문가 프로그래머는 명료함이 최고라는 사실을 이해한다.
8. 클래스 이름
클래스의 이름은 동사나 불용어 보다는 명사나 명사구를 지향하자
ex : CUstomer, WikiPage 등등
왜그럴까?
보통 클래스는 상태(필드)와 행동(메서드)를 포함하는 개념적 단위로 사용된다.
명사는 객체의 책임과 역할을 표현하는데 더 직관적일 수 있다.
동사는 보통 행동의 역할을 표현하는데 사용되므로 상태까지 나타내기에는 애매하다고 생각한다.
9. 메서드 이름
동사나 동사구를 지향한다.
ex: save, delePage
접근자, 변경자, 조건자는 get, set, is를 앞에 붙인다.
생성자를 중복 정의할 때는(여러개 생성자를 정의하되 매개변수 목록이 서로 다른 경우) 정적 팩토리 메서드를 사용하자.
정적 팩토리 메서드 패턴
개발자 임의의 static method를 통해서 간접적으로 생성자를 호출하는 객체를 생성하는 패턴
왜 사용할까?
생성자의 역할 대신 뿐만 아니라 가독성 좋은 코드 작성 및 객체지향적 프로그래밍에 도움이 되서.
1. 생성 목적에 대한 이름표현이 된다. ( 생성자에 넘기는 매개변수 만으로는 반환될 객체의 특성을 표현하기 어려움.
그래서 메서드 네이밍을 정적 팩토리메서드를 통해 해준다면 반환될 객체특성 표현이 가능한 것.)
2. 인스턴스 생성을 통제할 수도 있다. ( 싱글톤 등)
3. 하위 자료형 객체를 반환할 수 있다. 메서드 호출을 통해 얻을 객체 인스턴스를 자유롭게 선택할 수 있는 것.
4. 캡슐화 가능. 내부 데이터 뿐만 아니라 구현체도 숨길 수 있어서.
💠 정적 팩토리 메서드 패턴 (Static Factory Method)
Static Factory Method Pattern 정적 팩토리 메서드(Static Factory Method) 패턴은 개발자가 구성한 Static Method를 통해 간접적으로 생성자를 호출하는 객체를 생성하는 디자인 패턴이다. 우리는 지금까지 객체
inpa.tistory.com
10. 기발한 이름은 피하라
이름이 너무 기발하면 아는 사람만 기억한다.(마치 은어를 사용하면 아는 사람만 받아들이는 것 처럼)
그러니 기발한 이름보다는 명료한 이름을 쓰자.
특히 구어체나 속어와 같이 특정 문화에서만 사용되는 농담도 지양하자.
ex : kill() 대신 whack()
11. 한 개념에 한 단어를 사용하자
이름이 다르면 클래스나 타입도 다르다고 생각하기 쉬우므로
일관성 있는 어휘를 사용하자는 내용이다.
동일한 코드인데 controller, manager, driver를 섞어쓰면 독자 입장에서 혼란스럽다.
이건 테크니컬 라이팅의 일관성 있는 어휘 사용과도 통하는 내용으로 볼 수 있다.
12. 말장난을 하지 마라
한 단어를 2가지 목적으로 사용하지 말자.
ex: 기존값 2개를 더하는 경우 add 메서드라고 했다면, 집합에 값하나 추가하는 것은 add와는 맥락이 다르다.
그러므로 isnert와 같은 다른 명칭이 적합하다.
독자가 코드를 최대한 이해하기 쉽게 짜야 하므로, 동일한 명칭인데 다른 동작을 하도록 속이는 것은 가독성만 떨어뜨리기 때문이다.
13. 해법영역에서 가져온 이름을 사용하자
전산용어, 알고리즘, 수학용어를 사용해도 좋다.
독자도 프로그래머이므로.
전부다 문제영역에서 이름을 가져온다면 동료들이 오히려 이해하기 어렵다.
14. 문제영역에서 가져온 이름을 사용하자
적절한 프로그래밍 용어가 없으면 그때 문제(도메인) 영역에서 이름을 가져온다.
그러면 프로그래머는 도메인 전문가에게 의미를 물어 파악가능하다.
15. 의미 있는 맥락을 추가하라
이름에 의미가 분명하지 못할때는
- 클래스, 함수등 이름에 맥락을 넣거나
- 접두어를 붙이는 방법도 존재한다.
1. state 변수만 사용
2. firstName, lastName, street, city, state 등 변수
3. addrFirstName. addrLastName, addrState 변수 사용
위에서 아래로 갈 수록 조금 더 '주소'라는 맥락이 잡힌다.
// 맥락이 불문명한 변수
// 함수 이름은 맥락의 일부만 제공하며, 알고리즘이 나머지 맥락을 제공.
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, cadidate, pluralModifier);
print(guessMessage);
}
이 코드는 함수안에 변수가 들어있고, 각각의 로직이 맥락을 제공한다.
// 세 변수를 클래스에 넣음으로 맥락을 분명히. 세 변수를 함수 전반에서 사용.
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";
}
}
출처: https://bo5mi.tistory.com/225 [대범하게:티스토리]
이 코드는 클래스명과 알고리즘을 쪼개서 만든 메서드들로 조금 더 맥락을 알 수 있게 해주고 있다.
요지는 클래스와 메서드명을 사용해서 조금 더 맥락을 끌어올릴 수 있다는 뜻으로 보인다.
16. 불필요한 맥락을 없애라
고급 휘발유 충전소(Gas Station Deluxe)라는 앱을 만든다고 가정했을때,
모든 클래스 명을 GSD로 시작하는 것은 현명하지 못하다.
오히려 IDE자동완성시 모든 클래스가 열거되므로 가독성을 방해할 수 있기 때문에.
일반적으로는 의미가 분명한 경우 짧은 이름이 긴 이름보다 선호된다.
GSDAccountAddress라는 클래스명 보다는
Address라는 명이 더 적절할 것이다.
FIN
좋은 이름을 위해선 뛰어난 설명능력 및 문화적 배경이 같아야 하는데,
이건 쉽지 않은 일이다.
이름을 바꾸는게 반대에 부딪힐까 두려울 수 있겠지만,
개선하려는 노력을 중단하지 말자.