跳到正文
cccskills
免费在 GitHub 公开

introduce-parameter-object

반복되는 파라미터 그룹을 객체로 치환(IPO)하거나, 객체에서 꺼낸 값 대신 객체 자체를 전달(Preserve Whole Object). "파라미터 객체", "인자가 너무 많아", "start·end 대신 Range로", "/introduce-parameter-object" 요청 시 사용. 단, 결과 객체가 검증·연산을 가진 도메인 값이면 /discover-value-object가 적합. /introduce-parameter-object [commit-ref]로 호출.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(1)

  • SKILL.md11.0 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Introduce Parameter Object / Preserve Whole Object

상황에 따라 두 가지 기법 중 적합한 것을 선택:

  • Introduce Parameter Object (IPO): 파라미터에 행위를 추가해야 할 때 → 새 객체 생성 → 행위 이동 → Value Object 발견
  • Preserve Whole Object (PWO): 기존 객체에서 값을 꺼내 전달할 때 → 객체 자체를 전달하여 파라미터 수 감소

GOAL

  • 성공 = 반복 파라미터가 IPO 또는 PWO로 정리되어 커밋 완료됨
  • IPO: 파라미터 그룹이 Parameter Object로 치환되고 관련 행위가 이동됨
  • PWO: 객체에서 꺼낸 값들이 객체 자체 전달로 대체됨
  • 사용자 확인 후 적용
  • 모든 테스트 통과

기법 선택 기준

상황적용 기법이유
파라미터들이 이미 하나의 객체에서 꺼내져 전달됨Preserve Whole Object객체가 이미 존재 — 꺼내지 말고 그대로 전달
파라미터에 대한 행위를 추가해야 하는 경우Introduce Parameter Object새 객체 생성 → 행위 이동 → Value Object 발견

IPO의 진짜 목적

"더 큰 혜택은 파라미터 그룹에 대해서 동작하는 행위들을 파라미터 객체로 이동시킬 수 있는 것" — Fowler, Ch10

IPO는 파라미터 묶기 자체가 목적이 아니라, Value Object를 발견하는 시작점:

Introduce Parameter Object
  → Move Instance Method (관련 로직을 Parameter Object로 이동)
    → Value Object 탄생 (데이터 + 행위를 가진 객체)

적용하면 안 되는 경우

상황이유
파라미터 간에 논리적 관계가 없음논리 관계 없이 그룹화하면 의미 없는 객체가 생성됨
한 메서드에서만 사용되는 파라미터 조합반복이 없으면 추상화의 가치 없음
파라미터 객체에 이동할 행위가 없음단순 DTO가 되어 Anemic Domain Model 유발 (이 경우 PWO가 더 적합할 수 있음)

CONSTRAINTS

  • 계열: System-wide — 후보 제시 후 승인 받고 적용 (../../references/refactoring-procedure.md §0·§3-B)

Hard Rules

  • 동작 변경 금지 — 구조 개선만 수행
  • 테스트 수정 금지 — 구조 변경이 테스트를 실패시키면 되돌리기
  • 사용자 확인 없이 리팩토링 금지 — 모든 후보는 사용자 승인 후 실행
  • 커밋 단위 — 1파일 x 1기법 = 1커밋 (논리적으로 연결된 파일은 함께)
  • git add -A 금지 — 변경된 파일만 명시적으로 추가

적용 패턴

Introduce Parameter Object 리팩토링 단계:

  1. 반복 파라미터 그룹 식별

    • 3개 이상의 파라미터가 함께 전달되는 패턴
    • 2곳 이상에서 동일한 파라미터 조합 반복
  2. Parameter Object 클래스 생성

    • 논리적으로 관련된 파라미터를 하나의 클래스로
    • record 또는 immutable class 사용 (Java 14+)
    • 의미 있는 이름 부여
  3. 메서드 시그니처 변경

    • 개별 파라미터를 Parameter Object로 치환
    • 호출자 코드 업데이트
  4. 관련 동작 이동 (선택적)

    • Parameter Object와 관련된 로직을 객체 내부로 이동
    • Value Object로 발전 가능

