Differences between revisions 3 and 4
Revision 3 as of 2025-07-24 13:23:29
Size: 8918
Editor: 정수
Comment:
Revision 4 as of 2025-07-24 13:27:57
Size: 11260
Editor: 정수
Comment:
Deletions are marked like this. Additions are marked like this.
Line 9: Line 9:
''' 변경함정''' ''' 요리사이야기'''
Line 11: Line 11:
주니어 개발자들이 자주 빠지는 함정이 있다. "이 기능을 구현하려면 A도 바꾸고, B도 수정하고, C도 새로 만들어야 해"라고 생각하며 한 번에 많은 것을 바꾸려 한다. 어느 레스토랑에 두 명의 요리사가 있었다. 둘 다 새로운 파스타 요리를 개발하라는 임무를 받았다.
Line 13: Line 13:
결과는 참혹하다. 2시간 후 코드는 엉망이 되고, 어디서 문제가 생겼는지 알 수 없다. 원래 상태로 되돌리기도 어렵다. 머릿속 추측만으로는 복잡한 시스템의 동작을 정확히 예측할 수 없고, 긴 피드백 루프는 학습을 늦추며 잘못된 방향으로 오래 가게 만든다. 첫 번째 요리사 알렉스는 야심이 컸다. "완전히 새로운 파스타를 만들어보자!" 그는 면도 직접 만들고, 소스도 새로 개발하고, 치즈도 특별한 것을 사용하고, 허브도 독특한 조합으로 넣기로 했다. 3시간 동안 열심히 요리한 결과, 이상한 맛의 음식이 나왔다. 손님들은 고개를 저었다. 하지만 알렉스는 무엇이 잘못되었는지 알 수 없었다. 면 때문일까? 소스 때문일까? 치즈 때문일까? 처음부터 다시 시작해야 했다.
Line 15: Line 15:
'''요리사의 실수''' 두 번째 요리사 베타는 다르게 접근했다. 먼저 검증된 기본 파스타를 만들어 맛을 확인했다. 그 다음 소스만 조금 바꿔서 다시 맛을 보았다. "좋아, 이건 괜찮네." 그리고 치즈를 한 종류만 바꿔서 또 맛을 보았다. 각 단계마다 작은 접시에 조금씩 만들어서 확인했다. 만약 어떤 변경이 맛을 망쳤다면, 바로 이전 단계로 돌아갔다. 2시간 후, 손님들이 "이 파스타 정말 맛있네요!"라고 말하는 요리가 완성되었다.
Line 17: Line 17:
경험 없는 요리사가 새로운 요리를 만들 때를 생각해보자. 레시피를 보고 "설탕 대신 꿀을 넣고, 소금도 줄이고, 향신료도 바꿔보자"며 한 번에 여러 변경을 시도한다. 결과적으로 맛없는 요리가 나오지만, 무엇 때문에 실패했는지 알 수 없다. 설탕 때문인가? 소금 때문인가? 향신료 때문인가? 개발자들도 마찬가지다. 복잡한 기능을 한 번에 모두 구현하려다가 알렉스처럼 실패하거나, 베타처럼 작은 단계로 나누어 성공하거나. 차이는 접근 방법에 있다.
Line 20: Line 20:
'''작은 실험 ''' '''작은 실험실을 만들어라'''
Line 22: Line 22:
아주 작은 가설을 세우고 빠르게 검증할 수 있는 환경을 만들어라. 마치 과학자가 실험실에서 하나의 변수만 바꿔가며 실험하는 것처럼. 베타 요리사의 지혜는 단순했다. 큰 변화를 작은 실험들로 나누고, 각 실험의 결과를 즉시 확인하고, 실패해도 쉽게 되돌아갈 수 있게 준비하는 것이었다.
Line 24: Line 24:
=== 1단계: 명확한 가설 세우기 ===
막연한 "아마 이럴 것이다"가 아니라 구체적인 가설을 세워라.
프로그래밍에서도 이와 같은 "작은 실험실"을 만들 수 있다. 새로운 기능을 구현할 때, 버그를 찾을 때, 성능을 개선할 때마다 이 방법을 사용하라.
Line 27: Line 26:
나쁜 예: "이 코드가 느린 것 같다"
좋은 예: "이 반복문에서 데이터베이스 조회가 N번 발생해서 느릴 것이다"
'''명확한 가설부터 시작하라'''
Line 30: Line 28:
=== 2단계: 최소 실험 설계 ===
가설을 검증할 수 있는 가장 작은 실험을 만들어라.
베타가 "이 소스가 더 맛있을 것이다"라는 구체적인 가설을 세웠듯이, 개발에서도 명확한 가설을 세워야 한다. "이 함수가 느릴 것이다"가 아니라 "이 반복문에서 데이터베이스를 N번 호출해서 느릴 것이다"처럼 구체적으로 말이다.
Line 33: Line 30:
예시: 데이터베이스 조회 가설을 검증하려면
- 로그를 추가해서 실제 쿼리 횟수 확인
- 작은 데이터셋으로 테스트
- 쿼리 실행 시간 측정
'''안전한 실험 환경을 구축하라'''
Line 38: Line 32:
=== 3단계: 안전망 구축 ===
실패해도 쉽게 되돌아갈 수 있는 안전망을 준비하라.
베타는 작은 접시에 조금씩 만들어서 실험했다. 만약 망쳐도 전체 요리가 아니라 작은 부분만 버리면 되었다. 개발에서는 git 브랜치가 이 역할을 한다. 새로운 시도를 할 때마다 브랜치를 만들고, 실패하면 쉽게 되돌아간다. 테스트 코드는 기존 기능이 망가지지 않았는지 확인하는 안전망 역할을 한다.
Line 41: Line 34:
- git commit으로 현재 상태 저장
- 브랜치 생성해서 실험
- 테스트 코드로 기존 기능 보호
- 백업 데이터 준비
'''즉시 피드백을 받아라'''
Line 46: Line 36:
=== 4단계: 빠른 피드백 루프 ===
결과를 즉시 확인할 수 있는 환경을 만들어라.
베타는 각 단계마다 맛을 보았다. 3시간 후에 맛을 보는 게 아니라 5분마다 맛을 확인했다. 개발에서도 마찬가지다. 코드를 100줄 짠 후에 테스트하는 게 아니라, 5줄 짤 때마다 실행해보고 확인한다. 자동화된 테스트, 핫 리로드, 간단한 print문까지 모든 것이 즉시 피드백을 주는 도구가 된다.
Line 49: Line 38:
- 자동화된 테스트 실행
- 핫 리로드 개발 환경
- 실시간 로그 모니터링
- 간단한 확인 스크립트
'''한 번에 하나씩만 바꿔라'''
Line 54: Line 40:
=== 5단계: 격리된 환경 ===
다른 요소들의 영향을 받지 않도록 격리하라.
베타의 가장 중요한 원칙이다. 소스를 바꿀 때는 다른 것은 그대로 두고 소스만 바꿨다. 그래서 결과가 나빠지면 소스 때문이라는 걸 확실히 알 수 있었다. 개발에서도 한 번에 하나의 변수만 바꿔야 한다. 함수를 수정할 때 동시에 데이터베이스 스키마까지 바꾸면, 문제가 생겼을 때 원인을 찾기 어렵다.
Line 57: Line 42:
- 테스트용 데이터베이스 사용
- 모의 객체(mock)로 외부 의존성 제거
- 개발 전용 환경에서 실험
- 한 번에 하나의 변수만 변경
== Examples ==
Line 62: Line 44:
=== 6단계: 가추법 활용 ===
관찰된 현상에서 가능한 원인을 추론하고 다시 검증하라.
'''신입 개발자 준호의 첫 번째 버그 수정'''
Line 65: Line 46:
현상: "API 응답이 느리다"
가능한 원인들:
- 데이터베이스 쿼리가 느림 → 쿼리 실행 계획 확인
- 네트워크 지연 → 로컬 테스트로 비교
- 메모리 부족 → 메모리 사용량 모니터링
준호는 "로그인 후 대시보드가 가끔 안 보인다"는 버그 리포트를 받았다. 처음에는 겁이 났다. 로그인 시스템은 복잡하고, 대시보드도 여러 컴포넌트로 이루어져 있었다.
Line 71: Line 48:
== Detailed Examples == 시니어 개발자 민지가 조언했다. "베타 요리사처럼 해봐. 한 번에 모든 걸 고치려 하지 말고, 작은 실험부터 시작해."
Line 73: Line 50:
=== 예시 1: 새로운 기능 구현 ===
'''상황:''' 사용자 프로필 페이지에 '좋아요' 기능 추가
준호는 먼저 "이 버그를 재현할 수 있을까?"라는 가설을 세웠다. 자신의 로컬 환경에서 여러 번 로그인해봤지만 문제가 없었다. 그러다가 다른 브라우저로 시도해봤더니 Internet Explorer에서만 문제가 발생했다.
Line 76: Line 52:
'''잘못된 접근:'''
- 데이터베이스 스키마 변경
- API 엔드포인트 추가
- 프론트엔드 UI 구현
- 알림 기능 추가
- 권한 검증 로직 추가
모든 것을 한 번에 구현 → 3일 후 동작하지 않음
"IE에서만 발생한다"는 새로운 정보를 얻은 준호는 다음 가설을 세웠다. "JavaScript 에러가 있을 것이다." 브라우저 콘솔을 열어보니 과연 에러 메시지가 있었다. 특정 함수에서 undefined 에러가 발생하고 있었다.
Line 84: Line 54:
'''TinyExperiment 접근:'''
1. '''가설:''' "좋아요 데이터를 저장할 수 있다"
   - 임시 테이블 생성
   - 간단한 INSERT/SELECT 쿼리 테스트
   - 5분 만에 검증 완료
