Skip to content

Instantly share code, notes, and snippets.

@guersam
Created May 8, 2026 05:08
Show Gist options
  • Select an option

  • Save guersam/b60f2eef6723c6b393c0d0b610e29043 to your computer and use it in GitHub Desktop.

Select an option

Save guersam/b60f2eef6723c6b393c0d0b610e29043 to your computer and use it in GitHub Desktop.
이름짓기: 왜 중요하고, 왜 어렵고, 어떻게 잘 지을 것인가

이름짓기: 왜 중요하고, 왜 어렵고, 어떻게 잘 지을 것인가

도입 — 군대의 그 질문

"너네 집 어디야?" "서울입니다." "서울이 다 니네 집이냐?" "○○동입니다." "거기가 어딘지 내가 어떻게 알아."

이 잘 알려진 군대식 말장난은 표면적으로 보면 추상화 수준의 문제다. "서울"은 너무 넓어서 정보가 부족하고, "○○동"은 너무 좁아서 맥락이 부족하다. 적절한 답은 "서울 강남구 역삼동" 정도일 것이다. 듣는 사람이 이해할 수 있는 수준에서 충분히 구체적인 답이다.

프로그래밍에서의 이름짓기도 이와 비슷하다. 다만 이 비유에는 표면 너머의 층이 하나 더 있다. 그 이야기는 마지막에 다시 다룬다.


왜 중요하고, 왜 어려운가

이름은 의미 덩어리이자 해석의 틀이다

코드는 쓰는 시간보다 읽는 시간이 압도적으로 길다. 이름은 작성자의 머릿속 모델을 독자에게 전달하는 거의 유일한 통로다.

Gary Klein의 RPD(Recognition-Primed Decision) 모델은 전문가가 개별 요소가 아니라 이미 형성된 의미 덩어리(chunk)로 상황을 인지한다는 점을 보여준다. 화재 현장에서 경험 많은 소방관이 "지붕이 이상하다"고 직감하는 것은 수많은 단서를 하나의 의미 덩어리로 묶고, 그것을 장기기억 속 패턴과 맞추기 때문이다.

Klein의 Data/Frame 모델은 한 걸음 더 나아간다. 데이터는 해석의 틀(frame)을 통해서만 의미를 갖고, 그 틀은 새로 들어오는 데이터에 의해 다시 조정된다.

좋은 이름은 다음 두 가지를 동시에 한다.

  • 독자의 장기기억 속 의미 단위와 즉시 맞물려, 추가 인지 비용 없이 의미가 떠오르게 한다.
  • 새로 읽는 코드의 해석 틀이 되어, 이후 마주칠 세부를 이해하는 렌즈 역할을 한다.

나쁜 이름이 비싼 이유는 이 두 가지를 하지 못하기 때문이다. data, manager, handler, info 같은 이름은 의미 단위가 너무 추상적이다. 반대로 tmp_x37 같은 이름은 해석의 틀을 제공하지 못한다. 결국 독자는 매번 코드를 다시 읽어야 한다. 이름이 해야 할 일을 하지 않으면, 그 일은 사람이 대신하게 된다.

듣는 사람에 따라 알맞은 층이 다르다

Eleanor Rosch가 1970년대에 제시한 기본 수준 범주(basic-level categories)는 "가구 → 의자 → 흔들의자"의 위계에서 사람이 가장 자연스럽게 부르는 이름이 대체로 "의자"라는 점을 보여준다. 이 층은 같은 범주 안의 유사성과 다른 범주와의 차이를 동시에 크게 만드는, 인지적으로 특별한 위치다.

여기에 이름짓기에 중요한 후속 발견이 있다. Tanaka와 Taylor(1991)는 전문가의 기본 수준이 한 층 아래로 내려간다는 점을 보였다. 비전문가에게는 "참새"가 한 단계 더 구체적인 이름이지만, 조류학자에게는 그것이 기본 층이 된다. 결국 적절한 이름의 층은 두 가지에 달려 있다. 듣는 사람이 누구인지, 그리고 그들의 의미 단위 구조가 어디까지 내려가 있는지다.

라이브러리 내부 헬퍼와 비즈니스 로직에서 알맞은 이름이 다른 이유도 여기에 있다. 같은 함수 이름이 신입 개발자에게는 너무 구체적으로 보이고, 시니어 개발자에게는 너무 추상적으로 보일 수 있는 이유도 마찬가지다.

