이 내용은 로버트 C. 마틴 저자님의 클린코드 책의 내용을 가져온 것입니다.
개발자들에게 이름을 짓는 것은 매우 어려운 일이다.. 항상 이름을 뭘로 할지 고민하다가 30분이 지난 적도 있다. 클린코드에서 의미 있는 이름을 짓는 법을 알아보도록 하자!
의도가 분명한 이름을 짓는 것이 정말로 중요하다. 고민하는 시간이 아까워도 투자해야 한다. 좋은 이름을 지으면서 절약하는 시간이 훨씬 더 많기 때문이다.
int d; // 경과 시간(단위: 날짜)
이름을 단순히 d라고 만들어 버리면 무슨 의미를 가진 변수인지 알기 어렵다.
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
위와 같이 시간의 뜻이 잘 담긴 변수명을 사용해서 의도를 분명하게 하면 좋다.
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x: theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
위 코드만 보면 어떤 역할을 하는 메서드인지 바로 파악할 수 있을까? 정확히 어떤 기능을 하는 메서드인지 파악하기 어렵다.
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
for (int[] cell: gameBoard)
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
}
아까 보던 코드보다는 훨씬 직관적이고 이해하기 편해진 코드이다. 여기서 한걸음 나아가서 int 배열을 사용하는 대신 칸을 간단한 클래스로 만들어도 좋을 것 같다. isFlagged 라는 함수를 사용해서 FLAGGED라는 함수를 감춰도 좋을 것 같다.
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell: gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
단순히 이름만 고쳤는데 함수가 하는 기능을 이해하기 쉬워졌다. 이게 좋은 이름이 주는 위력이다.
나름대로 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하면 안된다. 예를 들어 hp라는 변수를 사용했다고 가정해볼때 hp를 보면 어떤 의미가 떠오르나? 나는 바로 컴퓨터 제조사 hp가 떠올랐다. 의도는 직각삼각형의 빗변을 뜻하는 hypotenuse 였다.
이처럼 널리 쓰이고 있는 단어는 피해서 사용하는 것이 좋다.
그리고 여러 계정을 그룹으로 묶을 때 실제 List가 아니라면 accountList라고 하지 않는 것이 좋다. 추가로 List 자료구조로 보이게 하는 그릇된 정보를 제공하는 셈이기 때문에 List를 썼다고 해도 해당 유형을 이름에 넣지 않는 편이 좋다. 따라서 accountGroup, bunchOfAccounts, Accounts와 같은 이름이 어울린다.
또한 서로 흡사한 이름을 사용하지 않도록 주의한다.
String XYZControllerForEfficientHandlingOfStrings;
String XYZControllerForEfficientStorageOfStrings;
딱 보자마자 3초안에 무슨 차이가 있는지 연락주시면 치킨사드림.
마지막으로 비슷해보이는 문자를 쓰지말자는 것.
int a = l;
if (O == l)
a = O1;
else
l = 01;
소문자 l과 숫자 1, 대문자 O와 숫자 0과 같이 헷갈리는 문자는 아예 쓰지를 말아버리자.
내 코드를 읽는 사람이 차이를 알도록 이름을 짓는 습관을 들여야 한다.
연속된 숫자를 덧붙이거나 불용어를 추가하는 방식은 적절하지 않다.
추가로 예를 들어 Product라는 클래스가 있을 때 다른 클래스를 ProductInfo, ProductData와 같이 부른다면 개념을 구분하지 않은 채 이름만 달리했다고 생각할 수 있다. 마치 a, the 와 같은 의미가 불분명한 불용어를 사용한 것과 같다.
불용어를 사용하는 것은 중복을 만드는 것 밖에 되지 않는다. NameString
과 Name
, Customer
와 CustomerObject
와 같이 차이가 전혀 없다는 것을 확인할 수 있다.
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
}
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId = "102";
}
두 개의 클래스 중 어떤 게 더 알아보기도 쉽고 발음하기도 쉬울까요? 맞춰보세용~!
MAX_CLASSES_PER_STUDENT
와 같은 의미 있는 문구를 사용하자. 7이라고 작성한 것은 이유가 있을테니까!유형이나 범위 정보처럼 이름에 인코딩할 정보는 아주 많다. 여기에 추가로 의미 구분을 위한 인코딩 규칙까지 추가하게 되면 그만큼 이름을 해독하기 어려워진다. 예를 들어 멤버 변수를 선언할 때 m_
와 같은 접두어를 붙이는 경우가 해당할 것이다. 전반적으로 코드에 m_
이 붙어있으면 아무래도 가독성이 떨어지게 된다.
인터페이스 클래스와 구현 클래스 구분을 위해 인코딩이 필요하기도 하다. 흔히 IShapeFactory
와 ShapeFactory
처럼 인터페이스에는 I
접두어를 붙이기도 하는데 이는 주의를 흐트리고 과도한 정보를 제공할 수 있다. 이보다는 구현 클래스에 인코딩을 해서 ShapeFactoryImp
등으로 사용하는 편이 좋다.
독자가 코드를 읽으면서 변수 이름을 자신이 아는 이름으로 변환해야 한다면 그 변수 이름은 바람직하지 않다. 예를 들어 r이라는 변수가 호스트와 프로토콜을 제외한 소문자 URL이라는 사실을 언제나 기억할 수 있을까?
명료함이 최고다.
클래스 이름과 객체 이름은 명사나 명사구
가 적합하다.
메서드 이름은 동사나 동사구가 적합하다.
재미난 이름보다 명료한 이름을 선택하자.
예를 들어 Student를 가지고 오는 메서드를 작성한다고 할 때 다음과 같은 3개의 메서드가 있다고 해보자.
get, fetch, retrieve 모두 받아온다는 의미를 가지고 있긴하다. 하지만 어떤 거든 통일해서 쓰는게 가장 편하다.
개발자들끼리 주로 사용하는 디자인 패턴에서 나오는 단어를 사용하는 것도 좋다. 코드를 읽고 고치는 사람도 개발자 이기 때문에 문제되는 부분은 없을 것이다. 대표적으로 AccountVisitor
와 JobQueue
가 있을 것 같다.
대다수의 이름은 스스로 의미가 분명하지 않다. 그래서 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다. 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.
고급 휘발유 충전소 어플리케이션을 짠다고 가정해보면 모든 클래스 이름을 GSD로 시작하는 것은 바람직하지 못하다. (고급 휘발유 충전소 = Gas Station Deluxe)
이번에 생각보다 내용이 많은데 배운점이 너무 많은 것 같다. 사실 이정도까지 생각을 깊게 가져가면서 이름을 짓지는 않은 것 같다. 지금 진행하고 있는 프로젝트에 빨리 조금조금씩 적용해보고 싶은 마음이 굴뚝같다.
나중에 기회가 된다면 이름 규칙을 적용한 코드와 그렇지 않은 코드를 비교하는 블로그 게시물을 올려보고 싶다!