이제 "이 함수의 이 변수가 undefined이다"라는 구체적인 가설이 생겼다. console.log를 몇 줄 추가해서 변수의 값을 확인해봤더니, IE에서는 특정 API가 지원되지 않아서 undefined가 되고 있었다.
Line 90: Line 56:
2. '''가설:''' "API로 좋아요 데이터를 주고받을 수 있다"
   - 기본적인 POST/GET 엔드포인트만 구현
   - Postman으로 테스트
   - 10분 만에 검증 완료
문제를 정확히 파악한 준호는 간단한 브라우저 호환성 체크 코드를 추가했다. 테스트해보니 문제가 해결되었다. 전체 과정이 1시간밖에 걸리지 않았다. 만약 처음부터 "아마 세션 문제일 것이다"라고 추측하고 세션 관련 코드를 모두 뒤졌다면, 하루 종일 걸렸을 것이다.
Line 95: Line 58:
3. '''가설:''' "프론트엔드에서 API를 호출할 수 있다"
   - 단순한 버튼과 AJAX 호출만 구현
   - UI는 나중에 다듬기
   - 15분 만에 검증 완료
'''경력 5년 차 수진의 성능 개선 프로젝트'''
Line 100: Line 60:
각 단계가 성공한 후 다음 단계로 진행. 실패하면 원인을 정확히 알 수 있음. 수진은 "페이지 로딩이 너무 느리다"는 요청을 받았다. 경험이 있는 그녀도 처음에는 막막했다. 성능 문제는 여러 원인이 복합적으로 작용할 수 있기 때문이다.
Line 102: Line 62:
=== 예시 2: 버그 디버깅 ===
'''상황:''' "로그인 후 대시보드가 가끔 안 보인다"는 신고
하지만 수진은 베타 요리사의 방법을 알고 있었다. 먼저 현재 상황을 정확히 측정했다. 브라우저 개발자 도구를 열고 실제 로딩 시간을 확인했다. 8초가 걸리고 있었다.
Line 105: Line 64:
'''잘못된 접근:'''
코드를 훑어보며 "아마 세션 문제일 것이다" 추측하고 세션 관련 코드를 모두 수정
첫 번째 가설: "이미지 파일이 너무 클 것이다." 네트워크 탭을 보니 5MB짜리 이미지들이 여러 개 있었다. 이미지를 압축하고 다시 측정했다. 5초로 줄어들었다. 좋은 시작이었다.
Line 108: Line 66:
'''TinyExperiment 접근:'''
1. '''가설:''' "재현 가능한 조건이 있다"
   - 다양한 브라우저, 사용자로 테스트
   - 재현 조건 발견: "IE에서만 발생"
