#acl +All:read = NamesAsDesign = ''주니어 개발자들을 위한 패턴 언어 - 네이밍을 설계 활동으로 다루어 개념을 명확히 하는 방법'' <> == 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