여러 제약을 한꺼번에 풀어야 한다

이름짓기가 어려운 진짜 이유는 다음 제약을 동시에 풀어야 하기 때문이다.

  • 이름의 종류: 지역 변수, 전역 변수, 클래스, 함수, 도메인 객체, 운영 자원, 프로젝트명은 각각 좋은 이름의 기준이 다르다.
  • 단어 순서: getUserById인가, getByIdUser인가. 어느 분류 축이 먼저 와야 자연스럽게 읽히고 정렬되는가.
  • 주변과의 일관성: 같은 네임스페이스에 find*로 시작하는 형제들이 있다면 새 이름도 find*여야 한다. 혼자 get*으로 벗어나면 안 된다.
  • 추상화 수준의 일치: 함수 이름은 그 함수가 호출하는 다른 함수들과 같은 추상화 층에 있어야 한다.

좋은 이름을 한 번에 떠올리는 것은 보통 불가능하다. 실제로는 후보 어휘를 나열하고, 재정렬하고, 도메인 어휘로 치환하는 작업이 동시에 일어난다. 코드 작성 중에 이 일이 함께 일어나면 어려운 일을 두 가지 한꺼번에 하는 셈이다. 그래서 이름짓기가 막힌다. TDD가 빨간불, 초록불, 리팩터링으로 단계를 분리하듯, 이름짓기에도 같은 분리가 필요하다.


방법론

이 절은 한 번 읽고 끝내는 설명이 아니다. 자기 분야에 적용할 때 다시 펼쳐 보는 참고 자료에 가깝다. 각 방법론이 무엇을 처방하는지, 왜 그 방식이 작동하는지, 자기 도메인에 어떻게 옮겨 적용할 수 있는지를 정리한다.

분류학적 시스템 — 이름은 부분으로 합성된다

Ranganathan의 PMEST, IUPAC nomenclature, Linnaean binomial이라는 세 가지 명명법은 공통적으로 한 가지를 보여준다. 좋은 이름 시스템은 작은 의미 단위의 합성으로 만들어진다. 합성 규칙이 정해져 있으면 어휘가 재사용되고, 독자는 새 이름의 의미를 추론할 수 있다.

S. R. Ranganathan(1933)의 faceted classification은 PMEST(Personality–Matter–Energy–Space–Time)라는 다섯 분류 축(facet)과 배열 순서(citation order)를 제안했다. 하나의 대상을 여러 분류 축의 조합으로 보고, 어떤 축을 먼저 배치하느냐가 검색, 정렬, 인지의 방식을 결정한다는 뜻이다. 코드에서 getUserByIdgetByIdUser보다 자연스러운 이유, 운영 자원 이름에서 prod-api-logs-us-east가 가장 큰 축인 환경부터 좁혀 가는 이유도 같은 원리다.

IUPAC nomenclature는 화학에서 접두사, 작용기, 골격 같은 작은 어휘 단위를 합성해 분자명을 만든다. 어휘를 알면 이름만 보고도 분자 구조를 거의 그릴 수 있다. 코드의 패턴 어휘인 Repository, Factory, Service, Adapter도 비슷하게 작동한다. Repository라는 말을 한 번 익히면 모든 *Repository 형태 클래스의 의미를 어느 정도 추론할 수 있다. 실패 방식도 분명하다. 공유 어휘 없이 합성하면 이름은 그저 길어질 뿐이다. 먼저 어휘에 대한 합의가 필요하다.

Linnaean binomial(Carl Linnaeus, 1735)은 genus(상위 카테고리)와 species(하위 한정자) 두 부분으로 구성된다. 상위는 이미 알려진 카테고리이고, 하위는 그 안에서의 차이다. 운영 명명에서 prod-api-payment-service처럼 여러 단계로 확장되는 이름도 이 구조의 자연스러운 연장이다.

자기 분야에 적용하려면 먼저 도메인의 분류 축을 식별해야 한다. 어떤 차원으로 사물이 나뉘는지 보는 것이다. 그다음 배열 순서를 정한다. 가장 안정적이고 가장 큰 단위가 앞에 와야 검색과 정렬에 유리하다. 작은 어휘에 합의하고, 새 이름은 그 어휘의 조합으로 만든다.

