개발자에게 가장 어려운 일 중 하나는 단연 이름 짓기(Naming)일 것이다.
코드를 작성하다 보면 로직을 짜는 시간보다 변수나 함수 이름을 고민하는 데 더 많은 시간을 쏟곤 한다.
”이게 최선일까?” 고민하다 결국 모호한 이름을 짓고, 나중에 다시 코드를 볼 때 후회한 적이 한 번쯤은 있을 것이다.
좋은 이름은 코드를 읽는 동료(그리고 미래의 나)에게 명확한 이정표가 된다. 그렇다면 좋은 이름의 구체적인 기준은 무엇일까?
좋은 이름의 5가지 원칙: SMART
이름이 좋은지 나쁜지는 감으로 판단하기 쉽다. 하지만 감각은 사람마다 다르고, 시간이 지나면 쉽게 흔들린다. 그래서 이름을 지을 때는 객관적으로 점검할 수 있는 기준이 필요하다.
그럴 때 도움이 되는 기준이 SMART다. 이 기준은 완벽한 이름이 아니라, 협업과 유지보수에 유리한 이름인지를 판단하기 위한 체크리스트에 가깝다.
- Search (검색하기 쉬운가?)
- Mix (조합하기 좋은가?)
- Agree (수긍할 수 있는가?)
- Remember (기억하기 쉬운가?)
- Type (입력하기 쉬운가?)
각 원칙을 구체적인 예시와 함께 살펴보자.
Search: 검색하기 쉽게
좋은 이름은 IDE에서 검색했을 때 의미 있는 결과만 나온다. 프로젝트 규모가 커질수록 특정 상수나 변수를 찾아야 할 일이 많아진다. 이때 상위 범주를 접두사(Prefix)로 사용하면 검색 효율이 획기적으로 높아진다.
반대로, 너무 일반적인 이름은 검색을 방해한다. 일반적인 이름은 프로젝트 전체에서 수십 개가 검색될 가능성이 높다. 이 경우, 특정 로직을 찾기 위해 불필요한 파일을 계속 열어보게 된다.
검색하기 쉬운 이름이란, 프로젝트 내에서 역할이 고유하게 드러나고 다른 맥락과 충돌하지 않는 이름이다. 이름 하나가 곧 탐색 비용을 결정한다.
나쁜 예
public static final int TIMEOUT = 5000;
public static final int NO_RESULT = -1;
public static final int BAD_REQUEST = 400;
TIMEOUT이나 NO_RESULT는 너무 일반적인 단어라 검색 결과가 너무 많이 나올 수 있다.
좋은 예
public static final int ERROR_SERVER_TIMEOUT = 5000;
public static final int ERROR_NO_RESULT = -1;
public static final int ERROR_BAD_REQUEST = 400;
ERROR_라는 접두사를 사용하면, IDE에서 ERROR_만 검색해도 프로젝트의 모든 에러 상수를 한눈에 파악할 수 있다.
Mix: 조합하기 쉽게
개발 언어는 문법적 특성상 여러 단어를 조합해 사용하는 경우가 많다.
좋은 이름은 다른 개념과 자연스럽게 결합된다.
클래스, 메서드, 변수 이름은 혼자 존재하지 않고 항상 문맥 속에서 읽힌다.
이름을 이어서 읽었을 때 문장이 어색하지 않다면,
그 이름은 조합에 강하다.
반대로, 이름이 너무 추상적이거나 감정적인 경우
다른 단어와 붙을 때 의미가 흐려진다.
조합이 잘 된다는 것은
확장되었을 때도 이름이 무너지지 않는다는 뜻이다.
나쁜 예
public class User {
private String name; // User.name (O) but...
}
public class Order {
private String name; // Order.name (O)
}
단순히 name이라고만 하면, 로컬 변수나 매개변수로 사용될 때 어떤 객체의 이름인지 혼동될 수 있다.
좋은 예
public class User {
private String userName;
}
public class Order {
private String orderName;
}
userName, orderName처럼 구체적인 맥락을 포함하면, 다른 변수와 섞여 있어도 그 출처와 의미가 명확해진다.
Agree: 수긍하기 쉽게
좋은 이름은 설명이 필요 없다. 혹은, 설명하더라도 대부분의 사람이 고개를 끄덕인다.
이 원칙은 개인의 취향보다 팀의 합의를 더 중요하게 본다.
도메인 용어와 맞는가?
비즈니스 담당자가 들어도 납득할 수 있는가?
팀 내에서 같은 단어를 다른 의미로 쓰고 있지는 않은가?
이름은 개인의 창작물이 아니라
팀의 공용 언어다.
나쁜 예
public class Papago {
// 번역 기능 담당? 특정 제품명을 클래스 이름으로?
}
Papago는 특정 서비스의 이름이지, 기능 자체를 설명하지 못한다. 나중에 번역 엔진이 바뀌면 이름도 바꿔야 할까?
좋은 예
public class TranslationService {
// 누가 봐도 번역 서비스를 담당하는 클래스
}
TranslationService는 구현체가 무엇이든 번역을 담당한다는 역할이 명확하다.
Remember: 기억하기 쉽게
좋은 이름은 다시 보지 않아도 떠오른다.
기억하기 어렵다는 것은, 그만큼 맥락 의존적이라는 뜻이다.
약어가 과도하거나, 발음이 애매하거나 의미를 유추하기 어려운 조합이라면 코드를 읽을 때마다 “이게 뭐였지?”라는 생각이 든다.
기억하기 쉬운 이름은 발음이 자연스럽고 의미가 한 방향으로 수렴된다.
이는 신규 인원이 합류했을 때 특히 큰 차이를 만든다.
나쁜 예
public class XYZZY {
// 로그인 기능... 그런데 이름이 왜 이러죠?
}
발음하기도 어렵고 의미도 알 수 없는 이름은 기억 속에 남지 않는다.
좋은 예
public class LoginManager {
// 로그인 관리자. 직관적이고 외우기 쉽다.
}
Manager, Service, Controller 같은 접미사는 역할에 대한 힌트를 준다.
Type: 입력하기 쉽게
의외로 자주 무시되지만, 현실적인 기준이다.
이름은 생각보다 많이 타이핑된다.
너무 길지는 않은가?
비슷한 철자가 반복되지는 않는가?
대소문자 구분이 과도하지는 않은가?
입력하기 어려운 이름은
오타를 만들고, 자동 완성을 강요하고, 리듬을 끊는다.
타이핑이 편하다는 것은
코드를 쓰는 흐름을 방해하지 않는다는 의미다.
나쁜 예
public class SuperUltraComplicatedDataProcessingFactoryManager {
// 치다가 지친다. 오타 날 확률 99%
}
좋은 예
public class DataProcessor {
// 깔끔하고 입력하기도 편하다.
}
핵심 의미만 담아 간결하게 줄인다. IDE의 자동 완성 기능이 있더라도 짧은 이름이 읽기에도 편하다.
마치며
좋은 이름은 코드를 설명하는 가장 강력한 주석이자, 동료를 배려하는 최고의 매너다.
우리가 작성하는 코드는 컴퓨터가 실행하지만, 그 코드를 읽고 유지보수하는 것은 결국 사람이다. 지금 당장 5분을 더. 투자해 고민한 변수명이, 미래의 나 혹은 동료의 1시간을 아껴줄 수 있다.
SMART는 절대적인 규칙은 아니다. 하지만 이름을 지을 때 이 다섯 가지를 하나씩 점검해보면, “이름이 마음에 드는가?”가 아니라 “이 이름이 살아남을 수 있는가?” 라는 질문을 던지게 된다. 한 번 더 자문해보는 태도만으로도 충분하다.
오늘 작성하는 코드에서 모호한 변수 하나를 찾아, 더 명확한 이름으로 바꿔보는 건 어떨까? 처음엔 조금 귀찮을지 몰라도, 그 작은 시도가 미래의 동료들이 여러분에게 감사할 것이다.