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를 체화하면:
- **복잡성에 압도되지 않는다**: 큰 문제도 작은 실험들의 연속으로 본다 - **학습 속도가 빨라진다**: 빠른 피드백으로 깊은 이해를 얻는다 - **자신감이 생긴다**: 실패를 두려워하지 않고 시도한다 - **문제 해결력이 향상된다**: 체계적인 실험 방법을 가진다
가장 중요한 변화는 **"실험하는 프로그래머"**가 되는 것이다. 추측하고 기대하는 대신, 실험하고 학습한다.
Related Patterns
* 연관: BabySteps, GreenRefuge - 작은 단계와 안전한 되돌림 * 활용: DesignThroughTest, DetectiveWork - 설계와 디버깅에서의 실험 * 보완: TightLoop, AtomicCommit - 빠른 피드백과 작은 변경
See Also
* 추론법 - 가설을 세우고 검증하는 사고 방법 * Kent Beck의 "Test Driven Development" - 작은 테스트로 시작하기 * Gary Klein의 "Sources of Power" - 전문가의 직관적 사고 패턴