11장: 변수 이름의 기능

11장: 변수 이름의 기능

  • 좋은 이름 짓기는 중요한 주제인데도 대부분의 책은 몇 문단으로 넘어감. 이 장은 반대로 좋은 이름에 관한 수십 가지 고려 사항을 다룸
  • 지침은 주로 변수(객체와 기본 데이터) 이름에 적용되지만 클래스, 패키지, 파일 등 다른 프로그래밍 요소에도 적용됨

11.1 좋은 이름을 선택하기 위한 고려 사항

  • 변수와 변수 이름은 본질적으로 같은 것임. 변수의 좋고 나쁨은 이름이 크게 좌우함
  • x = x - xx 같은 코드는 무엇을 하는지 알 수 없지만, balance = balance - lastPayment는 바로 읽힘
  • 좋은 변수 이름은 읽기 쉽고, 기억하기 쉽고, 적절함

가장 중요한 명명 고려 사항

  • 이름이 변수가 나타내는 대상을 완전하고 정확하게 설명해야 함
  • 변수가 나타내는 것을 말로 표현해 보면, 그 표현 자체가 종종 최선의 이름임
  • 이자율은 r이나 x보다 rateinterestRate가 나음
  • x, temp, i처럼 여러 목적으로 쓸 수 있을 만큼 일반적인 이름은 대개 나쁜 이름임. 이름은 가능한 한 구체적이어야 함

문제 지향

  • 좋은 이름은 해법(how)이 아니라 문제(what)를 표현함
  • inputRec보다 employeeData, bitFlag보다 printerReady, calcVal보다 sum이 문제 도메인을 가리키는 이름임

최적의 이름 길이

  • 너무 짧은 이름은 의미를 전달하지 못하고, 너무 긴 이름은 타이핑하기 어렵고 시각적 구조를 가림
  • 연구에 따르면 평균 10~16자 이름일 때 디버깅 노력이 최소였음 (8~20자도 거의 비슷함)
  • 모든 이름을 그 길이로 맞추라는 뜻이 아니라, 짧은 이름이 많다면 충분히 명확한지 점검하라는 뜻임
  • 너무 긺: numberOfPeopleOnTheUsOlympicTeam / 너무 짧음: n, np / 적당함: numTeamMembers, teamMemberCount

범위가 변수 이름에 미치는 영향

  • 짧은 이름이 항상 나쁜 것은 아님. i 같은 이름은 그 자체로 “몇 줄 안에서만 쓰는 임시 값”이라는 정보를 줌
  • 연구에 따르면 긴 이름은 거의 사용되지 않는 변수나 전역 변수에, 짧은 이름은 지역 변수나 루프 변수에 적합함
  • 다만 짧은 이름은 문제가 많아 방어적으로 아예 피하는 프로그래머도 있음
  • 전역 네임스페이스에 있는 이름에는 한정자를 사용함. C++/C#의 namespace, Java의 패키지, 또는 uiEmployee/dbEmployee 같은 접두어 규칙으로 충돌을 줄임

계산된 값 한정자

  • Total, Sum, Average, Max, Min 같은 한정자는 이름 끝에 붙임
  • 의미의 핵심이 앞에 오고, totalRevenuerevenueTotal을 혼용하는 혼란을 막고, revenueTotal/expenseTotal/revenueAverage 같은 대칭성이 생김
  • 예외는 Num인데, 앞에 붙으면 총계(numCustomers), 뒤에 붙으면 인덱스(customerNum)를 뜻해 혼란스러움
  • 총계에는 CountTotal, 특정 항목에는 Index를 써서 문제를 회피함 (customerCount, customerIndex)

변수 이름에서 흔한 반의어

  • 반의어는 정확하게 짝을 맞춰 사용함: begin/end, first/last, locked/unlocked, min/max, next/previous, old/new, opened/closed, visible/invisible, source/target(destination), up/down

11.2 특정 타입의 데이터 이름 짓기

