클린코드 #2 의미있는 이름


프로그래밍을 하면서 우리는 변수에도, 함수, 인수와 클래스와 패키지에도 이름을 붙인다. 이 책, 클린코드 2장에서는 이름을 잘 짓는 간단한 규칙을 몇가지 소개한다.

SUMMARY

  1. 의도를 분명히 밝혀라
  2. 그릇된 정보를 피해라
  3. 의미있게 구분하라
  4. 발음하기 쉬운 이름을 사용하라
  5. 검색하기 쉬운 이름을 사용하라
  6. 인코딩을 피하라
  7. 자신의 기억력을 자랑하지 마라
  8. 기발한 이름은 피하라
  9. 한 개념에 한 단어를 사용하라
  10. 말장난을 하지마라
  11. 해법 영역: 문제 영역에서 가져온 이름을 사용하라
  12. 의미 있는 맥락을 추가하라
  13. 불필요한 맥락을 없애라

렛츠 고고싱~

의도를 분명히 밝혀라

좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 많다. 변수나 함수 그리고 클래스 이름은 다음과 같이 굵직한 질문에 모두 답해야 한다.

  • 변수(혹은 함수나 클래스)의 존재 이유는?
  • 수행 기능은?
  • 사용 방법은?

따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 말이다. 문제는 코드의 단순성이 아니라 코드의 함축성이다. 코드명에서 충분한 정보 제공을 해주는가?

그릇된 정보를 피해라

프로그래머는 코드에 그릇된 단서를 남겨서는 안 된다. 나름대로 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용해도 안된다.

여러 계정을 그룹으로 묶을 때 실제 List가 아니라면, accountList라 명명하지 않는다. 프로그래머에게 List라는 단어는 특수한 의미이기 때문이다. 그러므로 accountGroup 또는 bunchOfAccounts, 아니면 단순히 Accounts라 명명한다.

서로 흡사한 이름을 사용하지 않도록 주의한다. 유사한 개념은 유사한 표기법을 사용한다. 이것도 정보다.

특히 대문자 O와 소문자 L을 사용할 때 주의해야한다. O는 숫자 0처럼, L은 숫자 1처럼 보인다.

의미있게 구분하라

동일한 범위 안에서는 다른 두 개념에 같은 이름을 사용하지 못한다. 한쪽 이름을 마음대로 바꾸고픈 유혹에 빠져서 컴파일러만 통과하도록 살짝 고친다면 안될것이다.

의미가 불분명한 불용어를 쓴 경우: 다른 클래스를 ProductInfo혹은 ProductData라 부른다면 개념을 구분하지 않은 채 이름만 달리한 경우다.

불용어(nosie word)는 중복이다. 변수 이름에 variable이라는 단어는 단연코 금물이다. 표 이름에 table이라는 단어도 마찬가지다. 읽는 사람이 차이를 알도록 이름을 지어라.

발음하기 쉬운 이름을 사용하라

사람들은 단어에 능숙하다. 말을 처리하려고 발달한 두뇌를 활용하려면 발음하기 쉬운 이름을 선택하자.

발음하기 어려운 이름은 토론하기도 어렵고 바보처럼 들리기 십상이다.

genymdhms (generate date, year, month, day, hour, minute, second)라는 변수명을 읽는다고 생각해보라.

검색하기 쉬운 이름을 사용하라

문자 하나를 사용하는 이름과 상수는 텍스트 코드에서는 쉽게 눈에 띄지 않는다는 문제점이 있다. 마찬가지로 e라는 문자도 변수 이름으로 적합하지 못하다. 검색이 어려운 탓이다. 십중팔구 거의 모든 프로그램, 거의 모든 문장에 등장한다.

  • 긴 이름이 짧은 이름보다 좋다
  • 검색하기 쉬운 이름이 상수보다 좋다
  • 간단한 메서드에서 로컬 변수만 한 문자를 사용한다
  • 이름 길이는 범위 크기에 비례해야 한다

인코딩을 피하라

인코딩: 코드화, 암호화

문제 해결에 집중하는 개발자에게 인코딩은 불필요한 정신적 부담이다. 인코딩한 이름은 거의가 발음하기 어려우며 오타가 생기기도 쉽다.

헝가리식 표기법

이름 길이가 제한된 언어를 사용하던 옛날에는 어쩔 수 없이 이 규칙을 위반했다. 포트란은 첫 글자로 유형을 표현했다. 헝가리식 표기법은 기존 표기법을 완전히 새로운 단계로 끌어올렸다.

당시는 컴파일러가 타입을 점검하지 않았으므로 프로그래머에게 타입을 기억할 단서가 필요했다. 하지만 요즘 나오는 프로그래밍 언어는 훨씬 많은 타입을 지원한다. 또한 컴파일러가 타입을 기억하고 강제한다.

멤버 변수 접두어

이제는 멤버 변수에 _m이라는 접두어를 붙일 필요도 없다. 클래스와 함수는 접두어가 필요없을 정도로 작아야 마땅하다. 게다가 사람들은 접두어 (또는 접미어)를 무시하고 이름을 해독하는 방식을 재빨리 익힌다. 코드를 읽을수록 접두어는 관심 밖으로 밀려난다.

인터페이스 클래스와 구현 클래스

때로는 인코딩이 필요한 경우도 있다. 예를 들어 도형을 생성하는 ABSTRACT FACTORY를 구현한다고 가정하자. 이 클래스가 인터페이스라는 사실을 남에게 알리고 싶지 않고, 사용자는 그냥 ShapeFactory라고만 생각하면 좋겠다.

그래서 인터페이스 클래스 이름과 구현 클래스 이름 중 하나를 인코딩해야 한다면 구현 클래스 이름을 택한다. ShapeFactoryImp가 (접두어를 붙인) IShapeFactory 보다 좋다.