도메인 모델링 — 이름은 도메인을 따른다

Eric Evans의 Domain-Driven Design(2003)에서 나온 두 핵심 개념은 이름짓기에 매우 강력한 처방을 제공한다. 특히 비즈니스 로직과 도메인 객체에 잘 맞는다. 라이브러리 헬퍼나 인프라 코드에는 상대적으로 덜 적합하다. 그쪽에는 분류학적 시스템이 더 잘 작동한다.

Ubiquitous Language는 도메인 전문가와 개발자가 하나의 언어를 공유한다는 원칙이다. 회의에서 "endorsement"라고 부르는 것은 코드에서도 endorsement여야 한다. 번역 층이 생기는 순간 의미가 새기 시작한다. 비즈니스에서는 "고객"이라고 부르는데 코드에서는 User라고 부른다면, 두 개념이 어긋나는 순간 추적이 어려워진다. 운영 차원에서는 도메인 용어집을 만들고 코드와 함께 갱신해야 한다.

Bounded Context는 같은 단어가 맥락에 따라 다른 뜻을 가질 수 있다는 인식이다. "User"가 billing context에서는 청구 대상이고, support context에서는 문의자이며, auth context에서는 인증 주체일 수 있다. 한 시스템 안에서 "어디까지가 같은 의미인가"라는 경계를 명시하지 않으면 이름의 의미가 흔들린다. 경계를 가로지르는 통신에는 명시적인 번역이 필요하다.

이 활동은 Klein의 Cognitive Task Analysis(CTA)와 본질적으로 닮아 있다. 전문가의 의미 구조를 인터뷰와 관찰로 추출해 코드의 어휘로 옮기는 일이다. DDD의 "knowledge crunching"은 CTA의 다른 이름에 가깝다.

자기 분야에 적용할 때는 두 가지를 점검한다. 첫째, 자기 도메인에 합의된 용어집이 있는가. 없다면 만들어야 한다. 둘째, 같은 단어가 다른 의미로 쓰이는 자리가 있는가. 있다면 컨텍스트의 경계를 명시해야 한다.

실증 연구 — 직관은 자주 틀린다

이름짓기는 오랫동안 "취향"의 영역으로 다뤄졌다. 그러나 지난 15년 동안 학술 연구가 여러 직관을 검증하거나 반박해 왔다.

Felienne Hermans의 The Programmer's Brain(Manning, 2021)은 장기기억(LTM), 단기기억(STM), 작업기억(WM)이라는 인지 모델 위에서 코드 가독성에 대한 처방을 학술 연구로 뒷받침한다. 작업기억이 한 번에 2~6개의 의미 단위만 보유한다는 추정에서 출발해, 한 함수에 들어갈 수 있는 의미 단위 수와 이름이 의미 단위 인식을 돕는 방식을 정리한다. 저자는 이름 패턴(naming "moulds")이라는 용어로 자주 등장하는 형태들을 분류한다.

Hebrew University의 Dror Feitelson 그룹은 일련의 실험을 통해 변수명에 대한 정량적 데이터를 쌓아 왔다. Avidan과 Feitelson(2017)은 72명의 C# 개발자를 대상으로 letters, abbreviations, words 세 형태를 비교했다. 그 결과 단어 형태가 약어나 단일 문자보다 19% 빠른 이해를 보였다. Beniamini 등(2017)은 단일 문자 변수가 항상 나쁜 것은 아니며 스코프에 따라 달라진다는 점을 보였다. 좁은 스코프의 ix는 정당할 수 있지만, 넓은 스코프에서는 단어가 필요하다.

자기 분야에 적용할 때는 이름짓기에 대한 직관 중 한 번도 검증된 적 없거나 데이터와 어긋나는 것이 있는지 점검해야 한다. "긴 이름이 항상 좋다"거나 "짧을수록 깔끔하다"는 식의 양극단은 대개 스코프 의존이라는 사실 앞에서 무너진다.

사용자 중심 — 이름은 검증할 수 있다

코드 내부의 식별자는 작성자와 리뷰어가 맥락을 공유한다. 그러나 프로젝트명, 메뉴 라벨, Slack 채널명, 외부 API endpoint처럼 다수가 검색하고 식별하는 이름은 그렇지 않다. 작성자의 의미 단위와 사용자의 의미 단위가 어긋날 위험이 크다.