두 번째 가설: "JavaScript 파일이 클 것이다." 번들 분석기로 확인해보니 사용하지 않는 라이브러리들이 포함되어 있었다. 불필요한 것들을 제거하고 측정했다. 3초로 더 줄어들었다.
Line 113: Line 68:
2. '''가설:''' "특정 브라우저의 문제다"
   - 콘솔 로그 확인
   - 네트워크 탭에서 요청 확인
   - JavaScript 오류 발견
세 번째 가설: "데이터베이스 쿼리가 느릴 것이다." 서버 로그를 보니 N+1 쿼리 문제가 있었다. 쿼리를 최적화하고 측정했다. 1.5초까지 줄어들었다.
Line 118: Line 70:
3. '''가설:''' "이 JavaScript 오류가 원인이다"
   - console.log 추가해서 실행 경로 추적
   - 특정 함수에서 오류 발생 확인
각 단계마다 실제 측정치로 개선 효과를 확인했기 때문에, 어떤 최적화가 얼마나 효과적인지 정확히 알 수 있었다. 만약 한 번에 모든 것을 바꿨다면, 어떤 변경이 진짜 효과가 있었는지 알 수 없었을 것이다.
Line 122: Line 72:
4. '''가설:''' "이 함수의 이 부분이 문제다"
   - 최소한의 수정으로 오류 해결
   - 테스트로 검증