자신의 기억력을 자랑하지 마라

독자가 코드를 읽으면서 변수 이름을 자신이 아는 이름으로 변환해야 한다면 그 변수 이름은 바람직하지 못하다. 이는 일반적으로 문제 영역이나 해법 영역에서 사용하지 않는 이름을 선택했기 때문에 생기는 문제다.

  • 문자 하나만 사용한 변수 이름 사용하지 않기
  • 명료한, 남들이 이해하는 코드를 내놓기

클래스 이름

클래스 이름과 객체 이름은 명사나 명사구가 적합하다. 동사는 사용하지 않는다.

// 좋은 예
Customer, Account, AddressParser

// 피해야 할 예
Manager, Processor, Data, Info

메서드 이름

메서드 이름은 동사나 동사구가 적합하다.

// 좋은 예
postPayment, deletePage, save

접근자, 변경자, 조건자는 javabean 표준에 따라 값 앞에 get, set, is를 붙인다.

기발한 이름은 피하라

재미난 이름보다 명료한 이름을 선택하라. 특정문화에서만 사용하는 농담은 피하는 편이 좋다. 의도를 분명하고 솔직하게 표현하라.

한 개념에 한 단어를 사용하라

메서드 이름은 독자적이고 일관적이어야 한다. 그래야 주석을 뒤져보지 않고도 프로그래머가 올바른 메서드를 선택한다. 예를 들어 똑같은 메서드를 fetch, retrieve, get으로 제각각 부르면 혼란스럽다. 어느 클래스에서 어느 이름을 썼는지 기억하기 어렵다. 이름이 다르면 독자는 당연히 클래스도 다르고 타입도 다르리라 생각한다.

말장난을 하지마라

한 단어를 두가지 목적으로 사용하지 마라. 아래 예시를 보자.

  • 지금까지 구현한 add 메서드
    • 기존 값 두개를 더하거나 이어서 새로운 값을 만든다
  • 새 메서드 add
    • 집합에 값 하나를 추가한다.

일관성을 고려해 add라고 이름을 짓는게 좋을까? 이런 경우에는 맥락이 다르기 때문에 insertappend라는 이름이 적당하다.

해법 영역에서 가져온 이름을 사용하라

코드를 읽을 사람도 프로그래머다. 전산 용어, 알고리즘 이름, 수학 용어 등을 사용해도 괜찮다. 기술 개념에는 기술 이름이 가장 적합한 선택이다.

문제 영역에서 가져온 이름을 사용하라

앞서 말한 것 처럼 적절한 프로그래머 용어가 없다면 문제 영역에서 이름을 가져온다. 문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져와야 한다.

의미 있는 맥락을 추가하라

클래스, 함수, 이름 공간에 넣어 맥락을 부여해서 이름의 의미를 분명하게 만든다. 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다. 예: addrFirstName

addr라는 접두어를 추가하면 맥락이 좀 더 분명해진다. 물론 Address라는 클래스를 생성하면 더 좋다. 그러면 변수가 좀 더 큰 개념에 속한다는 사실이 컴파일러에게도 분명해진다.

불필요한 맥락을 없애라

일반적으로는 짧은 이름이 긴 이름보다 좋다. 단, 의미가 분명한 경우에 한해서다. 이름에 불필요한 맥락을 추가하지 않도록 주의한다.

// 클래스 인스턴스로 좋은 예
accountAddress, customerAddress

// 클래스 이름으로 적합한 예
Address

느낀 점

첫 아이 이름 짓듯이 변수명 (함수, 메서드명 등….)을 지으라니! 아이는 없지만 엄청난 책임감이 느껴진다. 프로그래밍을 막 시작하고 나서는 내가 작성한 코드가 동작한다는 사실만으로도 신기했다. 많아봤자 두 페이지, 천 줄을 넘지 않는 코드는 대충 지어도 어떤 역할인지 저 이름이 어떤 의미인지 알 수 있었다. 내가 작성했고 물론, 독자도 나뿐인 코드니까! 하지만 일을 하게 되면서 나 아닌 다른 사람이 작성한 코드를 작성했고, 내가 작성한 코드를 다른 사람들이 봐야 할 때가 왔다. REST API로 서버에서 데이터를 받아오는 법을 배우게 됐다. 그때 바로 스토어에 있는 액션을 다른 페이지에서 불러와 사용할 때를 위해 직관적으로 이름을 명명해야 한다는 사실을 깨달았다.

그냥 리턴해버리고 끝나는 (dispatch가 없는) 경우에는 onTheFly라고 붙여줌으로써 의미를 알려준다. 한 스토어 안에서 데이터를 가져오는 접두사를 fetch라고 하기로 했으면 같은 맥락에서 사용하는 액션은 일관성을 위해 get이라고 쓰는 일이 없도록 한다.

이 장을 읽으면서 그때 일을 하며 어렴풋이 생각했던 것들이 최고 선배님들의 손으로 명확하게 텍스트로 작성된 것을 보니 앞으로 어떤 식으로 이름을 지어야 할지 알 것 같다. 회사에서 사용할 이름을 부모님에게 의뢰 맡겼는데 부모님이 이틀 밤을 같이 고민하셨던 몇 달 전이 기억난다. 그 모습을 기억하면서 (이틀이나 고민하면 곤란하겠지만) 그리고 이 장에서 배운 13가지 규칙을 기억하면서 읽기 쉬운 변수, 함수, 메서드명을 지어야지. 물론 이렇게 다짐하고 나서도 나는 코드에 무수히 수많은 똥을 싸버릴 것이지만 실패는 성공의 어머니. 저는 어머니를 찾으러 갑니다… 안녕.