카드 소팅(Donna Spencer, Card Sorting, Rosenfeld Media, 2009)은 이 어긋남을 측정하는 도구다. 사용자에게 항목을 자유롭게 그룹화하고 이름을 붙이게 하면 사용자의 자연스러운 의미 단위를 추출할 수 있다. 작성자 한 명의 직관이 다수 사용자의 의미 단위와 얼마나 어긋나는지 데이터로 확인할 수 있다.

정보 아키텍처 라벨링(Peter Morville와 Louis Rosenfeld, Information Architecture, 4th ed., 2015)은 같은 문제에 더 넓은 도구 상자를 제공한다. 트리 테스팅, A/B 테스트, 검색 로그 분석 등이 여기에 속한다.

자기 분야에 적용할 때는 회사나 제품의 외부 노출 이름 중 사용자에게 한 번도 검증한 적 없는 것을 찾아본다. 전수 조사가 아니어도 5명 규모의 라벨 테스트나 30분짜리 카드 소팅으로 큰 어긋남은 잡을 수 있다. 이 방법은 외부 사용자나 폭넓은 내부 사용자가 마주치는 이름에 적합하다. 코드 내부 식별자에까지 적용하기에는 과하다.


실천 — 살피기, 짓기, 가꾸기

이름짓기 작업은 보통 세 국면으로 나뉜다. 어떤 어휘와 컨벤션이 이미 있는지 살피고, 그 위에서 후보를 짓고, 시간이 흐르는 동안 가꾼다. 살피기 없이 짓는 것은 바퀴를 다시 발명하는 일이고, 가꾸기 없이 짓는 것은 시간이 지나며 부패를 방치하는 일이다.

살피기 — 컨벤션의 4층

컨벤션 탐색은 하나의 층에만 있지 않다. 보통 네 층에 분포한다. 각 층은 다른 탐색 방법을 요구한다. 어느 층에서 찾아야 하는지 잘못 판단하면 답이 없는 것처럼 보인다.

1층은 중앙화된 명시적 컨벤션이다. 단일한 권위 출처가 있고, 검색하면 즉시 답이 나온다. OpenTelemetry semantic conventions, RFC 1034 DNS, PEP 8, IUPAC nomenclature가 여기에 속한다. 보통 30분 정도의 타임박스로 충분하다.

2층은 분산된 명시적 컨벤션이다. 여러 곳에 적혀 있지만 서로 모순되거나 맥락에 따라 달라진다. 예를 들어 git commit message의 imperative mood만 해도 cbea.ms는 권장하지만, Red Hat 스타일 가이드는 사용자 문서에서 피하라고 한다. REST API design이나 error message tone도 비슷하다. 여러 출처를 종합한 뒤 자기 컨텍스트에 가장 가까운 결을 채택해야 한다.

3층은 아티팩트에 숨어 있는 잠재 컨벤션이다. 어디에도 규칙으로 적혀 있지 않지만 기존 아티팩트를 충분히 읽으면 패턴이 보인다. 회사 코드베이스의 로그 메시지 스타일, 주석 밀도, 변수명의 추상화 층위 같은 것들이 여기에 속한다. 이때 필요한 것은 검색이 아니라 기존 아티팩트 50~100개를 의식적으로 훑고 패턴을 추출하는 작업이다.

4층은 언어와 문화에 숨어 있는 잠재 컨벤션이다. 모국어의 관습과 달라서 비원어민에게 잘 보이지 않는 영역이다. 영어 코드 문화의 전보식 표현이 정확히 이 층에 있다. "Connection refused", "User not found" 같은 형태가 압도적으로 흔하지만, 한국어 화자가 모국어 직관으로 영어 로그를 쓰면 "The connection has been refused" 같은 문장으로 바뀌기 쉽다. 한국어는 관사를 표시하지 않기 때문에 어긋남 자체가 잘 보이지 않는다. 단순히 코퍼스를 많이 읽는 것만으로는 부족하다. 자기 모국어가 표시하지 않는 특징에 의식적으로 주의를 기울여야 한다.

핵심은 단순하다. 검색으로 나오지 않는 컨벤션은 코퍼스에 있고, 코퍼스로도 잘 보이지 않는 컨벤션은 모국어와의 차이에 있다.

