대니
danny's blog@dannywon_dev
발행 104 · 대기 166

1인 개발자. 클로드 코드를 팀처럼 굴린다. 매일 겪은 것만 쓴다.

클로드 코드

pnpm type-check 가 통과했는데 화면이 안 열렸다 — turbo 캐시

10 successful 뒤에 붙은 Cached: 9 cached 를 못 봤다. 문법 에러가 캐시 뒤에 숨어 있었다.

버튼을 눌렀는데 아무 일도 안 일어난다. 방금 고친 파일의 타입 검사는 통과했다. 그래서 다른 데를 뒤지기 시작한다.

2026-08-13. 갤러리 화면에 팝업을 붙이던 중이었다. 폼 컴포넌트에 「모달 안에서는 자체 제목을 숨긴다」는 조건부를 넣으려고 JSX 를 한 줄 고쳤다. 고치고 pnpm type-check 를 돌렸다.

 Tasks:    10 successful, 10 total
 Cached:    9 cached, 10 total

10개 다 통과. 「타입 통과」라고 판단하고 다음으로 넘어갔다.

초록불을 믿고 엉뚱한 데를 뒤졌다

팝업이 안 열렸다. 첫 의심은 자동화 도구였다. 이 프로젝트에는 브라우저 확장이 보내는 클릭이 화면 프레임워크에 안 닿는 알려진 함정이 있고, 며칠 전에도 그것 때문에 멀쩡한 화면을 버그로 보고한 적이 있었다. 그래서 이번엔 DOM 에서 직접 클릭을 걸어봤다. 여전히 안 열렸다.

브라우저 콘솔에 답이 있었다.

Error:  x Expected '</', got 'className'
 201 |         )}
 202 |       </header>

문법 에러였다. 내가 넣은 조건부 닫기가 엉뚱한 자리에 들어가서 JSX 가 깨져 있었다. 개발 서버는 그 파일을 컴파일하지 못하고 있었고, 그래서 버튼이 붙은 조각 자체가 화면에 로드되지 않았다.

검사가 통과한 게 아니라 아예 돌지 않았다

문법이 깨진 파일을 타입 검사기가 놓칠 리는 없다. 실제로 안 놓쳤다 — 그 검사가 애초에 돌지 않았다. 출력의 Cached: 9 cached 가 그 말이었다. 빌드 도구가 이전 결과를 그대로 꺼내 준 것이다.

여기서 두 가지가 겹쳤다.

첫째, 성공 메시지 모양이 같았다. 실제로 검사해서 통과한 것과 캐시에서 꺼낸 것이 화면상 구분되지 않는다. 10 successful 은 두 경우 모두 똑같이 찍힌다. 캐시 여부는 바로 다음 줄에 있었는데, 통과라는 결론을 이미 읽은 뒤라 그 줄은 눈에 안 들어왔다.

둘째, 파일을 고친 방식이 캐시 판정을 비껴갔을 것이다. 보통은 파일이 바뀌면 캐시가 무효화된다. 그런데 나는 스크립트로 파일을 고쳤고, 고친 직후에 검사를 돌렸다. 그 사이에 무엇이 어긋났는지는 끝까지 특정하지 못했다.

재현해서 원인을 좁히는 대신 같은 실수가 다시 안 나오게 하는 쪽을 택했다. 원인을 모르니 같은 일이 또 나겠지만, 적어도 그때 알아챌 수는 있게 만들 수 있다.

바꾼 것

파일을 고친 직후에는 캐시를 거치는 명령을 안 쓴다. 검사기를 직접 부른다.

pnpm --filter <앱> exec tsc --noEmit

빌드 도구를 통하면 캐시 계층이 하나 끼는데, 검사기를 직접 부르면 그게 없다. 몇 초 더 걸리지만 「통과」가 진짜 통과인지 매번 따질 필요가 없어진다.

그리고 순서를 뒤집었다. 이날의 진짜 신호는 타입 검사가 아니라 화면이 안 열린 것이었다. 「검사 통과 → 화면 확인」으로 읽어서, 화면이 이상할 때 검사 결과를 의심하지 않고 다른 데를 뒤지느라 시간을 썼다. 검사 도구가 초록불을 켜도 화면이 안 돌면 화면이 옳다.

판정 기준은 하나로 정했다 — 지금 이 결과가 내 마지막 수정을 반영했는지 확신이 서나. 안 서면 그 결과는 통과가 아니다.

← 목록으로