Differences between revisions 3 and 6 (spanning 3 versions)
Revision 3 as of 2025-07-24 13:23:29
Size: 8918
Editor: 정수
Comment:
Revision 6 as of 2025-07-24 16:37:50
Size: 10545
Editor: 정수
Comment:
Deletions are marked like this. Additions are marked like this.
Line 6: Line 6:
복잡한 소프트웨어 문제를 해결하거나 새로운 기능을 구현할 때, 또는 버그를 추적할 때. 불확실성이 높고 여러 가능성이 존재하는 상황에서 어떻게 접근해야 할지 막막할 때. 복잡한 문제나 큰 시스템을 다룰 때. 어디서부터 시작해야 할지 막막하거나, 변경이 미칠 영향을 예측하기 어려운 상황. 새로운 기술을 배우거나 기존 코드를 이해해야 할 때.
Line 9: Line 9:
'''큰 변경의 함정'''

주니어 개발자들이 자주 빠지는 함정이 있다. "이 기능을 구현하려면 A도 바꾸고, B도 수정하고, C도 새로 만들어야 해"라고 생각하며 한 번에 많은 것을 바꾸려 한다.

결과는 참혹하다. 2시간 후 코드는 엉망이 되고, 어디서 문제가 생겼는지 알 수 없다. 원래 상태로 되돌리기도 어렵다. 머릿속 추측만으로는 복잡한 시스템의 동작을 정확히 예측할 수 없고, 긴 피드백 루프는 학습을 늦추며 잘못된 방향으로 오래 가게 만든다.

'''요리사의 실수'''

경험 없는 요리사가 새로운 요리를 만들 때를 생각해보자. 레시피를 보고 "설탕 대신 꿀을 넣고, 소금도 줄이고, 향신료도 바꿔보자"며 한 번에 여러 변경을 시도한다. 결과적으로 맛없는 요리가 나오지만, 무엇 때문에 실패했는지 알 수 없다. 설탕 때문인가? 소금 때문인가? 향신료 때문인가?
'''실험이라는 개념 자체가 없다'''

대부분의 사람들은 프로그래밍을 할 때 **실험**이라는 개념을 아예 가지고 있지 않다. 그들의 접근 방식은 다음과 같다:

1. **계획 → 구현 → 완성** : 머릿속으로 전체를 설계하고, 한번에 구현하려 한다
2. **추측 → 수정 → 기대** : "아마 이렇게 하면 될 것이다"라고 추측하고 수정한 뒤 되기를 기대한다
3. **검색 → 복붙 → 시도** : 스택오버플로에서 답을 찾아 복사하고 작동하기를 바란다

이런 접근법의 문제점:
- **피드백이 늦다** : 전체를 다 만들고 나서야 작동하는지 안 하는지 안다
- **실패 비용이 크다** : 잘못되면 처음부터 다시 해야 한다
- **학습이 일어나지 않는다** : 왜 작동하는지 작동하지 않는지 이해하지 못한다
- **복잡성에 압도된다** : 큰 문제 앞에서 어디서부터 손을 대야 할지 모른다

'''진짜 문제: 큰 덩어리에서 작은 부분을 떼어내지 못함'''

핵심 문제는 **큰 복합체에서 관심 있는 작은 부분을 분리해내는 능력**이 없다는 것이다.

- 300줄짜리 함수를 보면서 "어디서부터 손을 대야 할까?" 막막해한다
- 버그가 있을 때 "전체 시스템이 복잡해서..." 라며 포기한다
- 새로운 라이브러리를 사용할 때 전체 문서를 다 읽으려 한다
Line 20: Line 32:
'''작은 실험의 힘'''

아주 작은 가설을 세우고 빠르게 검증할 수 있는 환경을 만들어라. 마치 과학자가 실험실에서 하나의 변수만 바꿔가며 실험하는 것처럼.

=== 1단계: 명확한 가설 세우기 ===
막연한 "아마 이럴 것이다"가 아니라 구체적인 가설을 세워라.

나쁜 예: "이 코드가 느린 것 같다"
좋은 예: "이 반복문에서 데이터베이스 조회가 N번 발생해서 느릴 것이다"