엉뚱한 층에서 찾는 것은 흔한 함정이다. 답이 3층이나 4층에 있는데 1층만 검색하고 "컨벤션 없음"으로 결론 내리는 식이다. 신입이 자주 빠지는 함정이기도 하다.

짓기 — Belshee 7단계와 보조 기법

Arlo Belshee가 정식화한 Naming as a Process는 한 이름의 진화를 7단계로 본다. 각 단계는 이전보다 더 나은 이름이며, 단계 전환은 작은 리팩터링이다.

  1. Missing: 이름 없음, 또는 tmp
  2. Nonsense: 의도적으로 무의미한 이름. applesauce, banana 같은 이름
  3. Honest: 코드가 실제 하는 일을 투박하더라도 정직하게 드러내는 이름. 예: parseXmlAndStoreFlightAndCacheAndAddToScreenIfVisible
  4. Honest and Complete: 빠진 동작 없이 모두 드러낸 이름
  5. Does the Right Thing: 단일 책임이 되도록 코드를 쪼갠 뒤, 그에 맞게 짧아진 이름
  6. Intent: "왜"를 표현하는 이름
  7. Domain Abstraction: 도메인 어휘로 추상화된 이름. 결과적으로 screen.add(flight) 같은 짧은 이름

핵심 통찰은 한 줄로 압축된다. 3단계인 Honest가 1단계인 Missing이나 그럴듯한 거짓 이름보다 훨씬 낫다. 보기 좋은 거짓 이름은 정직하지만 투박한 이름보다 위험하다. 사람이 그 이름을 믿고 구현을 읽지 않기 때문이다.

처방은 단순하다. 완벽한 이름을 한 번에 지으려 하지 않는다. 먼저 실제 동작을 정직하게 드러내는 투박한 이름을 붙인다. 그리고 그 투박함을 다음 리팩터링의 단서로 삼는다. 이는 TDD의 빨간불, 초록불, 리팩터링에 대응하는 이름짓기 방식이다.

보조 기법은 다음과 같다.

  • Two-pass: 작업 중에는 일단 임시 이름이나 정직하지만 투박한 이름을 허용한다. 대신 커밋이나 PR 직전에 이름만 따로 다시 보는 단계를 둔다. 이름짓기와 로직 작성을 시간상 분리하는 방법이다.
  • N개 후보 강제 생성: 첫 후보는 가장 친숙해 보일 뿐, 가장 좋다는 보장은 없다. 3~5개의 후보를 서로 다른 축으로 만든 뒤 고른다.
  • Neighborhood-first: 새 이름을 짓기 전에 주변 네임스페이스의 어휘를 먼저 살핀다. 일관성은 우아함보다 중요하다.
  • Glossary 작성: 새 도메인에 진입할 때 30분을 들여 용어와 정의를 정리한다. 이후 모든 이름의 닻이 된다.
  • 큰 소리로 설명하기: 한 문장으로 설명했을 때 말이 되면 이름이 그 문장에서 자연스럽게 추출된다. 말이 되지 않는다면 한 가지 일을 하는 것이 아니거나, 도메인 어휘가 부족한 것이다.
  • 막히면 쪼개기: 이름이 떠오르지 않는 것은 함수가 너무 많은 일을 한다는 신호일 수 있다. Extract Method로 쪼개면 각 조각의 이름이 자연스럽게 나온다.

권장 루틴은 다음과 같다. 작업 중에는 임시 이름이나 정직하지만 투박한 이름을 허용한다. 작업 후에는 별도의 점검 단계에서 주변 네임스페이스를 살피고, 용어집을 확인하고, 후보를 3개 이상 만들고, 큰 소리로 설명해 본 뒤, Belshee 단계에서 한 칸 더 나아갈 수 있는지 본다.

가꾸기 — 시간, 자리, 정리

이름은 가만히 붙어 있는 라벨이 아니다. 시간이 흐르는 네임스페이스 안에서 하나의 자리를 차지한다. 작성 시점에 좋았던 이름도 시간이 지나며 부패할 수 있고, 좋은 이름도 네임스페이스 안에서 다른 이름들의 자리를 막을 수 있다. 가꾸기는 세 가지 의식으로 이루어진다. 시간을 견디는 일, 다른 이름들 사이에서의 자리를 의식하는 일, 정리 작업 자체의 규율을 지키는 일이다.

시간 — 이름은 시간을 견뎌야 한다