== The Wisdom of Small Steps ==
Line 126: Line 74:
=== 예시 3: 성능 개선 ===
'''상황:''' "페이지 로딩이 너무 느려요"
'''왜 작은 단계가 더 빠를까?'''
Line 129: Line 76:
'''TinyExperiment 접근:'''
1. '''측정부터:''' 브라우저 개발자 도구로 정확한 로딩 시간 확인
2. '''가설 1:''' "이미지가 너무 크다" → 이미지 최적화 후 측정
3. '''가설 2:''' "JavaScript 파일이 크다" → 번들 크기 분석
4. '''가설 3:''' "데이터베이스 쿼리가 느리다" → 쿼리 실행 시간 측정
역설적이게도, 작은 단계로 나누는 것이 결국 더 빠르다. 큰 변경을 한 번에 시도하다가 실패하면, 처음부터 다시 시작해야 한다. 하지만 작은 단계로 나누면 실패해도 바로 이전 단계로만 돌아가면 된다.
Line 135: Line 78:
각 개선 후 실제 측정치로 효과 확인. 마치 산을 오를 때와 같다. 정상을 향해 일직선으로 가려다가 절벽을 만나면 다시 처음부터 시작해야 한다. 하지만 지그재그로 안전한 길을 찾아가면, 조금 더 돌아가더라도 결국 정상에 더 빨리 도착한다.
Line 137: Line 80:
== 요리사의 지혜 (은유) ==
훌륭한 요리사는 새로운 요리를 개발할 때 이렇게 한다:
'''실패는 정보다'''
Line 140: Line 82:
1. '''기본 레시피로 시작''' - 검증된 방법부터
2. '''한 번에 하나만 바꾸기''' - 설탕량만 조정, 다른 것은 그대로
3. '''맛을 보며 조정''' - 변경 후 즉시 결과 확인
4. '''기록 남기기''' - 무엇을 바꿨는지, 결과가 어땠는지
5. '''실패해도 괜찮은 환경''' - 작은 양으로 실험, 큰 파티 음식은 나중에
베타 요리사에게 실패한 실험은 낭비가 아니었다. "이 조합은 맛이 없다"는 중요한 정보였다. 개발에서도 마찬가지다. "이 방법은 작동하지 않는다"는 것을 빨리 알면, 다른 방법을 시도할 수 있다.
Line 146: Line 84:
프로그래밍도 마찬가지다. 경험 많은 개발자는 작은 실험을 통해 점진적으로 시스템을 이해하고 개선한다. 중요한 것은 실패의 비용을 낮추는 것이다. 작은 실험에서 실패하면 5분을 잃는다. 큰 변경에서 실패하면 5일을 잃는다.
Line 148: Line 86:
== Common Anti-Patterns (피해야 할 것들) == '''시스템과 친해지기'''
Line 150: Line 88:
=== "Big Bang" 개발 ===
- 한 번에 많은 기능을 구현하려고 함
- 실패 시 원인을 찾기 어려움
- 되돌리기 어려움
작은 실험을 반복하다 보면, 시스템과 친해진다. 어떤 부분이 민감한지, 어떤 변경이 위험한지, 어떤 패턴이 잘 작동하는지 자연스럽게 알게 된다. 이런 직관은 큰 변경을 한 번에 시도해서는 얻을 수 없다.
Line 155: Line 90:
=== "추측 기반" 디버깅 ===
- 현상을 제대로 관찰하지 않고 추측으로 수정
- 한 번에 여러 부분을 수정
- 실제 원인과 다른 곳을 수정
베타 요리사가 재료들의 특성을 하나씩 이해해가듯이, 개발자도 코드베이스의 특성을 작은 실험을 통해 이해해간다.
Line 160: Line 92:
=== "완벽주의" 함정 ===
- 실험 환경을 너무 완벽하게 만들려고 함
- 실험보다 환경 구축에 더 많은 시간 소모
- 간단한 실험으로도 충분한 상황에서 과도한 준비
== Common Pitfalls ==
Line 165: Line 94:
== Tools and Techniques == '''완벽한 실험 환경의 함정'''
Line 167: Line 96:
=== 개발 환경 도구 ===
- '''Hot reload:''' 코드 변경 시 즉시 반영
- '''REPL:''' 작은 코드 조각을 즉시 실행
- '''디버거:''' 단계별 실행과 상태 확인
- '''로깅:''' 실행 경로와 변수 값 추적
어떤 개발자들은 실험을 시작하기 전에 완벽한 환경을 만들려고 한다. 모든 테스트를 작성하고, 모든 도구를 설정하고, 모든 문서를 읽고 나서야 실험을 시작한다. 하지만 이는 본말이 전도된 것이다.
Line 173: Line 98:
=== 테스팅 도구 ===
- '''Unit tests:''' 작은 단위의 동작 검증
- '''Test fixtures:''' 일관된 테스트 환경
- '''Mock objects:''' 외부 의존성 제거
- '''Test doubles:''' 복잡한 객체의 간단한 대체재
베타 요리사는 작은 접시와 기본 재료만 있으면 바로 실험을 시작했다. 완벽한 주방 설비를 기다리지 않았다. 개발에서도 마찬가지다. 간단한 print문이나 로그만 있어도 충분히 실험할 수 있다.
Line 179: Line 100:
=== 프로파일링 도구 ===
- '''성능 측정:''' 실행 시간, 메모리 사용량
- '''데이터베이스 쿼리 분석:''' 실행 계획, 인덱스 사용
- '''네트워크 모니터링:''' 요청/응답 시간, 데이터 크기
'''추측의 늪'''