=== 2단계: 최소 실험 설계 ===
가설을 검증할 수 있는 가장 작은 실험을 만들어라.

예시: 데이터베이스 조회 가설을 검증하려면
- 로그를 추가해서 실제 쿼리 횟수 확인
- 작은 데이터셋으로 테스트
- 쿼리 실행 시간 측정

=== 3단계: 안전망 구축 ===
실패해도 쉽게 되돌아갈 수 있는 안전망을 준비하라.

- git commit으로 현재 상태 저장
- 브랜치 생성해서 실험
- 테스트 코드로 기존 기능 보호
- 백업 데이터 준비

=== 4단계: 빠른 피드백 루프 ===
결과를 즉시 확인할 수 있는 환경을 만들어라.

- 자동화된 테스트 실행
- 핫 리로드 개발 환경
- 실시간 로그 모니터링
- 간단한 확인 스크립트

=== 5단계: 격리된 환경 ===
다른 요소들의 영향을 받지 않도록 격리하라.

- 테스트용 데이터베이스 사용
- 모의 객체(mock)로 외부 의존성 제거
- 개발 전용 환경에서 실험
- 한 번에 하나의 변수만 변경

=== 6단계: 가추법 활용 ===
관찰된 현상에서 가능한 원인을 추론하고 다시 검증하라.

현상: "API 응답이 느리다"
가능한 원인들:
- 데이터베이스 쿼리가 느림 → 쿼리 실행 계획 확인
- 네트워크 지연 → 로컬 테스트로 비교
- 메모리 부족 → 메모리 사용량 모니터링

== Detailed Examples ==

=== 예시 1: 새로운 기능 구현 ===
'''상황:''' 사용자 프로필 페이지에 '좋아요' 기능 추가

'''잘못된 접근:'''
- 데이터베이스 스키마 변경
- API 엔드포인트 추가
- 프론트엔드 UI 구현
- 알림 기능 추가
- 권한 검증 로직 추가
모든 것을 한 번에 구현 → 3일 후 동작하지 않음

'''TinyExperiment 접근:'''
1. '''가설:''' "좋아요 데이터를 저장할 수 있다"
   - 임시 테이블 생성
   - 간단한 INSERT/SELECT 쿼리 테스트
   - 5분 만에 검증 완료

2. '''가설:''' "API로 좋아요 데이터를 주고받을 수 있다"
   - 기본적인 POST/GET 엔드포인트만 구현
   - Postman으로 테스트
   - 10분 만에 검증 완료

3. '''가설:''' "프론트엔드에서 API를 호출할 수 있다"
   - 단순한 버튼과 AJAX 호출만 구현
   - UI는 나중에 다듬기
   - 15분 만에 검증 완료

각 단계가 성공한 후 다음 단계로 진행. 실패하면 원인을 정확히 알 수 있음.

=== 예시 2: 버그 디버깅 ===
'''상황:''' "로그인 후 대시보드가 가끔 안 보인다"는 신고

'''잘못된 접근:'''
코드를 훑어보며 "아마 세션 문제일 것이다" 추측하고 세션 관련 코드를 모두 수정

'''TinyExperiment 접근:'''
1. '''가설:''' "재현 가능한 조건이 있다"
   - 다양한 브라우저, 사용자로 테스트
   - 재현 조건 발견: "IE에서만 발생"

2. '''가설:''' "특정 브라우저의 문제다"
   - 콘솔 로그 확인
   - 네트워크 탭에서 요청 확인
   - JavaScript 오류 발견

3. '''가설:''' "이 JavaScript 오류가 원인이다"
   - console.log 추가해서 실행 경로 추적
   - 특정 함수에서 오류 발생 확인

4. '''가설:''' "이 함수의 이 부분이 문제다"
   - 최소한의 수정으로 오류 해결
   - 테스트로 검증

=== 예시 3: 성능 개선 ===
'''상황:''' "페이지 로딩이 너무 느려요"