한때 정직했던 이름도 거짓이 된다

작성 시점에는 정직했던 이름이 시간이 흐르며 거짓이 되는 일이 흔하다. legacy_xxx가 대표적이다. 처음에는 구버전과 신버전의 분리를 표시했지만, 신버전이 사실상 표준이 된 뒤에는 의미가 사라진다. v2_xxx도 마찬가지다. v1이 사라지면 v2가 기본이 되고, 접두어는 부채만 남긴다. _poc이나 pilot_도 비슷하다. POC가 production화된 뒤에는 접두어가 오히려 사람을 헷갈리게 만든다. 시간 의존 컨텍스트는 이름이 아니라 메타데이터나 태그로 표현하는 편이 낫다.

미래의 형제를 위한 자리를 남긴다

Neighborhood-first에 시간 차원을 더해야 한다. 지금 있는 이웃뿐 아니라 6개월 또는 1년 뒤 어떤 형제가 추가될지 한두 가지 시나리오를 떠올려 본다. 그 형제가 들어올 때 지금 이름이 자리를 가로막지는 않는지, 불행한 -2 접미사를 강요하지는 않는지 점검한다.

자리 — 이름은 다른 이름들 사이에 산다

이름은 네임스페이스의 자리를 차지한다

너무 큰 범주의 이름은 그 아래 모든 형제의 자리를 미리 차지한다. 옵저버빌리티 소스 이름 aws-batch-job이 그 예다. 조직 안의 모든 AWS Batch 작업을 대표할 수 있을 만큼 큰 이름인데, 실제로는 특정 작업 하나만 가리킨다. DB 테이블 settings도 마찬가지다. 누구의 settings인지 명시되지 않으면 다음 settings가 추가될 때 자리가 없다. 이벤트 invoice.created도 비슷하다. 어느 비즈니스 라인의 invoice인지 빠지면 멀티 라인 시스템에서 자리를 가로막는다. 점검 질문은 단순하다. 이 이름이 속한 상위 범주에 다른 형제가 들어올 수 있는가. 들어온다면 지금 이름이 그 자리를 가로막지는 않는가.

시스템이 이미 아는 정보는 이름에 다시 넣지 않는다

Joel Spolsky의 "Making Wrong Code Look Wrong"(2005)은 Hungarian notation의 두 종류인 Apps Hungarian과 Systems Hungarian을 구분한 1차 출처다. Charles Simonyi가 원래 의도한 Apps Hungarian은 변수의 역할, 예를 들어 unsafe string과 safe string 같은 차이를 접두어로 표시하는 방식이었다. 그러나 이것이 type system이 이미 아는 타입을 중복 표시하는 Systems Hungarian으로 변질되면서 안티패턴이 되었다.

이 구분은 더 넓게 일반화할 수 있다. 도구나 type system이 이미 표시, 필터링, 정렬에 쓰는 메타데이터라면 이름에 중복해 넣지 않는다. 옵저버빌리티 도구가 이미 소스 유형을 별도 필드로 알고 있는데도 이름에 소스 유형을 다시 넣거나, 클라우드 리소스의 리전 정보가 별도 메타데이터로 관리되는데도 이름에 리전 정보를 다시 넣는 경우가 같은 패턴이다.

평탄한 네임스페이스에서 계층을 표현한다

멀티 테넌트 SaaS의 리소스나, 한 계정에 여러 제품의 텔레메트리가 섞이는 옵저버빌리티 도구에서는 계층을 이름으로 드러내야 할 때가 있다. 이때는 분류 축의 배열 순서를 적용한다. 가장 안정적이고 가장 큰 단위부터 접두어로 둔다. {조직}-{제품}-{컴포넌트}-{환경} 같은 형태다. 산업 컨벤션이 있다면 그것을 우선한다. 예를 들어 OpenTelemetry semantic conventions의 service.name, service.namespace, deployment.environment나 AWS, GCP, Azure의 tagging strategy를 먼저 살핀다.

정리 — 가꾸기에는 별도의 규율이 있다

변경 작업의 부수효과를 점검한다