"아마 이것 때문일 것이다"라는 추측에 빠지는 것도 위험하다. 추측은 가설의 출발점이 될 수 있지만, 검증 없이는 의미가 없다. 베타 요리사도 "이 소스가 더 맛있을 것 같다"고 생각했지만, 반드시 맛을 보고 확인했다.

== Tools for Your Laboratory ==

실험실에는 도구가 필요하다. 베타 요리사에게 작은 접시와 맛보기용 스푼이 있었듯이, 개발자에게도 실험을 돕는 도구들이 있다.

코드를 즉시 실행해볼 수 있는 REPL, 변경사항을 바로 확인할 수 있는 핫 리로드, 중간 결과를 확인할 수 있는 디버거, 기존 기능을 보호하는 테스트 코드. 이 모든 것들이 당신의 실험실을 구성하는 도구들이다.

중요한 것은 도구 자체가 아니라 도구를 사용하는 마음가짐이다. "빨리 확인하고, 빨리 배우고, 빨리 조정한다"는 베타 요리사의 철학 말이다.
Line 185: Line 113:
TinyExperiment를 습관화하면: TinyExperiment를 습관화하면 복잡한 문제 앞에서도 당황하지 않게 된다. 큰 산도 작은 돌들로 이루어져 있고, 복잡한 시스템도 작은 부분들로 나누어 이해할 수 있다는 것을 안다. 실패를 두려워하지 않게 되고, 오히려 실패에서 배우는 것에 익숙해진다.
Line 187: Line 115:
- '''불확실성이 줄어든다''' - 추측 대신 확실한 지식 축적
- '''학습이 가속화된다''' - 빠른 피드백으로 경험 축적
- '''실패 비용이 낮아진다''' - 작은 실패로 큰 실패 방지
- '''자신감이 향상된다''' - 복잡한 문제도 작은 단위로 분해하여 해결
- '''시스템 이해가 깊어진다''' - 점진적 탐색으로 전체 그림 파악
- '''팀 협업이 개선된다''' - 명확한 가설과 결과로 소통
가장 중요한 것은, 시스템과 대화하는 법을 배우게 된다는 것이다. 코드에게 질문하고, 답을 듣고, 다시 질문하는 순환이 자연스러워진다. 이것이 진정한 프로그래밍의 시작이다.
Line 198: Line 121:
* '''Conflicts with:''' BigBangDevelopment, GuessBasedDebugging
Line 204: Line 126:
* 과학적 방법론 - 가설-실험-검증의 순환