'''TinyExperiment 접근:'''
1. '''측정부터:''' 브라우저 개발자 도구로 정확한 로딩 시간 확인
2. '''가설 1:''' "이미지가 너무 크다" → 이미지 최적화 후 측정
3. '''가설 2:''' "JavaScript 파일이 크다" → 번들 크기 분석
4. '''가설 3:''' "데이터베이스 쿼리가 느리다" → 쿼리 실행 시간 측정

각 개선 후 실제 측정치로 효과 확인.

== 요리사의 지혜 (은유) ==
훌륭한 요리사는 새로운 요리를 개발할 때 이렇게 한다:

1. '''기본 레시피로 시작''' - 검증된 방법부터
2. '''한 번에 하나만 바꾸기''' - 설탕량만 조정, 다른 것은 그대로
3. '''맛을 보며 조정''' - 변경 후 즉시 결과 확인
4. '''기록 남기기''' - 무엇을 바꿨는지, 결과가 어땠는지
5. '''실패해도 괜찮은 환경''' - 작은 양으로 실험, 큰 파티 음식은 나중에

프로그래밍도 마찬가지다. 경험 많은 개발자는 작은 실험을 통해 점진적으로 시스템을 이해하고 개선한다.

== Common Anti-Patterns (피해야 할 것들) ==

=== "Big Bang" 개발 ===
- 한 번에 많은 기능을 구현하려고 함
- 실패 시 원인을 찾기 어려움
- 되돌리기 어려움

=== "추측 기반" 디버깅 ===
- 현상을 제대로 관찰하지 않고 추측으로 수정
- 한 번에 여러 부분을 수정
- 실제 원인과 다른 곳을 수정

=== "완벽주의" 함정 ===
- 실험 환경을 너무 완벽하게 만들려고 함
- 실험보다 환경 구축에 더 많은 시간 소모
- 간단한 실험으로도 충분한 상황에서 과도한 준비
'''TinyExperiment의 3단계 사이클'''

=== 1단계: 작은 부분 분리하기 (Detachment) ===

**큰 복합체에서 실험하고 싶은 작은 부분만 떼어내라.**

이것이 TinyExperiment의 핵심 기술이다. 전체 시스템이 아니라 **울타리를 쳐서 특정 영역만** 분리한다.

'''분리 기법들:'''
- **함수 단위 분리** : 300줄 함수에서 10줄짜리 핵심 로직만 따로 떼기
- **데이터 단위 분리** : 복잡한 데이터에서 샘플 3-4개만 따로 준비하기
- **시나리오 단위 분리** : 100가지 경우 중 가장 간단한 1가지만 먼저 하기
- **기능 단위 분리** : 전체 시스템에서 한 가지 기능만 독립적으로 실행하기

=== 2단계: 실험 가능하게 만들기 (Make it Experiment-able) ===

**분리한 부분을 빠르고 안전하게 실험할 수 있는 환경을 구축하라.**

이 단계에서 **훈련된 창의성**이 필요하다. 기존 도구의 한계를 받아들이지 말고, 현재 상황에서 가능한 최선의 실험 환경을 만들어라.

'''실험 환경 구축 사례:'''

**구글 앱스 스크립트 예시** (유닛테스트가 없는 환경):
{{{
function testDataParsing() {
  console.log("날짜 파싱:", parseDate("2024-01-15") === "2024/01/15" ? "PASS" : "FAIL");
  console.log("빈 데이터:", handleEmpty("") === null ? "PASS" : "FAIL");
  console.log("숫자 변환:", toNumber("123") === 123 ? "PASS" : "FAIL");
}
}}}

**복잡한 API 호출 테스트**:
{{{
// 실제 API 대신 가짜 데이터로 실험
const mockData = { users: [{ id: 1, name: "test" }] };
console.log("사용자 필터링:", filterActiveUsers(mockData));
}}}

**데이터베이스 쿼리 실험**:
{{{
// 전체 DB 대신 작은 테스트 데이터로
const testRows = [
  { id: 1, status: 'active', score: 85 },
  { id: 2, status: 'inactive', score: 92 }
];
console.log("필터 결과:", filterByStatus(testRows, 'active'));
}}}

=== 3단계: 실험 휠 돌리기 (Flying the Experiment Wheel) ===

**빠른 실험 반복을 통해 학습하라.**

이제 **찔러보고 → 반응 관찰 → 학습 → 조정 → 다시 찔러보기** 사이클을 빠르게 돌린다.

'''실험 휠의 구성 요소:'''
- **Poke (찔러보기)** : 작은 변경을 가한다
- **Observe (관찰)** : 시스템의 반응을 본다
- **Learn (학습)** : 왜 그런 결과가 나왔는지 이해한다
- **Adjust (조정)** : 다음 실험을 위해 전략을 수정한다

== The Learning Laboratory ==

'''왜 빠른 실험 반복이 최고의 학습 환경인가?'''

TinyExperiment의 진짜 목적은 **학습**이다. 빠른 실험 반복은 다음을 가능하게 한다:

**1. 즉각적인 피드백**
- 추측을 몇 초 안에 검증할 수 있다
- 잘못된 가정을 빨리 발견하고 수정한다
- "왜?"에 대한 답을 즉시 얻는다

**2. 안전한 실패**
- 실패 비용이 거의 없다 (몇 초면 되돌릴 수 있음)
- 실패를 두려워하지 않고 과감하게 시도한다
- 실패에서 학습할 수 있다

**3. 깊은 이해**
- 표면적인 지식이 아니라 내부 원리를 이해한다
- "어떻게"가 아니라 "왜"를 안다
- 비슷한 문제에 응용할 수 있는 통찰을 얻는다

== Real Examples ==

=== 예시 1: 복잡한 정규표현식 이해하기 ===

**상황**: 기존 코드에 있는 복잡한 정규표현식을 수정해야 함
{{{
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
}}}

**전형적인 접근**: 정규표현식 문서를 읽고 전체를 이해하려 시도

**TinyExperiment 접근**:

1. **분리**: 정규표현식을 부분별로 나눔
2. **실험 환경**: 간단한 테스트 함수 생성
{{{
function testRegexPart(pattern, testString) {
  const regex = new RegExp(pattern);
  console.log(`"${testString}" -> ${regex.test(testString) ? 'MATCH' : 'NO MATCH'}`);
}

// 각 부분별로 실험
testRegexPart('(?=.*[a-z])', 'Hello123!'); // 소문자 포함 확인
testRegexPart('(?=.*[A-Z])', 'Hello123!'); // 대문자 포함 확인
testRegexPart('(?=.*\\d)', 'Hello123!'); // 숫자 포함 확인
}}}

3. **학습**: 각 부분이 무엇을 하는지 실험으로 이해
4. **조정**: 필요한 부분만 수정

**결과**: 15분만에 복잡한 정규표현식의 구조를 완전히 이해

=== 예시 2: 성능 병목 찾기 ===

**상황**: 페이지 로딩이 8초나 걸리는 문제

**전형적인 접근**: 프로파일러로 전체 분석하려 시도

**TinyExperiment 접근**:

1. **분리**: 로딩 과정을 단계별로 나눔
{{{
console.time('데이터 로딩');
const data = await fetchData();
console.timeEnd('데이터 로딩'); // 2초

console.time('데이터 가공');
const processed = processData(data);
console.timeEnd('데이터 가공'); // 5초 <- 병목 발견!

console.time('렌더링');
renderData(processed);
console.timeEnd('렌더링'); // 1초
}}}

2. **실험 환경**: 데이터 가공 부분만 분리해서 테스트
3. **학습**: N+1 쿼리 문제 발견
4. **조정**: 배치 처리로 변경

**결과**: 8초 → 1.5초로 성능 개선

=== 예시 3: 새로운 API 익히기 ===

**상황**: 복잡한 REST API 문서 100페이지

**전형적인 접근**: 문서를 처음부터 끝까지 읽으려 시도

**TinyExperiment 접근**:

1. **분리**: 가장 간단한 API 하나만 선택
2. **실험 환경**: curl이나 Postman으로 바로 호출
{{{
curl -X GET "https://api.example.com/users/1" -H "Authorization: Bearer token"
}}}

3. **학습**: 응답 구조 파악, 인증 방식 이해
4. **조정**: 다음 실험할 API 선택

**결과**: 2시간만에 API의 핵심 패턴 파악, 실제 개발 시작 가능

== Common Anti-Patterns ==

=== 1. 전체 이해하려는 강박 ===
- **증상**: "전체를 다 이해하고 나서 시작해야 해"
- **문제**: 영원히 시작하지 못함
- **해결**: 이해해야 할 최소한만 분리해서 실험

=== 2. 완벽한 환경 기다리기 ===
- **증상**: "제대로 된 테스트 프레임워크부터 세팅하자"
- **문제**: 환경 구축에만 시간 소모
- **해결**: console.log라도 활용해서 즉시 시작

=== 3. 한번에 너무 많이 바꾸기 ===
- **증상**: "이것도 고치고 저것도 고치고..."
- **문제**: 어떤 변경이 효과가 있었는지 모름
- **해결**: 한 번에 하나씩만 변경

== The Experiment Mindset ==

TinyExperiment를 체화하면 다음과 같은 사고방식이 자연스러워진다:

**"이걸 어떻게 작게 쪼갤 수 있을까?"**
**"이 부분만 따로 실험해볼 수 있을까?"**
**"5분 안에 결과를 확인할 수 있을까?"**
**"실패해도 쉽게 되돌릴 수 있을까?"**

이런 질문들이 습관이 되면, 복잡한 문제 앞에서도 당황하지 않는다. 항상 "작은 실험부터 시작하자"는 접근법이 자연스러워진다.
Line 167: Line 223:
=== 개발 환경 도구 ===
- '''Hot reload:''' 코드 변경 시 즉시 반영
- '''REPL:''' 작은 코드 조각을 즉시 실행
- '''디버거:''' 단계별 실행과 상태 확인
- '''로깅:''' 실행 경로와 변수 값 추적

=== 테스팅 도구 ===
- '''Unit tests:''' 작은 단위의 동작 검증
- '''Test fixtures:''' 일관된 테스트 환경
- '''Mock objects:''' 외부 의존성 제거
- '''Test doubles:''' 복잡한 객체의 간단한 대체재

=== 프로파일링 도구 ===
- '''성능 측정:''' 실행 시간, 메모리 사용량
- '''데이터베이스 쿼리 분석:''' 실행 계획, 인덱스 사용
- '''네트워크 모니터링:''' 요청/응답 시간, 데이터 크기
**빠른 실험을 위한 도구들:**
- **REPL**: 언어별 인터랙티브 셸
- **console.log/print**: 가장 기본적이지만 강력한 관찰 도구
- **단위 테스트**: 작은 부분을 격리해서 실험
- **git stash/branch**: 안전한 실험을 위한 버전 관리
- **디버거**: 코드 실행 과정을 관찰
- **프로파일러**: 성능 병목을 관찰

**핵심은 도구가 아니라 마음가짐**이다. 어떤 환경에서든 실험할 방법을 찾아내는 창의성이 중요하다.
Line 185: Line 234:
TinyExperiment를 습관화하면:

- '''불확실성이 줄어든다''' - 추측 대신 확실한 지식 축적
- '''학습이 가속화된다''' - 빠른 피드백으로 경험 축적
- '''실패 비용이 낮아진다''' - 작은 실패로 큰 실패 방지
- '''자신감이 향상된다''' - 복잡한 문제도 작은 단위로 분해하여 해결
- '''시스템 이해가 깊어진다''' - 점진적 탐색으로 전체 그림 파악
- '''팀 협업이 개선된다''' - 명확한 가설과 결과로 소통

TinyExperiment를 체화하면:

- **복잡성에 압도되지 않는다**: 큰 문제도 작은 실험들의 연속으로 본다
- **학습 속도가 빨라진다**: 빠른 피드백으로 깊은 이해를 얻는다
- **자신감이 생긴다**: 실패를 두려워하지 않고 시도한다
- **문제 해결력이 향상된다**: 체계적인 실험 방법을 가진다