의미 없는 중복을 제거할 때는 그 중복이 우연히 수행하던 부수 기능까지 함께 잃지 않는지 확인해야 한다. 예를 들어 오래된 접두어를 제거하면 "이것은 마이그레이션 컨텍스트"라는 거짓 정보는 사라진다. 그러나 네임스페이스를 분리하던 효과도 함께 사라질 수 있다. Martin Fowler의 Refactoring(2nd ed., 2018)과 Kent Beck의 Tidy First?(2024)는 이런 변경 작업의 안전 패턴을 다룬다.

이름을 정기적으로 점검한다

기존 이름을 정리할 때는 이름을 새로 짓는 기법과는 별개의 점검 절차가 필요하다. 큰 소리로 설명하기나 N개 후보 만들기도 유용하지만, 정리 단계에서는 다음 질문을 별도로 던져야 한다.

  • 이 이름은 지금도 정직한가.
  • 시스템이 이미 아는 정보를 중복하고 있지는 않은가.
  • 네임스페이스 안에서 정당한 자리를 차지하고 있는가.
  • 미래의 형제가 들어올 자리를 남기고 있는가.

자기 분야에 적용할 때는 가꾸기를 일회성 작업으로 보지 말아야 한다. 분기에 한 번, 큰 마이그레이션 직후, 새 제품 라인이 추가될 때처럼 적절한 시점에 네임스페이스 전체를 한 바퀴 점검하는 자리를 만든다.


마무리 — 의도

처음의 군대식 말장난으로 돌아가 보자. 그 상황에는 핵심적인 비밀이 하나 있다. 무슨 답을 해도 구박을 피할 수 없다는 것이다. "서울"이라고 해도, "역삼동"이라고 해도, "서울 강남구 역삼동"이라고 해도 선임병은 어떻게든 트집을 잡을 수 있다.

왜냐하면 그 질문의 진짜 의도는 어디에 사는지 궁금해서가 아니기 때문이다. 의도는 서열 확인, 압박, 테스트다. 표면 질문과 진짜 의도가 어긋나 있을 때는 어떤 형식적 답도 적절해질 수 없다.

이것이 이름짓기의 가장 깊은 층이다.

좋은 이름은 "그것이 무엇인가"를 답하는 데서 멈추지 않는다. "그것이 왜 거기에 있는가"까지 답한다. getUserList()findActiveCustomers()를 비교해 보자. 전자는 무엇을 가져오는지 말한다. 후자는 왜 그것을 찾는지에 더 가깝다. 시스템 동작의 what을 답하는 이름은 도메인 어휘를 많이 빌리지 않아도 된다. 그러나 비즈니스의 why를 답하는 이름은 도메인 어휘 그 자체로 만들어진다. DDD가 Ubiquitous Language를 강조하는 이유, Belshee가 7단계의 종착점을 Intent에서 Domain Abstraction으로 두는 이유가 여기에 있다. 이름은 의도의 결정체여야 한다.

따라서 다음과 같은 진단이 가능하다.

이름이 잘 떠오르지 않는다면, 문제는 단어 선택이 아닐 수 있다. 그 대상이 왜 존재하는지, 즉 의도가 아직 흐릿한 것이다.

이 말은 마지막에 멋있게 붙인 문장이 아니다. 이름이 막혔을 때 실제로 꺼내 볼 수 있는 진단 도구다. 자기 코드의 존재 이유를 스스로 명확히 모를 때는 어떤 단어를 골라도 "그래서 뭐?"라는 질문이 남는다. 이때 컨벤션을 더 찾는 것도, 후보를 더 만드는 것도 답이 되지 않는다. 살피기의 4층 어디에서 찾아도 답이 나오지 않는 이유는, 자기가 무엇을 찾는지 스스로 모르기 때문이다. 군대에서 어떤 답을 해도 구박이 가능했던 이유와 같다. 의도가 어긋난 자리에는 정답이 없다.

그래서 이 글의 마지막 처방은 기법 너머의 단순한 원칙이다.

이름을 짜내기 전에 의도를 먼저 잡아라.

이 함수는 왜 존재하는가. 이 변수는 어떤 해석의 틀을 나타내는가. 이 프로젝트는 어떤 비즈니스 결과를 내기 위해 존재하는가. 의도가 명확해지면 좋은 이름은 마술처럼은 아니더라도 자연스럽게 따라온다. 의도가 흐릿한데 단어만 다듬는 것은 선임병에게 동 이름을 더 정확히 말해주는 일과 같다. 답할 수 없는 질문에 답하려는 시도다.

이름은 의도다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment