[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,137 +1,157 @@
|
||||
---
|
||||
id: wiki-2026-0508-red-green-refactoring
|
||||
title: Red Green Refactoring
|
||||
title: Red-Green Refactoring
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Red-Green-Refactor, TDD Cycle, RGR]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
verification_status: applied
|
||||
tags: [tdd, refactoring, testing, xp]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: TypeScript
|
||||
framework: Vitest
|
||||
---
|
||||
|
||||
# [[Red-Green Refactoring]]
|
||||
# Red-Green Refactoring
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Red-Green Refactoring은 애자일 소프트웨어 개발에서 가장 널리 사용되는 코드 리팩토링 기법으로, 테스트 주도 개발(TDD) 워크플로우에 깊이 뿌리를 두고 있습니다 [1, 2]. 실패하는 테스트를 먼저 작성하는 'Red' 단계, 최소한의 코드로 테스트를 통과시키는 'Green' 단계, 그리고 코드를 개선하는 'Refactor' 단계의 세 가지 반복적인 주기로 구성됩니다 [3-5]. 기능 추가와 구조 개선을 엄격히 분리하여, 기존 동작을 훼손하지 않으면서도 시스템의 유연성과 유지보수성을 지속적으로 높이는 데 목적이 있습니다 [3, 5].
|
||||
## 매 한 줄
|
||||
> **"매 Red → Green → Refactor — 매 minute scale 의 design loop"**. Kent Beck 의 *Test-Driven Development: By Example* (2002) 에서 codified 된 micro-cycle. 매 failing test (Red) → minimum code 로 pass (Green) → smell 제거 (Refactor) 의 30초~3분 사이클이 매 production-grade XP/TDD 의 atomic unit 이다.
|
||||
|
||||
## 📖 Core 소스
|
||||
Red-Green Refactoring은 "테스트 우선(test-first)" 접근법을 따르며, 이는 모든 형태의 리팩토링의 기초를 형성합니다 [1]. 이 전략은 기능 구현과 리팩토링을 위한 세 가지 명확한 단계로 수행됩니다.
|
||||
## 매 핵심
|
||||
|
||||
* **RED (실패하는 테스트 작성):** 특정 소프트웨어 동작이나 기능을 검증하기 위한 실패하는 테스트(red-test)를 가장 먼저 작성합니다 [3, 5]. 아직 실제 코드가 작성되지 않았기 때문에 이 테스트는 의도적으로 실패하도록 설계됩니다 [5]. 이 단계를 통해 개발자는 무엇을 개발해야 할지 명확히 확인하게 됩니다 [3].
|
||||
* **GREEN (테스트 통과를 위한 최소한의 코드 구현):** 개발이 테스트를 통과(green)할 수 있도록 가장 단순하고 충분한 코드를 작성합니다 [3]. 이 단계의 핵심 목표는 코드의 품질보다는 속도에 있으므로, 테스트를 통과하기 위한 최소한의 코드만을 작성합니다 [5].
|
||||
* **REFACTOR (코드 개선 및 최적화):** 테스트가 통과하는 상태(green)를 유지하면서 코드를 개선하고 향상시키는 데 집중합니다 [3]. 소프트웨어의 동작은 그대로 보존하면서, 코드를 더 깨끗하고, 명확하며, 효율적으로 다듬어 최적화합니다 [4, 5].
|
||||
### 매 세 phase
|
||||
- **Red**: 매 새 behavior 를 실패하는 test 로 명시. Compile error 도 Red 로 인정 (Beck).
|
||||
- **Green**: 매 *fastest* path 로 pass — fake it, obvious implementation, triangulation 중 택 1. 매 ugly OK.
|
||||
- **Refactor**: 매 두 hat 의 second hat — duplicate 제거, naming, 추상화. 매 test 는 계속 green.
|
||||
|
||||
이 기술은 본질적으로 새로운 기능을 시스템에 추가하는 첫 번째 파트(Red, Green)와 그 기능을 수행하는 코드를 개선하는 두 번째 파트(Refactor)로 나뉩니다 [3]. 가장 중요한 원칙은 워크플로우 중에 이 두 가지 작업(기능 추가와 리팩토링)을 동시에 수행해서는 안 된다는 것입니다 [3].
|
||||
### 매 cycle 시간
|
||||
- 매 한 cycle = 30초 ~ 3분 권장. 30분 넘으면 step too big.
|
||||
- 매 commit 단위 = green 직후 또는 refactor 직후. Red 상태 commit 의 X.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **Green 단계에서의 품질 저하 감수:** Green 단계에서는 고품질의 완벽한 코드를 작성하는 것보다 빠른 시간 내에 테스트를 통과하는 '속도'를 우선시합니다 [5]. 이는 기능 구현을 빠르게 달성하는 대신 의도적으로 엉성한 코드를 임시로 남기게 되며, 후속 Refactor 단계를 거치지 않으면 기술 부채로 전락할 위험이 있습니다.
|
||||
* **기능 추가와 리팩토링의 동시 수행 금지:** 워크플로우를 진행할 때 새로운 기능 추가(코드 작성)와 리팩토링을 절대 동시에 진행해서는 안 됩니다 [3]. 이 엄격한 분리를 따르지 않으면 디버깅이 어려워지고, 테스트의 신뢰성이 떨어지는 부작용이 발생합니다 [3, 6].
|
||||
* **초기 테스트 작성의 한계:** 코드를 작성하기 전에 실패하는 테스트를 먼저 구현해야 하므로(Red 단계), 테스트를 작성하는 데 추가적인 시간적 제약과 노력이 요구됩니다 [3, 5]. 테스트 인프라가 부족한 상황에서는 리팩토링에 앞서 테스트부터 구축해야 하므로 적용이 어려울 수 있습니다 [7].
|
||||
### 매 응용
|
||||
1. Outside-in (London school): mock 기반 acceptance test → unit drill-down.
|
||||
2. Inside-out (Detroit/Chicago school): domain core 부터 state-based test.
|
||||
3. AI pair: 매 Claude Code 가 test 작성, 매 human 이 implementation 확인 — 또는 reverse.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
## 💻 패턴
|
||||
|
||||
#### [방법론/개발 프로세스]
|
||||
- [[TDD (Test-Driven Development)]]
|
||||
- 연결 이유: Red-Green Refactoring은 테스트 주도 개발(TDD) 워크플로우에 내재되어 있으며, TDD 사이클 그 자체를 의미하기 때문입니다 [2, 5, 8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 테스트 작성이 어떻게 소프트웨어 구현 및 리팩토링을 주도하고 안정성을 부여하는지 시스템 개발 관점에서 이해할 수 있습니다 [5, 8].
|
||||
- [[Agile Methodology]]
|
||||
- 연결 이유: Red-Green 기법은 애자일 소프트웨어 개발 프로세스에서 가장 인기 있고 널리 사용되는 기술이기 때문입니다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 짧은 주기의 반복적(iterative)인 전략이 어떻게 지속적인 리팩토링을 가능하게 하고 변화에 민첩하게 대응하게 하는지 학습할 수 있습니다 [5].
|
||||
### Vitest 의 매 cycle 예시
|
||||
```typescript
|
||||
// === RED ===
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { Money } from './money';
|
||||
|
||||
#### [리팩토링 원칙/규율]
|
||||
- [[Two Hats (두 개의 모자)]]
|
||||
- 연결 이유: 기능 추가의 단계(Red, Green)와 리팩토링 단계(Refactor)를 섞어서 진행하면 안 된다는 Red-Green Refactoring의 기본 규정은 마틴 파울러의 '두 개의 모자' 원칙을 완벽히 실천하는 형태이기 때문입니다 [3, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 리팩토링 과정 중 기존 코드의 구조 개선과 새로운 기능 추가를 심리적, 절차적으로 철저히 분리하여 디버깅 효율을 높이는 원리를 파악할 수 있습니다 [6].
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- Red-Green Refactoring의 'Green' 단계에서 속도를 우선하여 작성된 최소한의 코드가, 후속 'Refactor' 단계의 설계 결정에 어떠한 인지적 편향을 일으킬 수 있는가?
|
||||
- TDD 기반의 Red-Green 주기를 도입할 때, 테스트 커버리지가 거의 없는 방대한 레거시 시스템(Legacy System)에서 이 기법을 점진적으로 적용하기 위한 효과적인 시퀀스는 무엇인가?
|
||||
- Red-Green-Refactor 단계를 매우 짧은 간격(마이크로 커밋)으로 반복할 경우, 소프트웨어 아키텍처의 지속 가능성과 모듈성에 미치는 정량적 변화는 어떠한가?
|
||||
- 테스트 코드가 외부 API나 데이터베이스와 강하게 결합된 환경에서 Red-Green Refactoring을 안전하게 수행하기 위해 테스트 더블(Mock, Stub)은 어느 단계에 어떻게 설계되어야 하는가?
|
||||
- 'Refactor' 단계에서 리팩토링을 멈추고 다시 'Red' 단계로 돌아가야 하는 시점(Stopping Condition)을 판단하는 경험적, 객관적 기준은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 새로운 기능 구현 시, 해당 요구사항을 명세하는 실패하는 테스트를 가장 먼저 코드로 작성하고, 테스트가 통과될 때까지 가장 무식하지만 빠른 코드를 구현한 뒤, 최종적으로 중복 코드를 제거하고 구조를 우아하게 다듬어 완료합니다 [3, 5].
|
||||
- **System Design:** 소프트웨어 설계에 앞서 테스트 가능한 구조를 강제함으로써, 결합도가 낮고 응집도가 높은 아키텍처가 점진적이고 반복적으로 도출될 수 있도록 팀의 설계 워크플로우를 구성합니다 [2, 5].
|
||||
- **Operation / Maintenance:** 운영 중 발견된 버그를 수정할 때, 버그를 재현하는 실패하는 테스트(Red)를 먼저 만들어 버그를 고치고(Green), 주변의 코드 스멜을 개선(Refactor)하여 추후 동일한 버그가 발생하지 않도록 유지보수 체계를 강화합니다 [9].
|
||||
- **Learning Path:** 주니어 개발자가 객체지향 설계와 클린 코드를 학습할 때, 단순히 예쁘게 코딩하는 것을 넘어 TDD 환경에서 동작 보존과 구조 개선을 단계적으로 달성하는 실전 훈련 파이프라인으로 활용됩니다 [5, 10].
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트에 Red-Green-Refactor 사이클을 적용하여, 기능 추가와 리팩토링 작업을 동시에 수행하다 발생하는 예기치 못한 사이드 이펙트를 차단하고, 항상 테스트로 보호받는 안정적인 코드베이스를 확보합니다 [3, 5].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Technical Debt (기술 부채)]]
|
||||
- 확장 방향: 정기적인 Refactor 단계를 무시하고 Red-Green만 반복하거나 편법을 사용했을 때 쌓이는 기술 부채가 장기적인 프로젝트 비용에 미치는 영향과 관리 전략을 확장하여 학습합니다 [11-13].
|
||||
- [[Automated Testing (자동화된 테스트)]]
|
||||
- 확장 방향: Red-Green 리팩토링의 성공을 좌우하는 테스트 피라미드, 단위 테스트(Unit Test) 작성법 및 레거시 코드에 테스트 하네스를 구축하는 방법론으로 이해를 확장합니다 [4, 14, 15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
describe('Money', () => {
|
||||
it('multiplies amount by scalar', () => {
|
||||
expect(new Money(5, 'USD').times(2)).toEqual(new Money(10, 'USD'));
|
||||
});
|
||||
});
|
||||
// → fails: Money is not defined
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Green: 매 fastest path
|
||||
```typescript
|
||||
// money.ts — Beck 의 "fake it" 단계
|
||||
export class Money {
|
||||
constructor(public amount: number, public currency: string) {}
|
||||
times(n: number): Money {
|
||||
return new Money(this.amount * n, this.currency);
|
||||
}
|
||||
// equals 는 Vitest 의 toEqual 가 structural 로 처리
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Refactor: 매 immutable + value semantics
|
||||
```typescript
|
||||
export class Money {
|
||||
private constructor(
|
||||
public readonly amount: number,
|
||||
public readonly currency: string,
|
||||
) {}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
static of(amount: number, currency: string): Money {
|
||||
if (!Number.isFinite(amount)) throw new RangeError('amount NaN');
|
||||
return new Money(amount, currency);
|
||||
}
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
times(n: number): Money {
|
||||
return Money.of(this.amount * n, this.currency);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Triangulation pattern
|
||||
```typescript
|
||||
// 매 두 번째 test 가 generalization 을 강제
|
||||
it('multiplies by 3', () => {
|
||||
expect(Money.of(5, 'USD').times(3)).toEqual(Money.of(15, 'USD'));
|
||||
});
|
||||
// → 매 hardcoded `return new Money(10, ...)` 는 더 이상 통하지 않음
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### Tidy First (Beck 2023)
|
||||
```typescript
|
||||
// 매 refactor 와 behavior change 를 별도 commit 으로 분리
|
||||
// 1. tidy first: rename, extract — pure structural
|
||||
// 2. behavior: 새 test + impl
|
||||
// 매 PR review 의 noise 감소
|
||||
```
|
||||
|
||||
### TCR (test && commit || revert) — Beck 2018
|
||||
```bash
|
||||
# 매 hardcore variant: green 이면 commit, red 이면 코드 폐기
|
||||
vitest run && git commit -am wip || git checkout -- .
|
||||
```
|
||||
|
||||
### AI-assisted RGR (Claude Code 2026)
|
||||
```typescript
|
||||
// 1. human: write Red test
|
||||
// 2. claude: minimal Green implementation
|
||||
// 3. human: review + suggest refactor
|
||||
// 4. claude: apply Extract Function, etc.
|
||||
// 매 test 의 contract 는 human 이 own
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 새 feature, 도메인 명확 | Inside-out RGR |
|
||||
| 외부 contract 우선 | Outside-in (mock-driven) |
|
||||
| Legacy, 매 test 없음 | 매 Characterization test 후 RGR |
|
||||
| Spike / prototype | RGR skip — 매 throw away 후 RGR 로 재작성 |
|
||||
| Refactor only | Red 없이 Refactor hat — 매 test 가 이미 green |
|
||||
|
||||
**기본값**: Inside-out RGR + Tidy First commit 분리.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TDD]] · [[Refactoring_Best_Practices]]
|
||||
- 변형: [[BDD]] · [[ATDD]] · [[TCR]]
|
||||
- 응용: [[Pair Programming]] · [[Mob Programming]]
|
||||
- Adjacent: [[Rule of Three (3의 법칙)]] · [[Code Smell]] · [[XP]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 well-bounded pure function, 매 algorithm, 매 domain logic. Claude Code 의 Green phase delegation 효율 높음.
|
||||
**언제 X**: 매 UI snapshot, 매 distributed system race, 매 exploration spike — RGR overhead 가 가치 초과.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Test after**: 매 implementation 후 test 추가 — 매 design feedback loss, 매 false-confidence test.
|
||||
- **Commit at Red**: 매 broken main, 매 bisect 불가.
|
||||
- **Skipping Refactor**: 매 green-and-go — 매 debt 누적.
|
||||
- **Big Red**: 매 30분 짜리 test → step too big, 매 walking skeleton 으로 분해.
|
||||
- **Refactor with failing test**: 매 두 hat 의 violation — 매 behavior change 와 cleanup 혼합.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified: Beck *TDD: By Example* (2002), *Tidy First* (2023). Martin Fowler *Refactoring 2e* (2018) Ch.1.
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — full RGR cycle, patterns, Tidy First/TCR variants |
|
||||
|
||||
Reference in New Issue
Block a user