| name | srp |
| description | 파일 단위 단일 책임 원칙(SRP)을 점검하고 리팩토링을 수행한다. "단일 책임", "책임 분리", "파일이 너무 크다", "이 파일 쪼개자", "/srp", "/srp 300", "/goal srp 300" 등으로 트리거된다. 숫자 인자는 import/export-from 라인을 제외한 LOC 기준의 후보 발견 하한이며, 목표 라인 수나 절대 분할 기준이 아니다. 파일명과 실제 구현 책임을 대조해 책임이 1개면 유지하고, 2개 이상이면 분리 계획을 표로 명시한 뒤 분리한다. |
SRP
파일명이 말하는 목적과 실제 구현의 책임을 비교하여, 파일 단위 책임 경계가 맞는지 판단한다.
일반적인 "함수가 길다", "중복 코드", "300줄이 넘는다" 같은 코드 스멜 자체는 다루지 않는다. 이 스킬은 파일 단위의 책임 경계만 다룬다.
숫자 인자의 의미
/srp 300, srp 300, /goal srp 300의 300은 후보 파일을 찾기 위한 LOC 하한이다.
반드시 지킨다:
300은 목표 라인 수가 아니다.
300은 "모든 파일을 300줄 이하로 만들라"는 완료 조건이 아니다.
300은 "300줄 이상이면 반드시 쪼개라"는 분리 기준이 아니다.
- LOC는 후보 발견에만 사용하고, 최종 유지/분리 판단은 책임 개수와 파일명-구현 일치 여부로 한다.
- 한 파일이 300줄을 넘어도 실제 책임이 1개면 유지한다.
- 분리 후 새 파일이 300줄을 넘더라도 책임이 1개면 허용한다.
정식 판정식:
| 실제 책임 수 | 판정 | 행동 |
|---|
| 1개 | 유지 | 파일을 쪼개지 않는다. 필요하면 유지 이유만 기록한다. |
| 2개 이상 | 분리 | 책임별 귀속 파일과 이동 방법을 표로 명시한 뒤 분리한다. |
| 판단 불가 | 보류 | @FIXME(srp) 또는 사용자 확인으로 판단 조건을 남긴다. |
대상 파일 선택
사용자가 파일을 직접 지정하면 그 파일을 점검한다. 이 경우 숫자 하한과 무관하게 지정 파일을 분석한다.
사용자가 숫자를 함께 주면 그 숫자를 import/export-from 라인을 제외한 LOC 하한으로 사용한다.
- 소스 파일 후보를 찾는다.
- import/export-from 라인은 LOC에서 제외한다.
- 빈 줄은 제외한다.
- 주석만 있는 줄은 프로젝트 언어에 맞게 가능하면 제외하되, 빠르게 판별하기 어렵다면 포함해도 된다.
- LOC가 숫자 이상인 파일을 찾는다.
- 규모만으로 정렬하지 말고, 파일명과 실제 구현 책임이 어긋날 가능성, 최근 변경, 호출 범위를 함께 보아 우선순위화한다.
- 가장 SRP 점검 가치가 큰 파일부터 분석한다.
숫자가 없고 파일도 지정되지 않았으면, 최근 수정된 소스 파일 맥락을 먼저 본다. 최근 변경 맥락이 없거나 판단하기 어려우면 300 LOC를 기본 하한으로 사용한다.
후보 추림은 예를 들어 다음처럼 수행할 수 있다. 프로젝트 언어에 맞게 확장자는 조정한다.
rg --files | rg '\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift)$'
LOC 계산은 정확한 파서보다 빠른 후보 선별이 목적이다. 선별 후 실제 분석은 반드시 코드를 읽고 판단한다.
후보를 사용자에게 보여줄 때는 숫자 절감 목표처럼 쓰지 않는다.
| 파일 | LOC(import 제외) | 파일명이 말하는 목적 | 의심되는 책임 | 우선순위 이유 |
|---|---:|---|---|---|
| ____ | 342 | ____ | ____ | ____ |
Phase 1: 분석
아래 템플릿을 순서대로 채운다. 확실한 사실을 먼저 쓰고, 추론을 거쳐, 결론은 마지막에 도출한다. 결론을 먼저 정하고 근거를 끼워맞추지 않는다.
## 단일 책임 점검
파일: ____
LOC(import 제외): ____
파일명이 말하는 목적: ____
### 사실 수집 (코드에서 확인)
이 파일이 하는 일:
1. ____ (lines ____)
2. ____ (lines ____)
### 실제 책임 식별
| 책임 ID | 실제 책임 | 근거 lines | 파일명 목적과의 관계 | 독립 변경 이유 |
|---|---|---|---|---|
| R1 | ____ | ____ | 일치/부분/불일치 | ____ |
### 책임 수 판정
| 파일 | 실제 책임 수 | 판정 | 이유 |
|---|---:|---|---|
| ____ | 1/2/... | 유지/분리/보류 | ____ |
### 분리 계획 (분리 판정일 때 필수)
| 책임 | 현재 lines | 분리 파일명 | 옮길 코드 | 원본에 남길 코드 | 공개 API/export | import 갱신 | 검증 |
|---|---|---|---|---|---|---|---|
| ____ | ____ | ____ | ____ | ____ | ____ | ____ | ____ |
### 유지 판단 (유지 판정일 때 필수)
| 파일 | 유지 책임 | 유지 이유 | 다음 조치 |
|---|---|---|---|
| ____ | ____ | 책임 1개라 분리하지 않음 | 없음/주석/테스트 |
### 보류 (@FIXME)
| 책임 | 애매한 이유 | 판단 조건 |
|---|---|---|
| ____ | ____ | ____ |
채우는 순서:
- 파일명만 보고 이 파일이 해야 할 일을 한 문장으로 쓴다.
- 코드를 읽고 실제로 하는 일을 line range와 함께 나열한다.
- 실제 책임을 센다. 책임은 함수 개수나 코드 길이가 아니라 독립적으로 바뀌는 이유다.
- 책임이 파일명 목적과 일치하는지 판단한다.
- 실제 책임 수가 1개면 유지로 결론 낸다.
- 실제 책임 수가 2개 이상이면 분리로 결론 내고, 분리 계획 표를 먼저 작성한다.
- 애매하면 보류로 분류하고 판단 조건을 남긴다.
확신도
판정의 확실함을 Cynefin 기준 3단계로 표기한다. 확신도가 행동을 결정한다. 애매하면 실행하지 않는다.
| 확신 | Cynefin | 의미 | 행동 |
|---|
| C | Clear | 책임 수와 귀속이 명백함 | 유지 또는 분리 실행 |
| K | Complicated | 분석하면 답이 나오지만 판단이 필요 | AI 판단 제시 + 사용자 확인 후 실행 |
| X | Complex | 옮겨봐야 아는 것 | 실행하지 않음. @FIXME(srp) 주석만 남김 |
Complex(X) 판정을 받은 책임은 코드에 주석으로 남긴다.
분리 실행 전에는 분석 결과와 분리 계획 표를 사용자에게 보여준다. /goal srp 300처럼 실행 목표로 들어온 경우에도, 목표는 "300줄 맞추기"가 아니라 "300줄 이상 후보에서 책임 경계를 판정하고 필요한 경우만 분리하기"다.
Phase 2: 리팩토링 실행
분리 판정이 Clear(C)이거나 사용자가 Complicated(K) 분리에 동의하면 리팩토링을 수행한다. 유지 판정이면 파일을 건드리지 않는다.
실행 원칙:
- 책임 단위 이동: 관련 코드를 책임별로 한 번에 옮긴다.
- LOC 목표 금지: 300줄 이하 같은 라인 수 목표를 맞추기 위해 책임을 찢지 않는다.
- 인터페이스 최소화: 분리된 파일이 원본에 노출하는 API는 최소한으로 한다.
- 파일명 = export: 새 파일명은 주 export 식별자와 일치해야 한다.
- import 경로 갱신: 분리 후 기존 import를 모두 갱신한다.
- @FIXME 삽입: Complex(X) 항목은 해당 코드 위에 주석을 남긴다.
실행 순서:
- 분리 계획 표의 각 책임별 대상 파일을 생성한다.
- 원본 파일에서 해당 책임 코드를 제거하고 새 파일을 import한다.
- 원본 파일에는 원본 파일명 목적에 맞는 책임만 남긴다.
- Complex(X) 항목에
@FIXME(srp) 주석을 삽입한다.
- 다른 파일의 import 경로를 갱신한다.
- 프로젝트의 정적 검증을 실행하여 회귀를 확인한다.
검증은 프로젝트에 존재하는 명령을 우선 사용한다. 예: tsc --noEmit, pnpm typecheck, npm run build, eslint.