가장 중요한 변화는 **"실험하는 프로그래머"**가 되는 것이다. 추측하고 기대하는 대신, 실험하고 학습한다.
Line 195: Line 245:
* '''Enables:''' [[BabyStep]], [[UseAbduction]], [[HereAndNowDebugging]]
* '''Used by:''' [[TddIsDesignActivity]], [[PiecemealGrowthCenterFirst]]
* '''Complements:''' [[ShortFeedbackCycle]], [[MicroCommit]]
* '''Conflicts with:''' BigBangDevelopment, GuessBasedDebugging
* '''연관:''' [[BabySteps]], [[GreenRefuge]] - 작은 단계와 안전한 되돌림
* '''활용:''' [[DesignThroughTest]], [[DetectiveWork]] - 설계와 디버깅에서의 실험
* '''보완:''' [[TightLoop]], [[AtomicCommit]] - 빠른 피드백과 작은 변경
Line 201: Line 250:
* [[추법]] - 관찰에서 가설을 도출하는 사고 방
* Kent Beck의 "Test Driven Development" - 작은 테스트로 설계하기
* Gary Klein의 "Sources of Power" - 전문가의 직관과 가설 검증
* 과학
방법론 - 가설-실험-검증의 순환
* [[추법]] - 가설을 세우고 검증하는 사고 방
* Kent Beck의 "Test Driven Development" - 작은 테스트로 시작하기
* Gary Klein의 "Sources of Power" - 전문가의 직관적 사고 패턴

TinyExperiment

Context

복잡한 문제나 큰 시스템을 다룰 때. 어디서부터 시작해야 할지 막막하거나, 변경이 미칠 영향을 예측하기 어려운 상황. 새로운 기술을 배우거나 기존 코드를 이해해야 할 때.

Problem

실험이라는 개념 자체가 없다

대부분의 사람들은 프로그래밍을 할 때 **실험**이라는 개념을 아예 가지고 있지 않다. 그들의 접근 방식은 다음과 같다:

1. **계획 → 구현 → 완성** : 머릿속으로 전체를 설계하고, 한번에 구현하려 한다 2. **추측 → 수정 → 기대** : "아마 이렇게 하면 될 것이다"라고 추측하고 수정한 뒤 되기를 기대한다 3. **검색 → 복붙 → 시도** : 스택오버플로에서 답을 찾아 복사하고 작동하기를 바란다

이런 접근법의 문제점: - **피드백이 늦다** : 전체를 다 만들고 나서야 작동하는지 안 하는지 안다 - **실패 비용이 크다** : 잘못되면 처음부터 다시 해야 한다 - **학습이 일어나지 않는다** : 왜 작동하는지 작동하지 않는지 이해하지 못한다 - **복잡성에 압도된다** : 큰 문제 앞에서 어디서부터 손을 대야 할지 모른다

진짜 문제: 큰 덩어리에서 작은 부분을 떼어내지 못함

핵심 문제는 **큰 복합체에서 관심 있는 작은 부분을 분리해내는 능력**이 없다는 것이다.

- 300줄짜리 함수를 보면서 "어디서부터 손을 대야 할까?" 막막해한다 - 버그가 있을 때 "전체 시스템이 복잡해서..." 라며 포기한다 - 새로운 라이브러리를 사용할 때 전체 문서를 다 읽으려 한다

Solution

TinyExperiment의 3단계 사이클

1단계: 작은 부분 분리하기 (Detachment)

**큰 복합체에서 실험하고 싶은 작은 부분만 떼어내라.**

이것이 TinyExperiment의 핵심 기술이다. 전체 시스템이 아니라 **울타리를 쳐서 특정 영역만** 분리한다.

분리 기법들: - **함수 단위 분리** : 300줄 함수에서 10줄짜리 핵심 로직만 따로 떼기 - **데이터 단위 분리** : 복잡한 데이터에서 샘플 3-4개만 따로 준비하기 - **시나리오 단위 분리** : 100가지 경우 중 가장 간단한 1가지만 먼저 하기 - **기능 단위 분리** : 전체 시스템에서 한 가지 기능만 독립적으로 실행하기

2단계: 실험 가능하게 만들기 (Make it Experiment-able)

**분리한 부분을 빠르고 안전하게 실험할 수 있는 환경을 구축하라.**

이 단계에서 **훈련된 창의성**이 필요하다. 기존 도구의 한계를 받아들이지 말고, 현재 상황에서 가능한 최선의 실험 환경을 만들어라.