루프 인덱스 이름

  • 단순한 루프에서는 i, j, k가 관례임
  • 루프 밖에서도 쓰이는 변수라면 recordCount처럼 의미 있는 이름을 붙임
  • 루프가 몇 줄 이상이거나 중첩되면 teamIndex, eventIndex처럼 긴 이름이 나음. score[ teamIndex ][ eventIndex ]score[ i ][ j ]보다 명확하고 인덱스 혼선(cross-talk)을 막음
  • i, j, k를 쓴다면 단순 루프 인덱스 외 용도로는 쓰지 않음

상태 변수 이름

  • 상태 변수에 flag라는 이름을 쓰지 않음. flag는 무엇을 하는지 아무 단서도 주지 않음
  • statusFlag = 0x80보다 characterType = CONTROL_CHARACTER, if ( printFlag == 16 )보다 if ( reportType == ReportType_Annual )이 명확함
  • 상태 값은 열거형, 이름 있는 상수로 할당하고 검사함
  • 코드를 “추리”하고 있다면 변수 이름을 바꿀 신호임. 코드는 추리하는 게 아니라 읽는 것이어야 함

임시 변수 이름

  • temp, x 같은 이름은 프로그래머가 문제를 아직 완전히 이해하지 못했다는 신호일 수 있음
  • 사실 프로그램의 변수 대부분은 임시적임. 몇 개만 “임시”라고 부르는 것은 진짜 목적을 모른다는 뜻일 수 있음
  • 이차방정식 예에서 temp 대신 discriminant(판별식)를 쓰면 같은 코드가 훨씬 명확해짐

불린 변수 이름

  • 유용한 대표 불린 이름: done(완료 여부), error(오류 발생 여부), found(발견 여부), success/ok(성공 여부)
  • success는 가능하면 processingComplete, found처럼 성공의 의미를 구체적으로 드러내는 이름으로 바꿈
  • 참/거짓을 암시하는 이름을 사용함. status, sourceFile은 참이 무슨 뜻인지 알 수 없는 나쁜 불린 이름임. statusOK, sourceFileAvailable로 바꿈
  • is 접두어를 쓰면 이름이 질문이 됨(isDone?). 모호한 이름에는 적용이 안 된다는 장점이 있지만(isStatus?는 말이 안 됨), if ( isFound )if ( found )보다 약간 덜 읽힘
    다만, is 접두어를 강제로 붙이는 경우도 있음 (JAVA, 롬복 @Getter 등...)
    
  • 긍정형 이름을 사용함. notFound는 부정하면 if not notFound처럼 읽기 어려워짐

열거형 이름

  • Color_, Planet_, Month_ 같은 그룹 접두어로 같은 그룹에 속함을 드러냄
  • 언어가 Color.Color_Red처럼 열거형 이름을 항상 앞에 붙여 준다면 접두어를 반복할 필요 없이 Color.Red로 단순화함

상수 이름

  • 상수가 가리키는 숫자가 아니라 상수가 나타내는 추상적 개념의 이름을 붙임
  • FIVE는 나쁘고 CYCLES_NEEDED가 좋음. BAKERS_DOZEN보다 DONUTS_MAX가 좋음

11.3 이름 규약의 효과

  • 규약의 이점: 결정을 한 번만 내려 더 중요한 일에 집중할 수 있음, 프로젝트 간 지식 이전이 쉬움, 새 프로젝트 코드를 빨리 익힘, 같은 것을 다른 이름으로 부르는 이름 증식을 줄임, 언어의 약점을 보완함, 관련 항목 간의 관계를 강조함(employeeAddress, employeePhone)
  • 핵심은 어떤 규칙이든 규칙이 없는 것보다 낫다는 것임. 힘은 특정 규칙이 아니라 규칙이 존재한다는 사실에서 나옴
  • 규칙이 필요한 경우: 여러 명이 작업할 때, 다른 프로그래머에게 넘길 때(거의 항상), 코드 리뷰를 받을 때, 프로그램이 머리에 다 안 들어올 만큼 클 때, 수명이 길 때, 표준 용어·약어가 필요할 때
  • 형식성의 정도는 인원, 규모, 수명에 따라 정함. 작은 일회성 프로젝트에는 엄격한 규칙이 과할 수 있고, 큰 프로젝트에는 공식 규칙이 필수적임