TinyExperiment

Context

복잡한 소프트웨어 문제를 해결하거나 새로운 기능을 구현할 때, 또는 버그를 추적할 때. 불확실성이 높고 여러 가능성이 존재하는 상황에서 어떻게 접근해야 할지 막막할 때.

Problem

두 요리사의 이야기

어느 레스토랑에 두 명의 요리사가 있었다. 둘 다 새로운 파스타 요리를 개발하라는 임무를 받았다.

첫 번째 요리사 알렉스는 야심이 컸다. "완전히 새로운 파스타를 만들어보자!" 그는 면도 직접 만들고, 소스도 새로 개발하고, 치즈도 특별한 것을 사용하고, 허브도 독특한 조합으로 넣기로 했다. 3시간 동안 열심히 요리한 결과, 이상한 맛의 음식이 나왔다. 손님들은 고개를 저었다. 하지만 알렉스는 무엇이 잘못되었는지 알 수 없었다. 면 때문일까? 소스 때문일까? 치즈 때문일까? 처음부터 다시 시작해야 했다.

두 번째 요리사 베타는 다르게 접근했다. 먼저 검증된 기본 파스타를 만들어 맛을 확인했다. 그 다음 소스만 조금 바꿔서 다시 맛을 보았다. "좋아, 이건 괜찮네." 그리고 치즈를 한 종류만 바꿔서 또 맛을 보았다. 각 단계마다 작은 접시에 조금씩 만들어서 확인했다. 만약 어떤 변경이 맛을 망쳤다면, 바로 이전 단계로 돌아갔다. 2시간 후, 손님들이 "이 파스타 정말 맛있네요!"라고 말하는 요리가 완성되었다.

개발자들도 마찬가지다. 복잡한 기능을 한 번에 모두 구현하려다가 알렉스처럼 실패하거나, 베타처럼 작은 단계로 나누어 성공하거나. 차이는 접근 방법에 있다.

Solution

작은 실험실을 만들어라

베타 요리사의 지혜는 단순했다. 큰 변화를 작은 실험들로 나누고, 각 실험의 결과를 즉시 확인하고, 실패해도 쉽게 되돌아갈 수 있게 준비하는 것이었다.

프로그래밍에서도 이와 같은 "작은 실험실"을 만들 수 있다. 새로운 기능을 구현할 때, 버그를 찾을 때, 성능을 개선할 때마다 이 방법을 사용하라.

명확한 가설부터 시작하라

베타가 "이 소스가 더 맛있을 것이다"라는 구체적인 가설을 세웠듯이, 개발에서도 명확한 가설을 세워야 한다. "이 함수가 느릴 것이다"가 아니라 "이 반복문에서 데이터베이스를 N번 호출해서 느릴 것이다"처럼 구체적으로 말이다.

안전한 실험 환경을 구축하라

베타는 작은 접시에 조금씩 만들어서 실험했다. 만약 망쳐도 전체 요리가 아니라 작은 부분만 버리면 되었다. 개발에서는 git 브랜치가 이 역할을 한다. 새로운 시도를 할 때마다 브랜치를 만들고, 실패하면 쉽게 되돌아간다. 테스트 코드는 기존 기능이 망가지지 않았는지 확인하는 안전망 역할을 한다.

즉시 피드백을 받아라