실험 환경 구축 사례:

**구글 앱스 스크립트 예시** (유닛테스트가 없는 환경):

function testDataParsing() {
  console.log("날짜 파싱:", parseDate("2024-01-15") === "2024/01/15" ? "PASS" : "FAIL");
  console.log("빈 데이터:", handleEmpty("") === null ? "PASS" : "FAIL");  
  console.log("숫자 변환:", toNumber("123") === 123 ? "PASS" : "FAIL");
}

**복잡한 API 호출 테스트**:

// 실제 API 대신 가짜 데이터로 실험
const mockData = { users: [{ id: 1, name: "test" }] };
console.log("사용자 필터링:", filterActiveUsers(mockData));

**데이터베이스 쿼리 실험**:

// 전체 DB 대신 작은 테스트 데이터로
const testRows = [
  { id: 1, status: 'active', score: 85 },
  { id: 2, status: 'inactive', score: 92 }
];
console.log("필터 결과:", filterByStatus(testRows, 'active'));

3단계: 실험 휠 돌리기 (Flying the Experiment Wheel)

**빠른 실험 반복을 통해 학습하라.**

이제 **찔러보고 → 반응 관찰 → 학습 → 조정 → 다시 찔러보기** 사이클을 빠르게 돌린다.

실험 휠의 구성 요소: - **Poke (찔러보기)** : 작은 변경을 가한다 - **Observe (관찰)** : 시스템의 반응을 본다 - **Learn (학습)** : 왜 그런 결과가 나왔는지 이해한다 - **Adjust (조정)** : 다음 실험을 위해 전략을 수정한다

The Learning Laboratory

왜 빠른 실험 반복이 최고의 학습 환경인가?

TinyExperiment의 진짜 목적은 **학습**이다. 빠른 실험 반복은 다음을 가능하게 한다:

**1. 즉각적인 피드백** - 추측을 몇 초 안에 검증할 수 있다 - 잘못된 가정을 빨리 발견하고 수정한다 - "왜?"에 대한 답을 즉시 얻는다

**2. 안전한 실패** - 실패 비용이 거의 없다 (몇 초면 되돌릴 수 있음) - 실패를 두려워하지 않고 과감하게 시도한다 - 실패에서 학습할 수 있다

**3. 깊은 이해** - 표면적인 지식이 아니라 내부 원리를 이해한다 - "어떻게"가 아니라 "왜"를 안다 - 비슷한 문제에 응용할 수 있는 통찰을 얻는다

Real Examples

예시 1: 복잡한 정규표현식 이해하기

**상황**: 기존 코드에 있는 복잡한 정규표현식을 수정해야 함

/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/

**전형적인 접근**: 정규표현식 문서를 읽고 전체를 이해하려 시도

**TinyExperiment 접근**:

1. **분리**: 정규표현식을 부분별로 나눔 2. **실험 환경**: 간단한 테스트 함수 생성

function testRegexPart(pattern, testString) {
  const regex = new RegExp(pattern);
  console.log(`"${testString}" -> ${regex.test(testString) ? 'MATCH' : 'NO MATCH'}`);
}

// 각 부분별로 실험
testRegexPart('(?=.*[a-z])', 'Hello123!');  // 소문자 포함 확인
testRegexPart('(?=.*[A-Z])', 'Hello123!');  // 대문자 포함 확인  
testRegexPart('(?=.*\\d)', 'Hello123!');    // 숫자 포함 확인

3. **학습**: 각 부분이 무엇을 하는지 실험으로 이해 4. **조정**: 필요한 부분만 수정

**결과**: 15분만에 복잡한 정규표현식의 구조를 완전히 이해

예시 2: 성능 병목 찾기

**상황**: 페이지 로딩이 8초나 걸리는 문제

**전형적인 접근**: 프로파일러로 전체 분석하려 시도

**TinyExperiment 접근**:

1. **분리**: 로딩 과정을 단계별로 나눔

console.time('데이터 로딩');
const data = await fetchData();
console.timeEnd('데이터 로딩'); // 2초