11.4 비형식적인 이름 규약

언어 독립적 규칙 지침

  • 변수 이름과 루틴 이름을 구분함 (예: variableName vs RoutineName())
  • 클래스와 객체(형과 변수)를 구분함: 첫 글자 대문자화(Widget widget), 전체 대문자(WIDGET widget), t_ 접두어, a 접두어, 더 구체적인 변수 이름(Widget employeeWidget) 등 선택지가 있고 각각 장단점이 있음
  • 전역 변수는 g_ 접두어로 식별함
  • 멤버 변수는 m_ 접두어로 지역도 전역도 아님을 드러냄
  • 형 정의는 t_Color처럼 접두어나 대문자로 식별해 변수와의 충돌을 피함
  • 이름 있는 상수는 c_RecsMax 또는 ALL_CAPS로 식별함
  • 열거형 요소는 e_ 접두어나 Color_ 같은 형 기반 접두어로 식별함
  • 입력 전용 매개변수를 언어가 강제하지 않으면 const 접두어 같은 규칙으로 보완함. constMax.SetNewMax(...)가 보이면 오류임을 알 수 있음
  • 가독성을 위해 대소문자 혼합이나 밑줄로 단어를 구분하되, 두 기법을 섞지 않음. 일관성이 세부 선택보다 중요함

언어별 규칙

  • C: c/ch는 문자, i/j는 정수 인덱스, n은 개수, p는 포인터, s는 문자열, 매크로는 ALL_CAPS, 변수·루틴은 all_lowercase에 밑줄 구분
  • C++: i/j는 인덱스, p는 포인터, 상수·typedef·매크로는 ALL_CAPS, 클래스와 형은 MixedCase, 변수·함수는 camelCase, 밑줄은 특수한 경우만
  • Java: 상수는 밑줄 있는 ALL_CAPS, 클래스·인터페이스는 PascalCase, 변수·메서드는 camelCase, 접근자에는 get/set 접두어
  • 혼합 언어 환경에서는 개별 언어 관례를 거스르더라도 전체 일관성과 가독성 기준으로 최적화함
  • 변수 이름에는 내용(무엇을 나타내는가), 데이터 종류(상수·변수·형·클래스), 범위(비공개·클래스·패키지·전역)의 세 가지 정보가 들어감 ``` 대체로 IDE 가 잘 되어 있어서, IDE 표준 따라가면 됨.

But, 너무 자주 틀리는 부분은 정적 분석기 사용



**Java**
 
- **Checkstyle** — 명명 규칙 강제의 표준. `LocalVariableName`, `ConstantName`, `MemberName` 등 요소별로 정규식 패턴을 지정함. Gradle/Maven 플러그인으로 빌드나 앞서 만든 pre-commit 훅에 연결하기 좋음

```xml
<!-- checkstyle.xml -->
<module name="ConstantName"/>                       <!-- ALL_CAPS 강제 -->
<module name="LocalVariableName">
    <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>  <!-- camelCase -->
</module>
<module name="AbbreviationAsWordInName"/>           <!-- XMLParser → XmlParser -->

11.5 표준 접두사

  • 대표 사례는 헝가리안 명명 규칙임. 지금은 널리 쓰이지 않지만 간결하고 정확한 표준 약어라는 기본 아이디어는 여전히 가치 있음
  • 표준화된 접두어는 사용자 정의 형(UDT) 약어와 의미 접두어 두 부분으로 구성됨
  • UDT 약어는 프로그램별로 만들어 표준화함 (워드프로세서 예: ch 문자, doc 문서, pa 문단, scr 화면 영역, wn 창)
  • 의미 접두어는 변수의 사용 방식을 설명하며 프로젝트를 넘어 비교적 표준적임: c(개수), first/last(작업 대상의 처음/마지막), lim(비포함 상한, 보통 last+1), min/max(배열 자체의 절대 처음/마지막), i(인덱스), p(포인터), g(전역), m(클래스 수준)
  • 장점: 기억할 이름이 줄고, min/first/last/lim의 정밀한 구분이 생기고, 이름이 간결해지고, paReformat = docReformat처럼 형 오류를 눈으로 잡을 수 있음
  • 함정: 접두어만 믿고 의미 있는 이름을 생략하는 것. ipa보다 ipaActiveDocument처럼 서술적 이름으로 완성함