베타는 각 단계마다 맛을 보았다. 3시간 후에 맛을 보는 게 아니라 5분마다 맛을 확인했다. 개발에서도 마찬가지다. 코드를 100줄 짠 후에 테스트하는 게 아니라, 5줄 짤 때마다 실행해보고 확인한다. 자동화된 테스트, 핫 리로드, 간단한 print문까지 모든 것이 즉시 피드백을 주는 도구가 된다.

한 번에 하나씩만 바꿔라

베타의 가장 중요한 원칙이다. 소스를 바꿀 때는 다른 것은 그대로 두고 소스만 바꿨다. 그래서 결과가 나빠지면 소스 때문이라는 걸 확실히 알 수 있었다. 개발에서도 한 번에 하나의 변수만 바꿔야 한다. 함수를 수정할 때 동시에 데이터베이스 스키마까지 바꾸면, 문제가 생겼을 때 원인을 찾기 어렵다.

Examples

신입 개발자 준호의 첫 번째 버그 수정

준호는 "로그인 후 대시보드가 가끔 안 보인다"는 버그 리포트를 받았다. 처음에는 겁이 났다. 로그인 시스템은 복잡하고, 대시보드도 여러 컴포넌트로 이루어져 있었다.

시니어 개발자 민지가 조언했다. "베타 요리사처럼 해봐. 한 번에 모든 걸 고치려 하지 말고, 작은 실험부터 시작해."

준호는 먼저 "이 버그를 재현할 수 있을까?"라는 가설을 세웠다. 자신의 로컬 환경에서 여러 번 로그인해봤지만 문제가 없었다. 그러다가 다른 브라우저로 시도해봤더니 Internet Explorer에서만 문제가 발생했다.

"IE에서만 발생한다"는 새로운 정보를 얻은 준호는 다음 가설을 세웠다. "JavaScript 에러가 있을 것이다." 브라우저 콘솔을 열어보니 과연 에러 메시지가 있었다. 특정 함수에서 undefined 에러가 발생하고 있었다.

이제 "이 함수의 이 변수가 undefined이다"라는 구체적인 가설이 생겼다. console.log를 몇 줄 추가해서 변수의 값을 확인해봤더니, IE에서는 특정 API가 지원되지 않아서 undefined가 되고 있었다.

문제를 정확히 파악한 준호는 간단한 브라우저 호환성 체크 코드를 추가했다. 테스트해보니 문제가 해결되었다. 전체 과정이 1시간밖에 걸리지 않았다. 만약 처음부터 "아마 세션 문제일 것이다"라고 추측하고 세션 관련 코드를 모두 뒤졌다면, 하루 종일 걸렸을 것이다.

경력 5년 차 수진의 성능 개선 프로젝트

수진은 "페이지 로딩이 너무 느리다"는 요청을 받았다. 경험이 있는 그녀도 처음에는 막막했다. 성능 문제는 여러 원인이 복합적으로 작용할 수 있기 때문이다.

하지만 수진은 베타 요리사의 방법을 알고 있었다. 먼저 현재 상황을 정확히 측정했다. 브라우저 개발자 도구를 열고 실제 로딩 시간을 확인했다. 8초가 걸리고 있었다.

첫 번째 가설: "이미지 파일이 너무 클 것이다." 네트워크 탭을 보니 5MB짜리 이미지들이 여러 개 있었다. 이미지를 압축하고 다시 측정했다. 5초로 줄어들었다. 좋은 시작이었다.

두 번째 가설: "JavaScript 파일이 클 것이다." 번들 분석기로 확인해보니 사용하지 않는 라이브러리들이 포함되어 있었다. 불필요한 것들을 제거하고 측정했다. 3초로 더 줄어들었다.

세 번째 가설: "데이터베이스 쿼리가 느릴 것이다." 서버 로그를 보니 N+1 쿼리 문제가 있었다. 쿼리를 최적화하고 측정했다. 1.5초까지 줄어들었다.

각 단계마다 실제 측정치로 개선 효과를 확인했기 때문에, 어떤 최적화가 얼마나 효과적인지 정확히 알 수 있었다. 만약 한 번에 모든 것을 바꿨다면, 어떤 변경이 진짜 효과가 있었는지 알 수 없었을 것이다.

The Wisdom of Small Steps

왜 작은 단계가 더 빠를까?

역설적이게도, 작은 단계로 나누는 것이 결국 더 빠르다. 큰 변경을 한 번에 시도하다가 실패하면, 처음부터 다시 시작해야 한다. 하지만 작은 단계로 나누면 실패해도 바로 이전 단계로만 돌아가면 된다.