Before/After 예시

// Before: 반복되는 파라미터 그룹
public class PriceService {
    public void processPrice(int originalPrice, int discountedPrice, String currency) {
        // 처리 로직
        validatePrice(originalPrice, discountedPrice, currency);
        formatPrice(originalPrice, discountedPrice, currency);
    }
    
    private void validatePrice(int originalPrice, int discountedPrice, String currency) {
        if (originalPrice < 0 || discountedPrice < 0) {
            throw new IllegalArgumentException("Price cannot be negative");
        }
        if (discountedPrice > originalPrice) {
            throw new IllegalArgumentException("Discounted price cannot exceed original");
        }
    }
    
    private String formatPrice(int originalPrice, int discountedPrice, String currency) {
        double discount = (originalPrice - discountedPrice) * 100.0 / originalPrice;
        return String.format("%s %.0f%% off: %d -> %d", 
            currency, discount, originalPrice, discountedPrice);
    }
}

// After: Parameter Object 적용
record Price(int original, int discounted, String currency) {
    // 생성자에서 검증
    public Price {
        if (original < 0 || discounted < 0) {
            throw new IllegalArgumentException("Price cannot be negative");
        }
        if (discounted > original) {
            throw new IllegalArgumentException("Discounted price cannot exceed original");
        }
    }
    
    // 관련 동작을 객체 내부로 이동
    public double discountPercentage() {
        return (original - discounted) * 100.0 / original;
    }
    
    public String formatted() {
        return String.format("%s %.0f%% off: %d -> %d", 
            currency, discountPercentage(), original, discounted);
    }
}

public class PriceService {
    public void processPrice(Price price) {
        // Parameter Object 하나만 전달
        // 검증은 Price 생성자에서 자동 수행
        String formatted = price.formatted();
    }
}

Preserve Whole Object 패턴

// Before: 객체에서 값을 꺼내서 전달
int low = temperatureRange.getLow();
int high = temperatureRange.getHigh();
boolean withinRange = plan.isWithinRange(low, high);

// After: 객체 자체를 전달
boolean withinRange = plan.isWithinRange(temperatureRange);
// Before: DTO에서 여러 값을 꺼내서 전달
String name = request.getName();
String email = request.getEmail();
int age = request.getAge();
User user = createUser(name, email, age);

// After: 객체 자체를 전달
User user = createUser(request);

적용 기준

Introduce Parameter Object를 적용해야 하는 경우:

  1. 파라미터 수: 3개 이상의 파라미터가 함께 전달
  2. 반복 패턴: 동일한 파라미터 조합이 2회 이상 반복
  3. 논리적 관계: 파라미터들이 논리적으로 관련 있음
  4. 함께 검증: 파라미터들이 함께 검증되어야 함
  5. 동시 변경: 파라미터들이 함께 변경되는 경향

OUTPUT FORMAT

실행 절차

공통 골격(대상 파일 수집 → 후보 제시(계열별 승인 규칙) → 적용 → 테스트 → 커밋/되돌리기, 브랜치·PR이 필요한 조건)은 이 스킬 디렉터리 기준 ../../references/refactoring-procedure.md가 정본이다. 아래는 이 기법에 고유한 부분만 규정한다.

반복 파라미터 그룹 후보 식별 (공통 절차 2단계)

대상 파일에서 다음 패턴을 찾는다:

패턴 A: Introduce Parameter Object

  • 3개 이상의 파라미터를 받는 메서드
  • 동일한 파라미터 조합이 2곳 이상에서 반복
  • 파라미터들이 논리적으로 관련 있음 (같은 도메인 개념)
  • 파라미터에 대한 계산/검증 로직이 여러 곳에서 중복
  • Move Method의 전 단계로 파라미터를 묶어야 하는 경우