11.6 읽기 쉬운 짧은 이름

  • 짧은 이름 선호는 이름 길이가 2~8자로 제한되던 시절의 유산임. 현대 언어에서는 의미 있는 이름을 줄일 이유가 거의 없음
  • 그래도 줄여야 한다면 여러 기법을 알아두는 것이 좋음. 어떤 기법도 모든 경우에 통하지는 않음

일반 약어 지침

  • 표준 약어(사전에 있는 것)를 사용함
  • 선행 모음이 아닌 모음을 제거함 (computer → cmptr)
  • 관사 등 불필요한 단어를 제거함
  • 각 단어의 첫 글자나 첫 몇 글자를 사용함
  • 각 단어를 일관되게 1·2·3번째 글자 뒤에서 자름
  • 각 단어의 첫 글자와 마지막 글자를 유지함
  • 최대 세 단어까지 의미 있는 단어를 모두 사용함
  • ing, ed 같은 접미사를 제거함
  • 각 음절에서 가장 두드러진 소리를 유지함
  • 변수의 의미가 바뀌지 않도록 주의함

발음식 약어와 주의 사항

  • sk8ing, b4, xqt 같은 발음식 약어는 개인 번호판 해독 같아서 권장하지 않음
  • 한 글자만 빼는 약어는 만들지 않음. 절약은 미미하고 어떻게 줄였는지 기억하기 어려움
  • 일관되게 약어를 사용함. NumNo를 혼용하지 않고, 어떤 곳은 전체 단어·어떤 곳은 약어로 쓰지 않음
  • 발음할 수 있는 이름을 만듦. 전화로 코드를 읽어줄 수 없다면 이름을 바꿈(전화 테스트)
  • 잘못 읽히는 조합을 피함. BEND보다 ENDB
  • 약어 충돌은 유의어 사전으로 해결함 (fired와 full revenue disbursal이 둘 다 frd가 되면 dismissed → dsm, complete revenue disbursal → crd)
  • 아주 짧은 이름만 허용되는 언어에서는 코드에 번역 표를 주석으로 둠. 6자 제한 같은 환경은 지금도 종종 있음
  • 프로젝트 수준 “표준 약어” 문서에 모든 약어를 기록하고 버전 관리함. 새 약어 등록의 번거로움 자체가 꼭 필요한 약어만 만들게 하는 장치가 됨
  • 이름은 코드를 쓰는 사람보다 읽는 사람에게 더 중요함. 작성 시 편의보다 읽기 편의를 우선함. 시스템 수명 동안 코드는 쓰는 시간보다 읽는 시간이 훨씬 김

11.7 피해야 할 이름

  • 오해를 부르는 이름이나 약어를 피함 (FALSE가 “Fig and Almond Season”의 약어라면 최악)
  • 의미가 비슷한 이름을 피함. 두 변수 이름을 바꿔도 프로그램이 멀쩡하다면 둘 다 다시 지어야 함 (input/inputValue, recordNum/numRecords)
  • 의미는 다른데 이름이 비슷한 변수를 피함. clientRecs/clientReps처럼 한 글자 차이는 위험함. 최소 두 글자 이상 차이를 두거나 차이를 처음이나 끝에 둠
  • 발음이 비슷한 이름을 피함 (wrap/rap). 전화 테스트가 여기에도 적용됨
  • 이름에 숫자를 피함. file1/file2가 의미 있다면 배열을 쓰고, 아니라면 더 나은 구분법을 찾음
  • 의도적으로 틀리게 쓴 단어를 피함. highlight를 hilite로 줄이면 어떻게 틀렸는지 기억해야 하는 부담이 생김
  • 영어에서 자주 틀리는 단어를 피함 (calender, recieve 등)
  • 대소문자만으로 이름을 구별하지 않음 (frd/FRD/Frd)
  • 여러 자연어를 섞지 않음. 프로젝트에서 하나의 자연어(그리고 하나의 영어 변형)로 표준화함
  • 표준 형, 변수, 루틴의 이름을 피함 (if if = then then은 PL/I에서 합법이지만 미친 짓임)
  • 변수와 전혀 무관한 이름을 피함 (margaret, pookie). 프로그램이 정말 여자친구에 관한 것이라도 girlfriend 같은 일반 이름이 나음
  • 구별하기 어려운 문자를 피함: (1, l), (1, I), (0, O), (2, Z), (5, S), (6, G) 등. 1970년대 Fortran FORMAT 문에서 마침표 대신 쉼표를 써서 16억 달러짜리 우주 탐사선을 잃은 사례가 있음

