AI가 짜도 모르면 깨진다: 브라우저 렌더링과 엔지니어링 규율

AI가 짜도 모르면 깨진다: 브라우저 렌더링과 엔지니어링 규율

useLayoutEffect와 Layout Thrashing을 모른 채 AI 코드를 병합하는 순간, 16.6ms 프레임 예산은 조용히 무너진다

브라우저 렌더링 Layout Thrashing useLayoutEffect agentic coding 엔지니어링 규율 React 성능 최적화 requestAnimationFrame
광고

AI 코딩 도구가 코드를 쏟아내는 속도는 이제 인간이 읽는 속도를 앞지른다. Cursor가 컴포넌트를 완성하고, Claude가 훅을 제안하고, v0.dev가 UI를 그려내는 동안—정작 그 코드가 브라우저 안에서 어떻게 살아 움직이는지를 아는 개발자는 점점 줄어들고 있다. 문제는 AI가 틀린 코드를 만든다는 게 아니다. '작동은 하지만 망가진 코드'를 만든다는 점이다.

16.6ms 안에 벌어지는 일

dev.to에 올라온 브라우저 렌더 사이클 해설 글은 프론트엔드 개발자라면 한 번쯤 피부로 느꼈을 불편함을 정확히 짚는다. 60Hz 모니터 기준으로 브라우저는 한 프레임을 처리하는 데 딱 16.6밀리초를 쓴다. 이 짧은 창 안에서 JavaScript 실행 → 스타일 계산 → 레이아웃(Reflow) → 페인트 → 컴포지트라는 파이프라인이 순서대로 돌아간다. React 컴포넌트의 상태 변경은 이 파이프라인의 JavaScript 단계에서 시작되고, useLayoutEffect는 React가 실제 DOM에 변경을 커밋한 직후—페인트가 일어나기 전—동기적으로 끼어든다. useEffect는 페인트가 끝난 뒤에야 비동기로 실행된다. 이 타이밍 차이를 모르면, 레이아웃을 읽고 쓰는 코드가 어디에 놓이느냐에 따라 화면이 한 프레임 깜빡이거나, 더 심하면 렌더 루프 전체가 망가진다.

Layout Thrashing: 조용한 성능 킬러

특히 주목할 개념이 Layout Thrashing이다. 브라우저는 기본적으로 레이아웃 계산을 '게으르게' 처리한다—스타일을 여러 번 바꿔도 실제 계산은 JavaScript가 끝난 뒤 한 번만 한다. 그런데 스타일을 쓴 직후에 offsetWidth 같은 레이아웃 값을 읽으면, 브라우저는 '정확한 수치를 돌려줘야 하니까' 지금 당장 강제로 레이아웃을 계산해버린다. 이걸 루프 안에서 반복하거나, 여러 자식 컴포넌트의 useLayoutEffect가 각자 읽기-쓰기를 섞어서 실행하면, 16.6ms 예산은 순식간에 바닥난다. 사용자 눈에는 뚝뚝 끊기는 애니메이션과 레이아웃 지연으로 보인다.

해결책은 단순하다. 읽기를 먼저 몰고, 쓰기를 나중에 몰아라. requestAnimationFrame을 쓸 때는 현재 프레임의 파이프라인 어디에서 스케줄링하느냐에 따라 콜백이 이번 프레임에 실행되는지, 다음 프레임으로 밀리는지가 달라진다. useLayoutEffect 안에서 rAF를 호출하면 브라우저가 이미 현재 프레임 파이프라인을 잠근 뒤라, 콜백은 다음 프레임으로 밀린다—한 프레임의 시각적 깜빡임이 발생한다. 이런 디테일은 코드가 '작동하는지'와 '올바르게 작동하는지'를 가르는 경계선이다.

AI는 이 경계선을 모른다

dev.to의 또 다른 글 'Agentic coding isn't a trap. Lazy engineering is.'는 이 문제를 정면으로 건드린다. AI 에이전트가 코드베이스를 망친다는 비판이 유행처럼 번지지만, 글쓴이의 진단은 다르다. 문제는 도구가 아니라 엔지니어링 규율의 부재다. 모호한 프롬프트, 검토 없는 병합, 아키텍처 결정을 에이전트에 위임하는 습관—이것들은 AI 이전에도 존재했던 나쁜 습관이다. AI는 그 습관을 더 빠른 속도로 증폭시킬 뿐이다.

이 두 논의를 브라우저 렌더링이라는 맥락에 겹쳐보면 구체적인 그림이 그려진다. AI 도구는 useLayoutEffect 안에 읽기와 쓰기가 뒤섞인 코드를 아무렇지 않게 생성할 수 있다. 겉보기엔 작동한다. 단위 테스트도 통과한다. 하지만 60fps 애니메이션이 들어간 순간, 혹은 자식 컴포넌트가 10개를 넘는 순간, Layout Thrashing이 터진다. CI는 이걸 잡지 못한다. 코드 리뷰어가 렌더 사이클을 모르면 역시 놓친다.

엔지니어링 규율이 더 중요해진 이유

AI가 코드를 빠르게 만들수록, 개발자에게 요구되는 역할은 '코드를 작성하는 사람'에서 '코드를 검증하는 사람'으로 이동한다. 그 검증의 질은 결국 기반 지식의 깊이에서 나온다. 브라우저가 한 프레임을 어떻게 처리하는지, useLayoutEffect가 Event Loop의 어느 지점에서 실행되는지, rAF 콜백이 어느 타이밍에 잠기는지—이런 것들을 모르면 AI가 생성한 코드의 잠재적 결함을 감지할 수 없다.

'Agentic coding' 글이 제안하는 좋은 워크플로우는 명쾌하다. 에이전트를 쓰기 전에 상세한 스펙을 먼저 쓸 것, 에이전트 출력물을 사람이 작성한 PR과 동일한 기준으로 리뷰할 것, 보일러플레이트와 테스트 같은 반복 작업에 에이전트를 투입하고 아키텍처 결정은 직접 내릴 것. 이 원칙들을 렌더링 맥락에 적용하면: 성능 민감한 애니메이션 코드나 레이아웃 측정이 포함된 훅은 AI 출력을 그대로 쓰지 마라. 렌더 사이클 전반을 이해한 사람이 직접 검토하거나 작성해야 한다.

앞으로의 지형

React Compiler가 자동 메모이제이션을 담당하고, 브라우저 View Transitions API가 페이지 전환 애니메이션을 간소화하더라도, 레이아웃 스래싱이나 잘못된 타이밍의 DOM 읽기는 여전히 개발자가 직접 판단해야 할 영역으로 남는다. 추상화는 복잡성을 숨기지만 없애지는 않는다. AI가 더 많은 코드를 생성할수록, 그 추상화 아래에서 무슨 일이 벌어지는지 아는 개발자의 가치는 오히려 올라간다.

결국 핵심은 이것이다. 좋은 프로세스 위에서 AI는 곱셈기가 되고, 나쁜 프로세스 위에서 AI는 부채 가속기가 된다—'Agentic coding' 글이 정확히 표현한 말이다. 브라우저 렌더 사이클을 이해하는 것은 그 '좋은 프로세스'의 가장 구체적인 출발점 중 하나다. AI가 짠 코드도 결국 16.6ms 안에서 살아남아야 한다.

출처

더 많은 AI 트렌드를 Seedora 앱에서 확인하세요