패턴 B: Preserve Whole Object

  • 하나의 객체에서 여러 값을 꺼내어 다른 메서드에 전달
  • obj.getX(), obj.getY(), obj.getZ()를 꺼낸 뒤 method(x, y, z) 호출
  • 객체 자체를 전달하면 파라미터 수가 줄어드는 경우

후보 제시 예시 (공통 절차 3단계)

후보를 하나씩 제시하고 사용자 확인:

## 리팩토링 후보 1: Introduce Parameter Object

**파일**: PriceService.java
**반복 파라미터**: (int originalPrice, int discountedPrice, String currency)

**반복 위치** (3곳):
1. processPrice() 메서드
2. validatePrice() 메서드
3. formatPrice() 메서드

**현재 시그니처**:
void processPrice(int originalPrice, int discountedPrice, String currency)
void validatePrice(int originalPrice, int discountedPrice, String currency)
String formatPrice(int originalPrice, int discountedPrice, String currency)

**제안 변경**:
1. Price record 생성 (original, discounted, currency)
2. 검증 로직을 Price 생성자로 이동
3. 포맷팅 로직을 Price.formatted()로 이동
4. 모든 메서드 시그니처를 Price로 변경

**적용할까요?** (yes / no / 수정 요청)
## 리팩토링 후보 2: Preserve Whole Object

**파일**: HeatingPlan.java
**현재**: temperatureRange에서 low, high를 꺼내어 isWithinRange(low, high) 호출
**제안**: isWithinRange(temperatureRange)로 변경

적용할까요? (yes / no / 수정 요청)
  • 사용자가 yes → 실행 목록에 추가
  • 사용자가 no → 스킵
  • 사용자가 수정 요청 → 요청 반영 후 재제시

모든 후보 확인 후 최종 실행 목록을 보여주고 진행 여부 확인.

Parameter Object 도입 실행 (공통 절차 4단계)

확정된 리팩토링을 하나씩 수행:

  1. Parameter Object 클래스(record) 생성
  2. 검증 로직을 생성자로 이동
  3. 관련 동작을 객체 메서드로 이동
  4. 메서드 시그니처 변경
  5. 호출자 코드 업데이트

커밋 메시지 형식:

refactor: introduce parameter object [객체명] in [클래스명]

결과 보고

사용자에게 보고:

  • 적용된 Parameter Object 목록

실전 리팩토링 경로 (Vault 사례)

사례 1: SequenceKey

Extract Method → Introduce Parameter Object → Move Instance Method → Convert Record to Class

효과: sequenceKey가 String → Value Object로 승격. format, increase 로직이 Value Object로 이동.

사례 2: ProductPrice

Split Conditional → Extract Method → Introduce Parameter Object → Move Instance Method

효과: isDiscounted, getFinalPrice가 ProductPrice로 이동. 독립 테스트 가능.

사례 3: StockChecker (빵속빵 패턴)

빵속빵(FCIS) 구조 만들기 → DTO 의존성을 파라미터로 전환 → Parameter Object 생성 → 관련 메서드 이동

패턴: Move Method 전 단계로 파라미터를 먼저 묶음.

공통 패턴

IPO → Move Instance Method → Value Object 탄생

FAILURE CONDITIONS

공통 실패 조건(계열별 승인 규칙 위반, 테스트 실패 방치, 테스트 수정, 커밋 단위, git add -A, heredoc 한글 메시지)은 ../../references/refactoring-procedure.md에 있다. 아래는 이 기법에 고유한 것만.

  • 논리적 관계 없는 파라미터를 억지로 묶음 (불필요한 결합)
  • 1곳에만 사용되는 파라미터 그룹에 적용 (과도한 추상화)
  • mutable Parameter Object 생성 (불변성 보장 필요)

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

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

中文简介正在准备中。当前显示原文说明。

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

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

中文简介正在准备中。当前显示原文说明。

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

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

中文简介正在准备中。当前显示原文说明。

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

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月16日 更新

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

中文简介正在准备中。当前显示原文说明。

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

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

中文简介正在准备中。当前显示原文说明。

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

查看 msbaek 的全部技能

报告此技能的问题