本文へ移動
cccskills
無料GitHub で公開

intent-revealing-names

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

インストール方法を見る

含まれるファイル(1)

  • SKILL.md18.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

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는 정보가 없으면서 정보가 있는 것처럼 보이는, 가장 위험한 종류의 이름이다.

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: 각 블록에 "무엇을/왜"를 한 줄로 붙인다. 이 주석이 곧 추출될 메서드 이름의 초안이다.

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로 흡수한다 — 각 조각이 비로소 제 일만 하게 되므로.)

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로 이름을 바꾼다.

// 호출부: 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 참조).

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. ExtractSRP 위반대로 분리Composed MethodensureStockAvailable() + 3개
D. Intent Revealing ★무엇이 아니라 왜whyplaceOrder(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 원개념

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

동일한 결과를 내는 여러 조건문(OR 나열·중첩 AND)을 하나로 통합하고 의미 있는 boolean 메서드로 추출. "조건문 합쳐", "같은 결과 반환하는 if 정리", "중첩 if 평탄화", "/consolidate-conditional" 요청 시 사용. 단, 여러 메서드에 흩어진 동일 조건을 호출자 쪽으로 올리는 것은 /lift-up-conditional, 복잡한 조건식·분기를 메서드로 쪼개는 것은 /decompose-conditional이 적합. /consolidate-conditional [commit-ref]로 호출.

日本語の概要は準備中です。原文の説明を表示しています。

msbaek/msbaek-claude-plugins82026年10月1日 更新

기능의 external behavior를 Cucumber 인수 테스트(주 검증층)로 구축 — .feature 실행으로 문서↔코드 드리프트를 구조적으로 차단, Four Layer(Steps→Protocol Driver→SUT), 태그 기반 가역 제외, 기존 JUnit 인수 테스트 이관. "인수 테스트 도입", "Gherkin을 실행 가능하게", "cucumber 셋업" 요청 시 사용. /cucumber-acceptance로 호출.

日本語の概要は準備中です。原文の説明を表示しています。

msbaek/msbaek-claude-plugins82026年10月1日 更新

복잡한 if/then/else의 조건식과 각 분기를 의미 있는 메서드로 추출하여 가독성 향상. "조건문 분해", "if 가독성", "복잡한 조건식에 이름 붙여", "/decompose-conditional" 요청 시 사용. 단, 같은 결과를 내는 조건문들을 하나로 합치는 것은 /consolidate-conditional, 타입별 분기를 클래스로 바꾸는 것은 /replace-conditional-with-poly가 적합. /decompose-conditional [commit-ref]로 호출.

日本語の概要は準備中です。原文の説明を表示しています。

msbaek/msbaek-claude-plugins82026年10月1日 更新

Primitive Obsession 제거 — 검증·연산이 따라다니는 primitive 필드(금액+통화, 이메일 문자열 등)를 도메인 개념을 담은 Value Object로 치환. "값 객체 도입", "primitive obsession", "Money 클래스로", "/discover-value-object" 요청 시 사용. 단, 함께 전달되는 파라미터 묶음을 객체로 바꾸는 것은 /introduce-parameter-object, 컬렉션을 감싸는 것은 /first-class-collection이 적합. /discover-value-object [commit-ref]로 호출.

日本語の概要は準備中です。原文の説明を表示しています。

msbaek/msbaek-claude-plugins82026年10月1日 更新

컬렉션 getter가 내부 List/Set을 직접 노출하는 것을 방지 — unmodifiable 반환 + add/remove 메서드 제공. "컬렉션 캡슐화", "getter가 List 그대로 노출", "unmodifiable로", "/encapsulate-collection" 요청 시 사용. 단, 컬렉션과 관련 로직을 전용 클래스로 뽑는 것은 /first-class-collection이 적합. /encapsulate-collection [commit-ref]로 호출.

日本語の概要は準備中です。原文の説明を表示しています。

msbaek/msbaek-claude-plugins82026年10月1日 更新

암묵적 의존성(전역 변수·클래스 필드·싱글턴 접근)을 명시적 파라미터로 전환하여 메서드 투명성 향상. "숨은 의존성 드러내", "필드 대신 파라미터로", "전역 참조 제거", "/explicit-parameters" 요청 시 사용. 단, 파라미터가 많아져 묶어야 하면 /introduce-parameter-object, I/O와 계산 분리는 /segregate-functional-core가 적합. /explicit-parameters [commit-ref]로 호출.

日本語の概要は準備中です。原文の説明を表示しています。

msbaek/msbaek-claude-plugins82026年10月1日 更新

msbaek のスキルをすべて見る

このスキルの問題を報告する