console.time('데이터 가공');  
const processed = processData(data);
console.timeEnd('데이터 가공'); // 5초 <- 병목 발견!

console.time('렌더링');
renderData(processed);
console.timeEnd('렌더링'); // 1초

2. **실험 환경**: 데이터 가공 부분만 분리해서 테스트 3. **학습**: N+1 쿼리 문제 발견 4. **조정**: 배치 처리로 변경

**결과**: 8초 → 1.5초로 성능 개선

예시 3: 새로운 API 익히기

**상황**: 복잡한 REST API 문서 100페이지

**전형적인 접근**: 문서를 처음부터 끝까지 읽으려 시도

**TinyExperiment 접근**:

1. **분리**: 가장 간단한 API 하나만 선택 2. **실험 환경**: curl이나 Postman으로 바로 호출

curl -X GET "https://api.example.com/users/1" -H "Authorization: Bearer token"

3. **학습**: 응답 구조 파악, 인증 방식 이해 4. **조정**: 다음 실험할 API 선택

**결과**: 2시간만에 API의 핵심 패턴 파악, 실제 개발 시작 가능

Common Anti-Patterns

1. 전체 이해하려는 강박

- **증상**: "전체를 다 이해하고 나서 시작해야 해" - **문제**: 영원히 시작하지 못함 - **해결**: 이해해야 할 최소한만 분리해서 실험

2. 완벽한 환경 기다리기

- **증상**: "제대로 된 테스트 프레임워크부터 세팅하자" - **문제**: 환경 구축에만 시간 소모 - **해결**: console.log라도 활용해서 즉시 시작

3. 한번에 너무 많이 바꾸기

- **증상**: "이것도 고치고 저것도 고치고..." - **문제**: 어떤 변경이 효과가 있었는지 모름 - **해결**: 한 번에 하나씩만 변경

The Experiment Mindset

TinyExperiment를 체화하면 다음과 같은 사고방식이 자연스러워진다:

**"이걸 어떻게 작게 쪼갤 수 있을까?"** **"이 부분만 따로 실험해볼 수 있을까?"** **"5분 안에 결과를 확인할 수 있을까?"** **"실패해도 쉽게 되돌릴 수 있을까?"**

이런 질문들이 습관이 되면, 복잡한 문제 앞에서도 당황하지 않는다. 항상 "작은 실험부터 시작하자"는 접근법이 자연스러워진다.

Tools and Techniques

**빠른 실험을 위한 도구들:** - **REPL**: 언어별 인터랙티브 셸 - **console.log/print**: 가장 기본적이지만 강력한 관찰 도구 - **단위 테스트**: 작은 부분을 격리해서 실험 - **git stash/branch**: 안전한 실험을 위한 버전 관리 - **디버거**: 코드 실행 과정을 관찰 - **프로파일러**: 성능 병목을 관찰

**핵심은 도구가 아니라 마음가짐**이다. 어떤 환경에서든 실험할 방법을 찾아내는 창의성이 중요하다.

Resulting Context

TinyExperiment를 체화하면:

- **복잡성에 압도되지 않는다**: 큰 문제도 작은 실험들의 연속으로 본다 - **학습 속도가 빨라진다**: 빠른 피드백으로 깊은 이해를 얻는다 - **자신감이 생긴다**: 실패를 두려워하지 않고 시도한다 - **문제 해결력이 향상된다**: 체계적인 실험 방법을 가진다

가장 중요한 변화는 **"실험하는 프로그래머"**가 되는 것이다. 추측하고 기대하는 대신, 실험하고 학습한다.

* 연관: BabySteps, GreenRefuge - 작은 단계와 안전한 되돌림 * 활용: DesignThroughTest, DetectiveWork - 설계와 디버깅에서의 실험 * 보완: TightLoop, AtomicCommit - 빠른 피드백과 작은 변경

See Also

* 추론법 - 가설을 세우고 검증하는 사고 방법 * Kent Beck의 "Test Driven Development" - 작은 테스트로 시작하기 * Gary Klein의 "Sources of Power" - 전문가의 직관적 사고 패턴


CategoryPattern

TinyExperiment (last edited 2025-12-30 10:00:26 by 정수)