Skip to content
Back to skills

Intent Revealing Names

ASecurity

하나의 긴 메서드를 grouping(Reorder/Chunk)·comment로 정돈해 책임을 드러낸 뒤 Arlo Belshee 6단계 네이밍(완전정직 이름 → Extract Method → Intent Revealing → Domain Abstraction)을 하나의 연속 흐름으로 관통하는 self-contained 워크플로우. "이 긴 메서드 이름이 하는 일을 안 드러낸다", "메서드 이름부터 정직하게 만들어서 쪼개줘", "이름 주도로 이 메서드 리팩토링" 요청 시 사용. 단, 여러 파일에 흩어진 개별 이름 스멜의 배치 교체는 /naming-process, 클래스 분리·도메인 이동 같은 대규모 구조 변경은 /system-wide-refactoring이 적합. /intent-revealing-names로 호출.

  • 8 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 20, 2026
code-qualityrustgojavarefactoringgit

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add msbaek/msbaek-claude-plugins --skill intent-revealing-names --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Intent Revealing Names?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Intent Revealing Names
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/msbaek-intent-revealing-names/badge)](https://www.skillsdirectory.com/skills/msbaek-intent-revealing-names)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: intent-revealing-names
description: 하나의 긴 메서드를 grouping(Reorder/Chunk)·comment로 정돈해 책임을 드러낸 뒤 Arlo Belshee 6단계 네이밍(완전정직 이름 → Extract Method → Intent Revealing → Domain Abstraction)을 하나의 연속 흐름으로 관통하는 self-contained 워크플로우. "이 긴 메서드 이름이 하는 일을 안 드러낸다", "메서드 이름부터 정직하게 만들어서 쪼개줘", "이름 주도로 이 메서드 리팩토링" 요청 시 사용. 단, 여러 파일에 흩어진 개별 이름 스멜의 배치 교체는 /naming-process, 클래스 분리·도메인 이동 같은 대규모 구조 변경은 /system-wide-refactoring이 적합. /intent-revealing-names로 호출.
argument-hint: "[파일:메서드 | commit-ref]"
---

# Intent-Revealing Names — 이름 주도 관통 리팩토링

이름 없는 긴 메서드 하나를 대상으로, **grouping → comment → 정직한 이름 → extract → 의도 드러내는 이름 → 도메인 추상화**를 하나의 연속 흐름으로 관통한다.

> 이름을 신뢰한다면 어떨까요? 이름을 읽어도 메서드를 읽을 필요가 없는 세상을 상상해 보세요.
> — Arlo Belshee

## 핵심 명제

- **intent(의도) = why(왜)**. 좋은 이름은 코드가 *무엇을 하는가(what)*가 아니라 *왜 부르는가(why)*를 드러낸다.
- **이름은 리팩터링의 결과가 아니라 진단 수단이다.** 이름을 정직하게 만들려는 시도 자체가 구조적 문제(SRP 위반, 원시 집착)를 드러내고, 그 진단이 Extract Method·값 객체 도입으로 이어진다.
- **comment는 extract될 메서드 이름의 초안이다** (Kent Beck: "좋은 이름이 떠오르지 않으면 먼저 주석으로 의도를 표현하라 — Extract Method의 전 단계").
- **전환점은 3 → 5단계**: 3단계까지 "무엇을(what)"을 정직하게 누적하고, 5단계에서 "왜(why)"로 전환한다. 이 전환이 있어야 "이름만 읽으면 본문을 읽을 필요가 없는" 상태가 된다.

## GOAL

- **성공 = 대상 긴 메서드가 목차(table of contents)로 축약되고, 각 이름이 why를 드러내며, 모든 테스트가 통과하고, 되돌리기 쉬운 단위 커밋으로 남는다.**
- 상위 메서드의 이름이 what 나열이 아니라 why(호출 이유)를 드러냄
- 추출된 각 private helper가 하나의 식별 가능한 책임만 수행 (Composed Method)
- 남은 원시 집착(Primitive Obsession)이 식별되어 후속 스킬로 인계됨 (승격 자체는 이 스킬 밖)
- 동작 변경 없이 구조만 개선됨

## CONSTRAINTS

- **계열**: Tidy — 후보 보고 후 **승인 없이 적용** (`../../references/refactoring-procedure.md` §0·§3-A)
### Hard Rules (공유)

- **동작 변경 금지** — 구조·이름만 개선, 기능 변경 없음
- **테스트 수정 금지** — 변경이 테스트를 실패시키면 즉시 되돌리기
- **작은 단계 + 매 단계 테스트** — 한 번에 하나의 변형만 적용하고 green 확인
- **명시적 git add** — `git add -A` 금지, 변경 파일만 명시
- **사용자 확인** — 대상 메서드 확정과 5·6단계 진입은 사용자와 합의

### 이 스킬 고유 규칙

- **대상은 하나의 긴 메서드** — 파일 전체 검토가 아니라, 지정된(또는 가장 냄새나는) 긴 메서드 하나에 집중
- **rename을 마지막에 일괄 수행하지 않는다** — 이름 진화(3단계)가 extract(4단계)를 **유발**하고, extract 후 다시 rename(5단계)한다. 이 인터리빙이 이 스킬의 본질이다
- **Extract는 국소(local)에 한정** — 대상 메서드를 **같은 클래스 내 private helper**로 분할하는 것까지. 클래스 분리·도메인 이동 등 대규모 구조 변경은 `/system-wide-refactoring` 전담 (이 스킬은 self-contained 연속 흐름)
- **6단계는 가르치되 인계** — 운영상 이 스킬은 **5단계(Intent Revealing)까지 실행**하고, 6단계(Domain Abstraction)는 방향만 보여준 뒤 원시 집착을 지목해 값 객체·도메인 이동을 후속 스킬(`/discover-value-object` 등)로 **인계**한다. 승격을 이 스킬 흐름 안에서 실행하지 않는다

## 6단계 관통 프로세스 — "주문 처리" 예제

e-commerce "주문 처리" 예제로 6단계를 처음부터 끝까지 진행한다. 각 단계는 **목적 + 코드 상태 + 다음 단계로 넘어가게 만드는 트리거(냄새)** 로 구성된다.

### 출발점 — 이름 없는 긴 메서드

`OrderHelper.process(cart)`가 재고 확인 → 재고 차감 → 결제 → 확정 메일을 한 메서드에서 처리한다. `-Helper` 접미사와 `process`는 정보가 없으면서 정보가 있는 것처럼 보이는, 가장 위험한 종류의 이름이다.

```java
public class OrderHelper {
    public void process(Cart cart) {
        for (CartItem item : cart.getItems()) {
            int stock = stockDao.getStock(item.getProductId());
            if (stock < item.getQuantity()) throw new RuntimeException("out of stock");
        }
        for (CartItem item : cart.getItems())
            stockDao.decrease(item.getProductId(), item.getQuantity());
        BigDecimal total = BigDecimal.ZERO;
        for (CartItem item : cart.getItems())
            total = total.add(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())));
        paymentGateway.charge(cart.getUserId(), total);
        emailSender.send(cart.getUserEmail(), "주문이 완료되었습니다");
    }
}
```

### 단계 A — 본문 정돈으로 책임 가시화 (grouping + comment)

> 사용자 요청 1·2번. 기법 정의는 `/tdd-tidy`(tdd-blue의 Local Tidying)에서 인용 — 여기서는 대상 메서드에 국소 적용한다.

**A-1. Reorder (Reading/Cohesion Order)**: 변수 선언을 사용 위치 가까이로(Reading Order), 관련 로직끼리 인접하게(Cohesion Order, Step Down Rule).
**A-2. Chunk**: 빈 줄로 논리 블록을 분리한다.
**A-3. Explaining Comment**: 각 블록에 "무엇을/왜"를 한 줄로 붙인다. **이 주석이 곧 추출될 메서드 이름의 초안**이다.

```java
public void process(Cart cart) {
    // 재고 확인 — 부족하면 주문 거절
    for (CartItem item : cart.getItems()) {
        int stock = stockDao.getStock(item.getProductId());
        if (stock < item.getQuantity()) throw new RuntimeException("out of stock");
    }

    // 재고 차감
    for (CartItem item : cart.getItems())
        stockDao.decrease(item.getProductId(), item.getQuantity());

    // 결제 — 합계 계산 후 청구
    BigDecimal total = BigDecimal.ZERO;
    for (CartItem item : cart.getItems())
        total = total.add(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())));
    paymentGateway.charge(cart.getUserId(), total);

    // 확정 메일 발송
    emailSender.send(cart.getUserEmail(), "주문이 완료되었습니다");
}
```

**트리거**: 주석 붙은 책임 블록이 4개다 — 이 메서드가 여러 일을 한다는 사실이 이제 눈에 보인다.

### 단계 B — 상위 메서드 이름을 정직하게 진화 (6단계 1→2→3)

이름 축을 정직하게 단계적으로 바꿔, 이름 스스로가 SRP 위반을 드러내게 만든다.

**1. Obvious Nonsense**: `process()` → `applesauce()`. 그럴듯하지만 비어 있는 이름을, 일부러 명백히 틀린 이름으로 바꿔 "여기 이름이 필요하다"를 코드가 명시하게 한다. `-er`/`-Utils`/라이프사이클(`onCreate`) 이름을 제거하는 단계이기도 하다.

**2. Honest**: `applesauce()` → `probably_updateStockAndCharge_andStuff()`. 3부 규칙 — `probably_`(불확실) + 파악한 동작 + `_andStuff`(아직 못 파악). 완벽함이 아니라 **오해를 주지 않는 것**이 목표.

**3. Completely Honest**: `checkStockAndDeductStockAndChargePaymentAndSendConfirmationEmail()`. 단계 A의 comment들을 그대로 이어 붙인 이름. `probably_`·`_andStuff`를 모두 제거하고 하는 일 **전부**(what)를 담는다. 길고 어색해도 상관없다.

**트리거**: 이름에 `And`가 네 번 등장한다 — 책임이 네 개, 즉 **SRP 위반을 이름이 드러낸다**. 이것이 다음 단계(extract)의 근거다.

> **팀 합의 노트**: `applesauce`·`probably_..._andStuff` 같은 중간 이름을 실제 커밋할지는 팀 합의 사항이다. "아직 이해하지 못했다"를 정직하게 남기는 편이 그럴듯한 거짓 이름보다 낫다는 입장(Emily Bache 데모)이 있으나, 개인 작업이면 3단계에서 한 번에 커밋해도 된다.

### 단계 C — 드러난 책임대로 Extract (6단계 4: Does the Right Thing, composed method)

완전정직 이름의 각 `And` 조각 = 단계 A의 각 comment 블록. 그 블록들을 **comment를 이름으로 승격**하여 private helper로 추출한다. 상위 메서드는 4줄짜리 목차가 된다. (Arlo Belshee 정본 4단계 "Does the Right Thing"을 여기서 Extract로 흡수한다 — 각 조각이 비로소 제 일만 하게 되므로.)

```java
public void checkStockAndDeductStockAndChargePaymentAndSendConfirmationEmail(Cart cart) {
    ensureStockAvailable(cart);
    deductStock(cart);
    chargePayment(cart);
    sendConfirmationEmail(cart);
}

private void ensureStockAvailable(Cart cart) { /* 재고 확인 블록 */ }
private void deductStock(Cart cart) { /* 재고 차감 블록 */ }
private void chargePayment(Cart cart) { /* 결제 블록 */ }
private void sendConfirmationEmail(Cart cart) { /* 확정 메일 블록 */ }
```

지역 변수가 상호 의존해 추출이 불가능하면 먼저 `/replace-temp-with-query`·`/extract-method-object`를 적용한다(이름으로 인용).

**트리거**: 구조는 정직해졌지만 상위 이름은 여전히 "무엇을 하는지"의 나열이다. "왜 이 메서드를 부르는지"는 아직 드러나지 않는다.

### 단계 D — 의도를 드러내기 (6단계 5) ★핵심 전환점

호출하는 쪽(예: `CheckoutController`의 "주문하기" 버튼 처리)을 살펴보면, 이 메서드의 진짜 목적은 "고객이 주문을 낸다"임을 알 수 있다. what이 아니라 why로 이름을 바꾼다.

```java
// 호출부: checkStockAndDeductStockAndChargePaymentAndSendConfirmationEmail(cart);
//      ↓
//         placeOrder(cart);

public class OrderService {          // OrderHelper → OrderService
    public void placeOrder(Cart cart) {
        ensureStockAvailable(cart);
        deductStock(cart);
        chargePayment(cart);
        sendConfirmationEmail(cart);
    }
}
```

이것이 "**intent = why**"의 실체다. 이름은 더 짧아지고, 호출 코드를 읽을 때 자연스럽게 이해된다.

**트리거**: 이름은 좋아졌지만 내부에 `String productId`, `int quantity`, `BigDecimal total` 같은 원시 타입이 분산되어 있다 — 원시 집착(Primitive Obsession).

### 단계 E — 도메인 추상화 (6단계 6)

> 여기서부터는 무거운 구조 변경이라 **이 스킬의 범위를 벗어난다** — 이 스킬은 5단계까지 실행하고 6단계는 인계한다. 값 객체·First Class Collection·Functional Core 분리는 각각 `/discover-value-object`, `/introduce-parameter-object`, `/first-class-collection`, `/segregate-functional-core`로 인계한다.
>
> **아래 코드는 후속 스킬들로 도달하는 목표 end-state(aspirational)이며, 이 스킬에서 전부 실행하지 않는다.** 이 스킬의 역할은 5단계까지 완성한 뒤 원시 집착을 _가리키고_, 실제 승격은 인용된 후속 스킬로 넘기는 것이다 (클래스 분리·도메인 이동은 이 스킬 범위 밖 — FAILURE CONDITIONS 참조).

```java
public Order placeOrder(Cart cart) {
    Order order = cart.toOrder();          // Order 애그리거트
    inventory.reserve(order.lines());      // 재고 확인+차감 → Inventory 도메인
    payment.charge(order.total());         // total() → Money 값 객체
    notifier.notifyOrderPlaced(order);
    return order;
}
```

| 이전 (원시 집착) | 이후 (도메인 개념) |
| --- | --- |
| `String productId` + `int quantity` 반복 | `OrderLine` 값 객체 |
| `BigDecimal total` 산재 | `Money` 값 객체 (`order.total()`) |
| `stockDao.getStock()`/`decrease()` 절차 호출 | `Inventory.reserve(lines)` |
| `Cart`를 절차적으로 순회·변환 | `Order` 애그리거트 (`cart.toOrder()`) |

이제 `placeOrder`의 본문은 하나의 유비쿼터스 언어 안에서 비즈니스 규칙을 읽는 산문이 된다.

### 6단계 요약

| 단계 | 이 스킬의 활동 | 초점 | 예제 이름 |
| --- | --- | --- | --- |
| A. Tidy-prep (6단계 이전 준비) | Reorder + Chunk + Comment | 책임 가시화 | `// 재고 확인` 등 4개 블록 |
| B1. Obvious Nonsense | 나쁜 이름 제거 | — | `applesauce()` |
| B2. Honest | 파악한 사실만 정직하게 | what(부분) | `probably_updateStockAndCharge_andStuff()` |
| B3. Completely Honest | 하는 일 전부 | what(전부) | `checkStock...AndSendConfirmationEmail()` |
| C. Extract | SRP 위반대로 분리 | Composed Method | `ensureStockAvailable()` + 3개 |
| D. Intent Revealing ★ | 무엇이 아니라 **왜** | why | `placeOrder(cart)` |
| E. Domain Abstraction (범위 밖 — 인계) | 원시 집착 → 도메인 언어 | 도메인 | 후속 스킬로 인계 (`Order`, `Money`, `Inventory`) |

## 다른 스킬과의 경계

이 스킬은 self-contained하지만, 각 기법의 **정의는 재기술하지 않고 이름으로 인용**한다.

- **grouping/comment 기법 상세** → `/tdd-tidy`(tdd-blue): Reorder, Chunk, Explaining Comment, Normalize Symmetries, Split Loop 등
- **대규모 Extract / 클래스 분리 / 도메인 이동** → `/system-wide-refactoring`. 이 스킬은 국소 private helper 추출까지만
- **개별 이름 rename 카탈로그(Naming Smells 탐지)** → `/naming-process`. 이 스킬은 "하나의 메서드를 6단계로 관통"이 목적 (개별 이름 스캔이 아님)
- **값 객체/컬렉션/함수형 코어 승격 상세** → `/discover-value-object`, `/introduce-parameter-object`, `/first-class-collection`, `/segregate-functional-core`

## OUTPUT FORMAT

### 실행 절차

#### 1. 대상 메서드 확정

- 인자로 `파일:메서드`가 오면 그 메서드를, `commit-ref`가 오면 그 diff의 Java 파일에서 가장 긴/냄새나는 메서드를 후보로 제시
- 인자가 없으면 `git diff --name-only -- '*.java'`(+`--cached`)의 변경 파일에서 20줄 이상 메서드를 찾아 후보 제시
- 테스트 파일(`*Test.java` 등)은 제외
- 후보를 보여주고 **대상 하나를 사용자와 확정**

```
관통 리팩토링 대상 후보:
- OrderHelper.process(Cart) — 15줄, 책임 4개 추정 (재고확인/차감/결제/메일)
이 메서드로 진행할까요?
```

#### 2. 단계 A~E를 순서대로, 작은 단계로 적용

- **A**: Reorder → Chunk → Comment (책임 블록 가시화)
- **B**: 상위 메서드 이름을 1→2→3단계로 진화 (완전정직까지)
- **C**: comment 블록을 이름으로 승격해 private helper 추출 (IDE Extract Method)
- **D**: 호출부를 근거로 상위 메서드를 intent-revealing rename (IDE Rename — 참조 자동 갱신). 클래스명 `-Helper`/`-er`도 이때 함께
- **E**: (실행 안 함 — 인계) 5단계 완성 후 남은 원시 집착을 지목하고, 값 객체·도메인 이동을 후속 스킬(`/discover-value-object` 등)로 제안한다. 승격은 이 스킬에서 수행하지 않는다

**각 단계마다**: 변경 → 테스트 실행(`./gradlew test` 또는 `mvn test`) → green이면 진행, red면 즉시 되돌리기.

#### 3. 커밋 — 되돌리기 쉬운 단위로

의미 단위로 나눠 커밋하는 것을 권장한다 (각 단계가 독립적으로 되돌려짐):

- `refactor: tidy-prep OrderHelper.process — group & comment responsibilities` (단계 A)
- `refactor: extract composed methods from OrderHelper.process` (단계 C, B의 이름 진화 포함)
- `refactor: reveal intent — process → placeOrder` (단계 D)

(단계 E의 도메인 승격은 이 스킬에서 커밋하지 않는다 — 후속 스킬로 인계.)

- 커밋 메시지는 `docs/reviewable-commits.md`(없으면 `${CLAUDE_PLUGIN_ROOT}/references/reviewable-commits.md`) 표준을 따른다. subject는 `refactor:` 접두사, body에 Why(이름이 무엇을 드러냈고 왜 이렇게 분리/명명했는지)를 담는다. 형식은 그 표준이 유일한 출처이므로 여기서 재기술하지 않는다. 길이는 `../../references/commit-style.md`의 간결성 규칙(제목 + 핵심 bullet 2~4줄)을 따른다.
- 한글 메시지는 임시 파일 + `git commit -F` (`-m "한글"` 금지 — 깨짐).
- 최소 요건이 급하면 전체를 단일 `refactor:` 커밋으로 마무리해도 되나, 단계별 분리가 리뷰·롤백에 유리하다.

#### 4. 완료 보고

- 이름 진화 경로 요약 (`process` → `applesauce` → … → `placeOrder`)
- 추출된 helper 목록과 각 책임
- 테스트 결과
- 남은 원시 집착과 인계할 후속 스킬 제안 (`/discover-value-object` 등)

## FAILURE CONDITIONS

이 중 하나라도 발생하면 작업 실패로 간주:

- [ ] 리팩토링 후 테스트가 실패함
- [ ] rename을 맨 마지막에 일괄 수행함 (3단계 완전정직 이름이 extract를 유발하는 인터리빙을 건너뜀)
- [ ] 3단계(Completely Honest)를 건너뛰고 곧장 intent-revealing 이름으로 건너뜀 (SRP 위반 진단 과정 생략)
- [ ] 별도 브랜치를 만들거나 PR을 생성함 (self-contained 위반 — 대규모는 `/system-wide-refactoring`)
- [ ] 클래스 분리·도메인 이동 같은 대규모 구조 변경을 이 스킬에서 수행 (경계 침범)
- [ ] 단계 E(도메인 승격)를 후속 스킬로 인계하지 않고 이 스킬 흐름 안에서 직접 실행 (5단계까지만 실행이 원칙)
- [ ] `git add -A` 사용 / 동작 변경 발생 / 사용자 확인 없이 5단계(Intent Revealing) 진입

## 더 읽을거리 (비-load-bearing)

이 스킬은 아래 vault 문서를 소스로 작성되었다. **런타임 의존성이 아니며**, 없어도 스킬은 완전하게 동작한다.

- vault: `Intent Revealing Names.md` — Arlo Belshee 6단계 프로세스를 "주문 처리" 예제로 관통한 원 노트
- Emily Bache, *Trustworthy Code with Naming as a Process* — Arlo Belshee 기법 라이브 데모
- Robert C. Martin, *Clean Code* Ch.4 Meaningful Names — Intention-Revealing Names 원개념

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…