마치 산을 오를 때와 같다. 정상을 향해 일직선으로 가려다가 절벽을 만나면 다시 처음부터 시작해야 한다. 하지만 지그재그로 안전한 길을 찾아가면, 조금 더 돌아가더라도 결국 정상에 더 빨리 도착한다.

실패는 정보다

베타 요리사에게 실패한 실험은 낭비가 아니었다. "이 조합은 맛이 없다"는 중요한 정보였다. 개발에서도 마찬가지다. "이 방법은 작동하지 않는다"는 것을 빨리 알면, 다른 방법을 시도할 수 있다.

중요한 것은 실패의 비용을 낮추는 것이다. 작은 실험에서 실패하면 5분을 잃는다. 큰 변경에서 실패하면 5일을 잃는다.

시스템과 친해지기

작은 실험을 반복하다 보면, 시스템과 친해진다. 어떤 부분이 민감한지, 어떤 변경이 위험한지, 어떤 패턴이 잘 작동하는지 자연스럽게 알게 된다. 이런 직관은 큰 변경을 한 번에 시도해서는 얻을 수 없다.

베타 요리사가 재료들의 특성을 하나씩 이해해가듯이, 개발자도 코드베이스의 특성을 작은 실험을 통해 이해해간다.

Common Pitfalls

완벽한 실험 환경의 함정

어떤 개발자들은 실험을 시작하기 전에 완벽한 환경을 만들려고 한다. 모든 테스트를 작성하고, 모든 도구를 설정하고, 모든 문서를 읽고 나서야 실험을 시작한다. 하지만 이는 본말이 전도된 것이다.

베타 요리사는 작은 접시와 기본 재료만 있으면 바로 실험을 시작했다. 완벽한 주방 설비를 기다리지 않았다. 개발에서도 마찬가지다. 간단한 print문이나 로그만 있어도 충분히 실험할 수 있다.

추측의 늪

"아마 이것 때문일 것이다"라는 추측에 빠지는 것도 위험하다. 추측은 가설의 출발점이 될 수 있지만, 검증 없이는 의미가 없다. 베타 요리사도 "이 소스가 더 맛있을 것 같다"고 생각했지만, 반드시 맛을 보고 확인했다.

Tools for Your Laboratory

실험실에는 도구가 필요하다. 베타 요리사에게 작은 접시와 맛보기용 스푼이 있었듯이, 개발자에게도 실험을 돕는 도구들이 있다.

코드를 즉시 실행해볼 수 있는 REPL, 변경사항을 바로 확인할 수 있는 핫 리로드, 중간 결과를 확인할 수 있는 디버거, 기존 기능을 보호하는 테스트 코드. 이 모든 것들이 당신의 실험실을 구성하는 도구들이다.

중요한 것은 도구 자체가 아니라 도구를 사용하는 마음가짐이다. "빨리 확인하고, 빨리 배우고, 빨리 조정한다"는 베타 요리사의 철학 말이다.

Resulting Context

TinyExperiment를 습관화하면 복잡한 문제 앞에서도 당황하지 않게 된다. 큰 산도 작은 돌들로 이루어져 있고, 복잡한 시스템도 작은 부분들로 나누어 이해할 수 있다는 것을 안다. 실패를 두려워하지 않게 되고, 오히려 실패에서 배우는 것에 익숙해진다.

가장 중요한 것은, 시스템과 대화하는 법을 배우게 된다는 것이다. 코드에게 질문하고, 답을 듣고, 다시 질문하는 순환이 자연스러워진다. 이것이 진정한 프로그래밍의 시작이다.

* Enables: BabyStep, UseAbduction, HereAndNowDebugging * Used by: TddIsDesignActivity, PiecemealGrowthCenterFirst * Complements: ShortFeedbackCycle, MicroCommit

See Also

* 가추법 - 관찰에서 가설을 도출하는 사고 방식 * Kent Beck의 "Test Driven Development" - 작은 테스트로 설계하기 * Gary Klein의 "Sources of Power" - 전문가의 직관과 가설 검증


CategoryPattern

TinyExperiment (last edited 2025-07-24 23:12:45 by 정수)