NamesAsDesign
주니어 개발자들을 위한 패턴 언어 - 네이밍을 설계 활동으로 다루어 개념을 명확히 하는 방법
Contents
The Story 1: The Search for the Right Name (Programming)
주니어 개발자 민수는 주문 처리 시스템을 작성하고 있었다. 그는 변수 이름을 짓다가 막혔다.
def process(data):
x = data['items']
y = 0
for i in x:
y += i['price'] * i['qty']
return y"이건 너무 못생겼어..." 민수는 생각했다. 30분 동안 고민한 끝에 이름을 아주 길게 고쳤다. calculate_order_total_amount_including_all_items(order_data). 하지만 코드 리뷰에서 하나가 말했다.
"민수님, 명확함은 길이가 아니라 문맥에서 나와요. 봐요."
class Order:
def total(self):
return sum(item.subtotal() for item in self.items)
class Item:
def subtotal(self):
return self.price * self.quantity
# 사용할 때
order = Order(...)
payment.charge(order.total())"봐요, order.total()이라고 쓰면 Order의 total이라는 게 명확하죠? 문맥이 이름을 완성하는 거예요. 그리고 Item.subtotal()은 Item의 소계라는 게 바로 보이지요? 이름은 혼자 존재하는 게 아니라 관계 속에서 의미를 갖는 거예요. 이름 짓기는 단순히 라벨을 붙이는 게 아니라, 좋은 설계를 반영하는 설계 활동 그 자체입니다."
The Story 2: The Baby's Name (Ordinary Life)
민수와 하나는 곧 태어날 아기의 이름을 고민하고 있다.
민수의 작명 (The Functional Name): 민수는 실용적인 이름을 원한다. "우리 첫째니까 그냥 '민수 주니어 1호'라고 부르면 어때? 누가 봐도 내 아들인 걸 알 수 있잖아." 민수에게 이름은 단순히 대상을 식별하기 위한 라벨일 뿐이었다. 하지만 '1호'라는 이름은 아이의 개성이나 가족 안에서의 정체성을 전혀 담아내지 못했다.
하나의 작명 (The Design Name): 하나는 이름이 아이의 삶을 설계하는 첫 번째 단추라고 생각한다. "아이의 이름은 성(Last name)과 조화로워야 하고, 나중에 자라서 사회에서 불릴 때의 느낌도 고려해야 해." 하나는 아이가 평생 불릴 문맥을 상상하며 이름을 골랐다. "밝게 빛나라는 뜻의 '윤(潤)'을 넣자. 우리 가족의 따뜻한 분위기와도 잘 어울려." 이름이 정해지자 아이의 방을 어떻게 꾸밀지, 어떤 옷을 입힐지 같은 '설계'가 자연스럽게 뒤따랐다. 이름은 단순한 라벨이 아니라, 존재의 본질을 규정하는 설계의 시작임을 하나는 알고 있었다.
Context
당신은 코드를 작성하면서 변수, 함수, 클래스, 모듈에 이름을 붙여야 한다. 이름은 코드의 모든 곳에 있고, 코드를 읽는 사람이 가장 먼저 보는 것이다.
당신은 LanguageBuilding을 통해 도메인 언어를 만드는 것의 중요성을 알고, MetaphorThinking을 통해 은유가 이해를 돕는다는 것을 안다. 이제 그 언어를 구성하는 단어 하나하나를 만드는 단계다.
일상적인 상황:
변수 이름을 data, temp, x 같은 일반적 이름으로 짓는다.
함수 이름을 너무 길게 만든다 (calculateOrderTotalAmountIncludingTax).
같은 개념을 여러 이름으로 부른다 (user / customer / account).
- 이름을 짓는 데 과도한 시간을 쓰거나, 거의 생각 없이 짓는다.
Problem
초보 프로그래머는 네이밍을 단순한 라벨링으로 취급한다. 어떤 이는 너무 빨리 못생긴 이름을 붙이고, 어떤 이는 오래 고민하지만 결과는 여전히 좋지 않다.
The Naming Dichotomy
주니어는 두 극단 사이를 오간다:
너무 빠른 네이밍: f(x), y = x['a'] 처럼 빠르지만 의미 없는 이름을 붙인다. 1주일 후 자신도 이해하지 못한다.
너무 긴 네이밍: calculate_total_amount_of_order_including_all_line_items() 처럼 명확하려 했지만 장황하고 읽기 어려운 이름을 만든다.
The Fundamental Misunderstanding
Phil Karlton은 "컴퓨터 과학에서 어려운 것은 딱 두 가지뿐이다. 캐시 무효화와 이름 짓기"라고 했다. 왜 네이밍이 어려운가?
잘못된 믿음: "좋은 이름은 그 자체로 명확해야 한다", "길고 자세할수록 좋다."
진실: 이름 자체로는 좋고 나쁨을 판단할 수 없다. 문맥에 embedding되었을 때 평가할 수 있다. 관계 속에서 의미가 만들어지기 때문이다.
The Isolation Problem
주니어는 이름을 고립되어 생각한다. 하지만 이름은 관계망 속에 존재한다. order.total()이라고 쓰면 'Order'라는 부모가 문맥을 제공하기 때문에 짧은 이름으로도 충분히 명확해진다. 이름의 품질은 부모, 형제, 자식과의 관계 속에서 결정된다.
The Surface of Design
이름은 설계의 표면이다. 나쁜 이름은 종종 나쁜 설계를 반영한다. 이름 짓기가 어렵다는 것은 개념이 불명확하거나, 책임이 잘못 분배되었거나, 추상화가 잘못되었다는 신호다.
Name as Concept
이름은 단순한 라벨이 아니라 개념 그 자체다. items를 shopping_cart라고 부르는 순간, 단순한 리스트가 쇼핑이라는 맥락을 가진 개념으로 변한다. 이름을 바꾸면 생각이 바뀐다.
Names vs Documentation
좋은 이름은 주석보다 가치 있다. "Clean code is when each function does pretty much what you expected." (Ward Cunningham). 그 예상을 만드는 것이 바로 이름이다.
Solution
네이밍을 사고를 명확하게 하고 추상화를 드러내는 설계 활동으로 다뤄라. 좋은 이름은 문맥 속에서 평가되고, 관계 속에서 의미를 갖는다. 이름은 개념이고, 좋은 이름은 좋은 설계를 반영한다.
Principle 1: Names in Context (Embedding)
이름은 고립되어 평가할 수 없다. 문맥에 embedding하여 평가하라.
Small Context (함수 내부): 짧은 스코프에서는 total, items 처럼 짧은 이름이 명확하다.
Large Context (클래스, 모듈): Order.total() 처럼 클래스 이름이 문맥을 제공할 때 메서드 이름은 간결해질 수 있다.
Principle 2: Relational Quality (Playing Along)
좋은 이름은 "잘 어울린다" - 형제, 부모, 자식과 조화롭게.
Siblings (형제 관계): 같은 레벨의 이름들은 일관된 패턴을 따라야 한다 (name(), age(), email()).
Parent-Child (부모-자식 관계): 부모와 자식이 조화로워야 한다. OrderCalculator.calculate_order_total()은 중복이다. Order.total()이 더 자연스럽다.
Principle 3: Two Spaces - Problem and Solution
TwoWorlds를 기억하라. 좋은 이름은 문제 공간과 해결 공간을 모두 잘 표현한다.
Problem Space Names (도메인 언어): Order.place(), Customer.purchase() 처럼 비즈니스 전문가와 공유하는 보편 언어(Ubiquitous Language)를 사용하라.
Solution Space Names (기술 언어): OrderRepository, EventBus 처럼 기술적 패턴은 기술 용어로 표현하라.
Principle 4: Name as Concept (Conceptualization)
이름 짓기는 개념화하기다. 명확한 이름 = 명확한 개념. 이름을 찾는 과정은 개념을 발견하는 과정이다. data -> user_data -> user_profile로 이름이 명확해지는 과정은 설계가 정교해지는 과정과 일치한다.
Principle 5: Names > Documentation
좋은 이름은 주석을 불필요하게 만든다. "The proper use of comments is to compensate for our failure to express ourselves in code." (Robert C. Martin). 이름으로 표현하지 못해서 주석을 쓰는 것이다.
Principle 6: Metaphor and Analogy
MetaphorThinking - 좋은 은유는 좋은 이름을 만든다. Stack.push(), Queue.enqueue(), Stream.flush() 처럼 은유가 직관적 이해를 돕는다.
Principle 7: Semantic Network
LanguageBuilding - 이름들은 의미 네트워크를 형성한다. total, subtotal, tax - 이 단어들은 서로 관계를 형성하며 하나를 보면 다른 것을 예상할 수 있게 한다.
Real Examples
Example 1: From Generic to Specific
process(data) -> process_numbers(numbers) -> double_prices(prices) -> apply_inflation(prices). 각 단계마다 개념이 명확해진다.
Example 2: Context Makes Meaning
같은 size()라도 File.size()는 바이트 크기, Shirt.size()는 "M", "L", List.size()는 원소 개수를 의미한다. 문맥이 의미를 만든다.
Example 3: Siblings Harmony
UserRepository의 create, read, update, delete 처럼 일관된 패턴은 예측 가능성을 만든다.
Example 4: Real Naming Session
엉성한 func(x, y) 로직을 find_passing_students(scores, 60)로 리팩토링하는 과정은 이름이 진화하면서 설계가 개선되는 전형적인 모습이다.
Example 5: Metaphor Power
Factory(공장), Builder(건축가), Observer(관찰자) 등 디자인 패턴의 이름은 은유를 통해 복잡한 설계를 한 번에 이해시킨다.
Example 6: Names Reveal Design Issues
UserManagerControllerHandlerService 처럼 이름 짓기가 어렵다면, 그것은 클래스가 너무 많은 일을 하고 있다는 설계적 결함의 신호다.
The Naming Process
Process 1: Start Concrete, Then Abstract
일반적인 것부터 시작하지 마라. prices -> doubled_prices 처럼 구체적인 것부터 시작하라.
Process 2: Let Context Emerge
이름을 먼저 짓지 마라. WorkingFirst 원칙에 따라 일단 작동하게 만들고, 사용 문맥 속에서 더 나은 이름을 발견하라.
Process 3: Refactor Names
이해도가 깊어지면 이름도 리팩토링하라. LivingVocabulary 패턴에 따라 어휘를 지속적으로 정제하라.
Process 4: Read Aloud Test
이름을 소리 내어 읽어보라. "Order야, total 해줘"가 자연스러운지 확인하라.
Process 5: Consistency Check
비슷한 개념은 비슷한 패턴으로 명명하여 일관성을 확인하라.
Common Pitfalls
Pitfall 1: Premature Long Names
명확하려다 장황해지는 것. 문맥을 활용하여 길이를 줄여라.
Pitfall 2: Abbreviations
proc_usr_ord 처럼 이해를 방해하는 약어를 피하라. 보편적인 약어(id, url)만 허용하라.
Pitfall 3: Inconsistent Vocabulary
User, Customer, Client를 혼용하지 마라. 하나의 개념은 하나의 이름으로 통일하라.
Pitfall 4: Type in Name
strName, arrUsers 처럼 타입 정보를 이름에 넣지 마라. 의미에 집중하라.
Pitfall 5: Noise Words
Manager, Processor, Data 처럼 의미 없는 단어(소음)를 제거하라.
Pitfall 6: Naming in Isolation
문맥 없이 이름을 평가하지 마라. get()이 좋은 이름인지는 그것이 어디에 속해 있느냐에 달렸다.
Connection to Other Patterns
LanguageBuilding - 이름은 언어의 단어입니다. 좋은 이름이 모여 좋은 언어를 만듭니다. 필수 관계
MetaphorThinking - 은유와 비유가 직관적인 이름을 만듭니다. 인지적 도구
TwoWorlds - 문제 공간과 해결 공간을 모두 잘 표현하는 이름이 필요합니다. 균형
DataAsFoundation - 데이터 구조의 이름이 전체 설계의 기반이 됩니다. 기반
WorkingFirst - 처음부터 완벽한 이름을 찾기보다 작동하는 코드에서 이름을 발견하십시오. 순서
LivingVocabulary - 이름은 고정된 것이 아니라 이해가 깊어짐에 따라 진화합니다. 성장
ArtisanMind - 이름을 짓는 것은 논리보다 뉘앙스가 중요한 장인의 기예입니다. 기예
Signs of Success
- 주석이 줄어들고 코드가 스스로 말한다.
- 새로운 팀원이 코드베이스를 읽는 것만으로도 비즈니스 로직을 빠르게 파악한다.
- 이름을 바꾸었을 뿐인데 클래스의 책임이 더 명확해지고 설계가 개선된다.
- 도메인 전문가와 대화할 때 코드의 이름을 그대로 사용할 수 있다.
The Ultimate Insight
이름은 코드의 가장 중요한 문서이며, 설계의 표면이자 개념 그 자체입니다.
이름을 짓는 것은 단순한 라벨링이 아니라, 당신의 사유를 정제하는 설계 활동입니다. 좋은 이름을 찾기 어렵다면 설계를 다시 보십시오. 이름을 설계하십시오. 그러면 코드가 스스로 당신에게 진실을 말할 것입니다.
CategoryPatternLanguage CategoryProgramming CategoryDesign CategoryNaming CategoryCleanCode
