빌더 자동저장 무한루프와 생성 후 스펙 미반영 버그 수정
목차
빌더 클라이언트에서 두 가지 버그가 동시에 터졌고, 둘 다 "왜 이게 터졌지?" 보다 "왜 진작 안 막았지?"가 더 먼저 드는 케이스였다.
배경 — 두 버그가 한 파일에서
builder-client.tsx는 프로젝트 빌더 화면 전체를 관장하는 클라이언트 컴포넌트다. 상태 관리, 자동저장 트리거, 생성 완료 이후 spec 동기화까지 꽤 많은 책임을 짊어지고 있는 파일인데, 이번에 건드린 건 크게 두 가지였다.
- v++ runaway autosave — 버전 카운터가 조건 없이 증가하면서 autosave가 무한 루프에 가깝게 반복 실행되는 문제
- generation done 이후 spec이 갱신되지 않는 문제 — 생성이 완료됐는데 화면에 반영된 spec이 이전 버전 그대로 남아 있는 문제
둘 다 독립된 버그이지만, 하나의 흐름 안에 엮여 있어서 같이 고쳤다.
autosave runaway 원인
autosave는 보통 "변경이 감지되면 저장"이라는 단순한 로직처럼 보이지만, 그 "변경 감지" 기준이 느슨하면 금방 무한 루프로 빠진다. 이번 케이스는 버전 카운터(v)를 effect 내부에서 증가시키는 구조였는데, 그 v 자체가 다시 effect의 dependency에 물려 있었다. 그러니 저장할 때마다 버전이 올라가고, 버전이 올라가면 또 저장 트리거가 걸리는 악순환이 생긴 것.
// before — v가 dependency에 물려서 루프 발생
useEffect(() => {
setV((prev) => prev + 1); // 이 줄이 문제
triggerAutosave();
}, [someState, v]); // v를 여기서 다시 바라봄
// after — v 증가 시점을 분리하거나 dependency에서 제외
useEffect(() => {
triggerAutosave();
}, [someState]); // v는 dependency에서 제거, 버전은 저장 성공 콜백에서만 bump
React에서 useEffect dependency 설계를 잘못하면 이런 runaway가 정말 쉽게 생긴다. 린터가 exhaustive-deps 경고를 뱉어도 "어차피 동작하니까"라는 이유로 무시하다가 이런 데서 터진다. 코드리뷰할 때도 effect dependency 목록은 꼭 따로 짚어보는 편인데, 이 파일은 리뷰 사각지대에 있었던 것 같다.
autosave runaway의 실질적 피해는 생각보다 크다. 서버 요청이 계속 나가고, 저장 API가 rate limit에 걸릴 수 있고, 유저는 "저장 중" 스피너가 사라지지 않는 상태를 마주하게 된다. 눈에 안 보이는 버그가 아니라 유저가 직접 체감하는 버그다.
generation done → spec sync 문제
생성 완료 이후 spec 동기화는 타이밍 이슈가 많다. 생성이 비동기로 돌고, 완료 이벤트를 받은 시점에 "지금 화면의 spec을 새 것으로 교체"하는 로직이 필요한데, 이 부분이 빠져 있거나 잘못된 시점에 실행되면 유저는 생성이 끝났는데도 구버전 spec을 보고 있게 된다.
| 상황 | 증상 | 원인 |
|---|---|---|
| 생성 완료 이벤트 수신 | spec 미갱신 | 완료 콜백에서 setState 누락 |
| v++ runaway 진행 중 | spec 갱신 타이밍 꼬임 | effect 재실행 순서 꼬임 |
| 정상 흐름 | 생성 완료 후 즉시 spec 반영 | 완료 콜백 → setState → 리렌더 |
두 버그가 겹쳐 있으면 디버깅이 어렵다. autosave가 루프를 돌면서 컴포넌트가 계속 리렌더되는 와중에 spec 갱신 타이밍까지 꼬여 있으니, 어디서 문제가 생기는지 파악이 느려진다. 이런 케이스에서는 하나씩 따로 재현하고 따로 수정한 다음 합치는 게 맞는데, 이번엔 수정 방향이 명확해서 한 번에 묶었다.
회고
builder-client.tsx 같은 "중심 컴포넌트"는 기능이 쌓이면서 자연스럽게 책임이 과해지는 경향이 있다. autosave 로직, 버전 관리, 생성 흐름, spec 동기화가 전부 한 파일에 들어가 있으면 변경 영향 범위가 넓고, 버그가 생겼을 때 어디서 터진 건지 추적하기가 어렵다. 지금 당장 분리까지 하기엔 범위가 크지만, 이번 fix를 계기로 팀 내에서 이 파일의 책임 범위를 다시 논의해볼 생각이다.
autosave runaway 류의 버그는 개발 환경에서 잘 안 보인다. 개발할 때는 저장 주기가 느리고, 네트워크 요청이 눈에 잘 안 띄기 때문이다. 스테이징이나 프로덕션에서 유저 리포트로 올라오기 전에 잡으려면 effect dependency를 코드리뷰 체크리스트에 명시적으로 넣는 게 맞다. 이번에 그걸 다시 확인했다.
끝.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.