아주 간단한 프로그램을 만들 때도 네이밍을 하는 것이 가장 고뇌이다. 이 장에서는 변수, 객체, 클래스, 함수 등 작명을 해야할 때 유념해야 할 규칙을 설명해주고 있다.
의도를 분명히 밝혀라
변수나 함수, 클래스의 이름에는 아래 질문에 답할 수 있는 정보가 포함되어야 한다.
- 변수(혹은 함수, 클래스)의 존재 이유는 ?
- 수행 기능은 ?
- 사용 방법은 ?
주석 없이 이름만으로 읽는 사람이 해당 자원의 정보를 캐치할 수 있도록 작명해야 한다.
코드는 단순하기보다는 함축적이어야 한다. 코드 맥락이 코드 자체에 명시적으로 드러나야하며, 이를 다양한 기법으로 구현할 수 있다. 아래 예시를 보자 !
public List<Cell> getFlaggedCells(){
List<Cell> flaggedCells = new ArrayList<Cell>();
for(Cell cell : gameBoard){
if(cell.isFlagged())
flaggedCells.add(cell);
}
return flaggedCells;
}
- flaggedCells라는 명확한 이름의 사용으로 List에 담긴 Cell의 공통된 특징을 파악할 수 있다.
- Cell이라는 클래스(혹은 구조체)를 사용해서 List에 무엇이 들었는 지 한 번에 파악할 수 있다.
- isFlagged()와 같은 함수를 호출하여 제어문에 대한 조건을 가독성있게 표현하였다.
그릇된 정보를 피하라
그릇된 단서는 코드의 의미를 흐린다. 그릇된 단서의 예시로는 아래와 같은 것이 있다.
- 나름대로 널리 쓰이는 의미가 있는 단어를 사용하는 것
- ex) 실제 List 자료형이 아닌 자원을 accountList와 같이 명명하는 것
- ex) hp, aix, sco와 같이 유닉스 플랫폼을 가르키는 이름으로 변수를 사용하는 것
- 서로 흡사한 이름을 사용하는 것
- ex) XYZControllerForEfficientHandlingOfStrings와 XYZControllerForEfficientStorageOfStrings를 함께 사용하는 것
- 유사한 모양의 표기를 사용하는 것
- ex) 대문자 L과 1, 대문자 I와 소문자 l, 그리고 대문자 O와 0은 혼용될 수 있다.
의미있게 구분하라
중복되거나 아무런 의미없는 단어로 명명하지 않을 것.
중복되는 경우는 AccountData, AccountInfo, NameString, CustomerObject 과 같이 쓸모 없거나 당연한 정보를 포함하는 경우를 말한다. 가끔 a1, a2와 같이 숫자를 접미사로 붙여 변수를 구분하기도 하는데, 아무런 정보를 제공하지 않는 이름이므로 지양하는 것이 좋다.
검색하기 쉬운 이름을 사용하라
보통 리눅스 체제에서는 아래와 같이 grep을 사용해 변수나 함수의 이름을 검색한다.
grep "MAX_CLASSES_PER_STUDENT" ./db/data/*
이런 경우에서 짧은 문자열보다 길고 명확한 문자열이 찾기 더 편하다.
숫자 5를 그냥 사용하는 것보다 상수로 사용하여, 상수로 인한 오류 시 원인을 찾기 용이하게 할 수 있다.
인터페이스 클래스와 추상 클래스
OOP에서는 다형성을 사용하기 위해 인터페이스 클래스 (Interface Class) 를 사용한다. 인터페이스에서는 모든 기능을 추상화로 정의만 하고 구현을 하지 않으며, 함수에 대한 구현은 구체 클래스 (Concrete Class)에서 따로 한다. 즉, 구체 클래스는 인터페이스의 메서드를 오버라이딩 (재정의) 하여 프로그램의 유연성을 높인다.
이런 인터페이스 클래스 이름과 구체 클래스 이름 중 하나를 인코딩해야한다면, 구체 클래스를 인코딩하는 방향을 선택한다. ShapeFactory라는 인터페이스 클래스가 있다면 ShpaeFactoryImpl 와 같이 클래스를 네이밍한다.
자신의 기억력을 자랑하지 마라
전문가 프로그래머는 명료함이 최고다! 라는 사실을 이해하고 있다. 클래스 이름과 메서드 이름에 대한 일반적인 가이드라인은 다음과 같다.
클래스 이름
클래스나 객체의 이름은 명사나 명사구가 적합하다. Manager, Data, Info 등의 추상적인 단어는 피하고, 동사는 사용하지 않는다.
올바른 예시 : Account, AddressParser, WikiPage, Customer
메서드 이름
메서드 이름은 동사나 동사구가 적합하다. 접근자 (Accessor), 변경자 (Mutator), 조건자 (Predicate)는 주로 get, set, is를 접두사로 붙인다.
올바른 예시 : postPayment, deletePage, save
추가로, 생성자를 오버로드할 때는 정적 팩토리 메서드를 사용한다.
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
*정적 팩토리 메서드(Static Factory Method) 란, 객체의 생성을 담당하는 클래스 메서드이다. new 연산자를 직접적으로 사용하지는 않지만 메서드 내부에서 new를 이용해 객체를 생성해 반환하는 것이다.
public static Complex FromRealNumber(Double number){
return new Complex(number);
}
그리고 정적 팩토리 메서드는 위와 같이 정의하면 된다.
한 개념에 한 단어를 사용하라
추상적인 개념 하나에 단어 하나를 선택해 고수한다.
내가 자주 놓치는 규칙인데, 예를 들어서 API 명세서의 엔드 포인트는 /members/join 으로 설정하였는데, 함수 이름은 insertMember인 경우이다. 이런 습관은 팀 작업을 할 때는 함수 이름을 기억하는 개인, 혹은 단체를 찾아가 물어봐야 하는 상황이 생기기 때문에 지양해야한다.
동일 코드 기반에 Controller, Driver, Manager 등의 용어를 혼동해서 사용하는 것도 이에 해당한다.
의미있는 맥락을 추가하라
스스로 의미가 불분명한 이름인 경우, 클래스나 함수 등 더 큰 범위에 이를 포함시키거나 접두어를 붙여서 맥락을 추가한다.
firstName, lastName, street, zipcode, city, state 등의 변수가 있다고 하자. 이 자체만으로는 무슨 정보를 포괄하는 지 알 수 없기 때문에, 아래와 같이 두 가지 방식으로 수정할 수 있다.
- Address 클래스를 생성해 멤버 변수를 포함시키는 방법
- 변수에 addrFirstName, addrLastName, addrStreet, addrZipcode, addrCity, addrState 와 같이 접두어를 추가하는 방법
'DEV book > Clean Code' 카테고리의 다른 글
[Clean Code] 3장 함수 (1) (0) | 2023.05.23 |
---|---|
[CleanCode] 1장 깨끗한 코드 (0) | 2023.04.28 |