체크리스트: 변수 이름 짓기

일반 명명 고려 사항

  • 이름이 변수가 나타내는 것을 완전하고 정확하게 설명하는가?
  • 이름이 프로그래밍 언어의 해법이 아니라 실제 문제를 가리키는가?
  • 이름이 고민하지 않아도 될 만큼 충분히 긴가?
  • 계산된 값 한정자가 이름 끝에 있는가?
  • Num 대신 Count나 Index를 사용하는가?

특정 데이터형 이름 짓기

  • 루프가 한두 줄을 넘거나 중첩됐다면 인덱스 이름이 i, j, k보다 의미 있는가?
  • 모든 “임시” 변수가 더 의미 있는 이름으로 바뀌었는가?
  • 불린 변수는 참일 때의 의미가 명확한가?
  • 열거형 이름에 Color_ 같은 범주 접두어나 접미어가 있는가?
  • 상수 이름이 숫자가 아니라 추상적 개념을 나타내는가?

명명 규칙

  • 규칙이 지역, 클래스, 전역 데이터를 구분하는가?
  • 규칙이 형 이름, 상수, 열거형, 변수를 구분하는가?
  • 언어가 강제하지 않는 경우 입력 전용 매개변수를 식별하는가?
  • 언어의 표준 규칙과 최대한 호환되는가?
  • 이름이 가독성을 위해 형식화되어 있는가?

짧은 이름

  • 코드가 (꼭 필요한 경우가 아니면) 긴 이름을 사용하는가?
  • 한 글자만 아끼는 약어를 피하는가?
  • 모든 단어가 일관되게 축약되는가?
  • 이름을 발음할 수 있는가?
  • 잘못 읽히거나 잘못 발음될 이름을 피했는가?
  • 짧은 이름이 번역 표에 문서화되어 있는가?

흔한 명명 문제: 다음을 피했는가

  • 오해를 부르는 이름
  • 의미가 비슷한 이름
  • 한두 글자만 다른 이름
  • 발음이 비슷한 이름
  • 숫자가 들어간 이름
  • 짧게 만들려고 일부러 틀리게 쓴 이름
  • 영어에서 자주 틀리는 단어
  • 표준 라이브러리 루틴이나 예약어와 충돌하는 이름
  • 완전히 임의적인 이름
  • 읽기 어려운 문자

요점 정리

  • 좋은 변수 이름은 프로그램 가독성의 핵심 요소다. 루프 인덱스나 상태 변수 같은 특정 종류의 변수는 별도의 고려가 필요하다.
  • 이름은 가능한 한 구체적이어야 한다. 여러 목적으로 쓸 수 있을 만큼 모호하거나 일반적인 이름은 대개 나쁜 이름이다.
  • 명명 규칙은 지역, 클래스, 전역 데이터를 구분하고 형 이름, 상수, 열거형, 변수를 구분한다.
  • 어떤 프로젝트든 변수 명명 규칙을 채택해야 한다. 규칙의 종류는 프로그램 크기와 참여 인원에 따라 정한다.
  • 현대 언어에서 약어는 거의 필요 없다. 약어를 쓴다면 프로젝트 사전에 기록하거나 표준화된 접두어 방식을 사용한다.
  • 코드는 쓰는 횟수보다 읽는 횟수가 훨씬 많다. 작성 편의보다 읽기 편의를 우선하는 이름을 선택한다.

results matching ""

    No results matching ""