| name | simulate-dont-just-scan |
| description | 읽기는 했지만 실행해 보지 않은 코드를 포팅·디버깅·구현할 때 적용한다 — 소스를 읽은 것이 동작을 이해한 것이라고 가정하지 말고, 구체적인 입력으로 코드를 머릿속에서 돌려 실제 런타임 출력·DOM·응답·데이터 모양·부수효과를 예측한다. |
Simulate, Don't Just Scan
소스 파일을 읽는 것은 이해하는 것과 다르다. 파일을 여는 건 "이 텍스트가 존재한다"를 알려준다. 파일을 머릿속에서 실행하는 건 "이게 돌면 무엇을 만들어내는가"를 알려준다.
포팅·디버깅·구현 버그 대부분은 읽기를 충분하다고 여기는 데서 온다 — "이게 돌 때 실제 출력 / DOM / 응답 / 데이터 모양 / 부수효과가 뭐지?"를 한 번도 묻지 않고 소스 파일만 머릿속에 모으는 것.
The Mistake
관련돼 보이는 파일을 다 연다. 내용을 훑는다. context를 가졌다고 느낀다. 하지만 코드를 머릿속에서 돌린 적은 없다: 구체적인 값을 대입한 적도, entry point에서 부수효과까지 control flow를 따라간 적도, 터미널 출력을 예측한 적도 없다.
이해처럼 보이지만 아닌 신호들:
- "스타일 파일을 열었으니 스타일링은 안다." (그런데 렌더 시점에 어느 엘리먼트가 실제로 어느 클래스를 갖지?)
- "타입 정의를 읽었으니 모양은 안다." (그런데 살아있는 엔드포인트에서 오는 실제 응답 본문은 뭐지?)
- "미들웨어를 훑었으니 뭘 변환하는지 안다." (그런데 전체 체인을 통과한 뒤 요청이 어떻게 생겼지?)
- "config 스키마를 봤으니 런타임 값은 안다." (그런데 이 환경에서 실제로 로드된 건 뭐지?)
이건 모두 소스의 존재에 대한 것이지, 런타임 동작에 대한 게 아니다.
Why It Happens
읽기는 싸고 생산적으로 느껴진다. 머릿속 실행은 더 많은 상태를 들고 있어야 한다 — 값을 대입하고, 분기를 처리하고, 여러 계층을 가로질러 동작을 합성한다. 뇌는 가능하면 싼 길을 택한다.
합성과 추상화가 이걸 더 나쁘게 만든다. 컴포넌트 트리, 미들웨어 체인, 데이터 파이프라인, ORM 매핑, config 레이어링, 이벤트 디스패치에서는 — 어느 한 파일도 답 전체를 담고 있지 않다. 동작을 직접 합성해야 한다.
Symptoms
- 출력이 현실과 안 맞고, 교정을 거듭할수록 격차가 계속 벌어진다.
- 10초짜리 시뮬레이션이면 드러났을 값·상태·구조에 놀란다.
- 리뷰어가 "코드를 읽었으면 알았을" 효과를 반복해서 짚는다 — 그리고 따지자면 너는 코드를 읽긴 했다.
Protocol
출력(코드, 포트, 수정, 분석)을 내기 전에 명시적으로 시뮬레이션한다:
- 구체적인 entry point와 구체적인 입력을 고른다. "일반적으로"가 아니라 특정 케이스로.
- 실행을 한 단계씩 걷는다. 각 단계마다 짚는다:
- 어느 파일 / 함수 / 계층이 처리하는지
- 그 지점에서 입력이 어떻게 생겼는지
- 어떤 변환이나 결정이 일어나는지
- 그 단계 뒤 출력이 어떻게 생겼는지
- 터미널에서 — DOM, HTTP 응답, DB row, 로그 줄 — 정확한 모양을 말한다. 못 하겠으면 아직 이해 못 한 것이다.
- 가능하면 예측한 출력을 현실과 비교한다: 페이지를 렌더하고, 엔드포인트를 때리고, 함수를 돌리고, 로그를 본다.
Rules
- 실행 하나도 따라가지 않고 파일만 모으고 있다는 걸 알아챘으면, 멈추고 시뮬레이션한다.
- 시스템이 합성될수록 시뮬레이션은 더 필수다 — 덜 필요한 게 아니다.
- 읽기는 시뮬레이션을 준비시킨다. 시뮬레이션의 대체물이 아니다.
- 리뷰어가 "코드를 봤으면 보였을" 격차를 짚을 때, 진짜 교훈은 거의 항상 시뮬레이션을 건너뛰었다는 것이지 읽기가 불완전했다는 게 아니다.