11장: 변수 이름의 기능
11장: 변수 이름의 기능
- 좋은 이름 짓기는 중요한 주제인데도 대부분의 책은 몇 문단으로 넘어감. 이 장은 반대로 좋은 이름에 관한 수십 가지 고려 사항을 다룸
- 지침은 주로 변수(객체와 기본 데이터) 이름에 적용되지만 클래스, 패키지, 파일 등 다른 프로그래밍 요소에도 적용됨
11.1 좋은 이름을 선택하기 위한 고려 사항
- 변수와 변수 이름은 본질적으로 같은 것임. 변수의 좋고 나쁨은 이름이 크게 좌우함
x = x - xx같은 코드는 무엇을 하는지 알 수 없지만,balance = balance - lastPayment는 바로 읽힘- 좋은 변수 이름은 읽기 쉽고, 기억하기 쉽고, 적절함
가장 중요한 명명 고려 사항
- 이름이 변수가 나타내는 대상을 완전하고 정확하게 설명해야 함
- 변수가 나타내는 것을 말로 표현해 보면, 그 표현 자체가 종종 최선의 이름임
- 이자율은
r이나x보다rate나interestRate가 나음 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같은 한정자는 이름 끝에 붙임- 의미의 핵심이 앞에 오고,
totalRevenue와revenueTotal을 혼용하는 혼란을 막고,revenueTotal/expenseTotal/revenueAverage같은 대칭성이 생김 - 예외는
Num인데, 앞에 붙으면 총계(numCustomers), 뒤에 붙으면 인덱스(customerNum)를 뜻해 혼란스러움 - 총계에는
Count나Total, 특정 항목에는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 비형식적인 이름 규약
언어 독립적 규칙 지침
- 변수 이름과 루틴 이름을 구분함 (예:
variableNamevsRoutineName()) - 클래스와 객체(형과 변수)를 구분함: 첫 글자 대문자화(
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같은 발음식 약어는 개인 번호판 해독 같아서 권장하지 않음- 한 글자만 빼는 약어는 만들지 않음. 절약은 미미하고 어떻게 줄였는지 기억하기 어려움
- 일관되게 약어를 사용함.
Num과No를 혼용하지 않고, 어떤 곳은 전체 단어·어떤 곳은 약어로 쓰지 않음 - 발음할 수 있는 이름을 만듦. 전화로 코드를 읽어줄 수 없다면 이름을 바꿈(전화 테스트)
- 잘못 읽히는 조합을 피함.
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_ 같은 범주 접두어나 접미어가 있는가?
- 상수 이름이 숫자가 아니라 추상적 개념을 나타내는가?
명명 규칙
- 규칙이 지역, 클래스, 전역 데이터를 구분하는가?
- 규칙이 형 이름, 상수, 열거형, 변수를 구분하는가?
- 언어가 강제하지 않는 경우 입력 전용 매개변수를 식별하는가?
- 언어의 표준 규칙과 최대한 호환되는가?
- 이름이 가독성을 위해 형식화되어 있는가?
짧은 이름
- 코드가 (꼭 필요한 경우가 아니면) 긴 이름을 사용하는가?
- 한 글자만 아끼는 약어를 피하는가?
- 모든 단어가 일관되게 축약되는가?
- 이름을 발음할 수 있는가?
- 잘못 읽히거나 잘못 발음될 이름을 피했는가?
- 짧은 이름이 번역 표에 문서화되어 있는가?
흔한 명명 문제: 다음을 피했는가
- 오해를 부르는 이름
- 의미가 비슷한 이름
- 한두 글자만 다른 이름
- 발음이 비슷한 이름
- 숫자가 들어간 이름
- 짧게 만들려고 일부러 틀리게 쓴 이름
- 영어에서 자주 틀리는 단어
- 표준 라이브러리 루틴이나 예약어와 충돌하는 이름
- 완전히 임의적인 이름
- 읽기 어려운 문자
요점 정리
- 좋은 변수 이름은 프로그램 가독성의 핵심 요소다. 루프 인덱스나 상태 변수 같은 특정 종류의 변수는 별도의 고려가 필요하다.
- 이름은 가능한 한 구체적이어야 한다. 여러 목적으로 쓸 수 있을 만큼 모호하거나 일반적인 이름은 대개 나쁜 이름이다.
- 명명 규칙은 지역, 클래스, 전역 데이터를 구분하고 형 이름, 상수, 열거형, 변수를 구분한다.
- 어떤 프로젝트든 변수 명명 규칙을 채택해야 한다. 규칙의 종류는 프로그램 크기와 참여 인원에 따라 정한다.
- 현대 언어에서 약어는 거의 필요 없다. 약어를 쓴다면 프로젝트 사전에 기록하거나 표준화된 접두어 방식을 사용한다.
- 코드는 쓰는 횟수보다 읽는 횟수가 훨씬 많다. 작성 편의보다 읽기 편의를 우선하는 이름을 선택한다.