2026년 4월 13일 | 개발 깨알 상식_Tips
프론트엔드에서 에이전트가 제일 그럴듯하게 속이는 순간은 화면은 아직 틀렸는데 수정은 끝났다고 말할 때다. 코드 diff만 보면 그럴싸한데, 실제 브라우저를 열어 보면 간격이 무너져 있고 버튼 상태가 어긋나 있고 다크 모드에서만 깨지는 식이다. 어젯밤 Why AI Sucks at Front End 글이 Hacker News에서 크게 돌았는데, 나는 본문보다도 댓글 한 줄에 더 오래 멈췄다. 프론트엔드 AI 코딩의 핵심 문제는 모델이 CSS를 잘 모르느냐보다, 자기 결과를 화면으로 다시 검사하는 루프가 없다는 점이었다.
실제로 상단 댓글에서는 스크린샷을 기준으로 실제 결과를 계속 비교하라는 얘기가 나왔고, 이어진 답글에서는 브라우저를 직접 조작하게 해서 UX를 확인하라는 쪽으로 대화가 붙었다. 이 얘기를 보자마자 내가 오늘 바로 메모해둔 한 줄은 이것이다. 프론트엔드 작업을 에이전트에게 맡길 때는 코드 리뷰보다 먼저 시각 검증 루프를 붙여야 한다. 글로 “간격을 조금 줄여줘”, “좀 더 세련되게”를 반복하는 것보다, 브라우저 스크린샷과 diff 기준을 먼저 고정하는 편이 훨씬 덜 흐려진다.
Figure 1. 프론트엔드 바이브코딩에서는 “코드가 바뀌었는가”보다 “화면이 기준과 맞는가”를 끝 조건으로 두는 편이 훨씬 안전했다.
1. 왜 프론트엔드는 말만으로 잘 안 맞는가
백엔드나 스크립트 쪽은 출력이 텍스트라서 에이전트가 자기 결과를 다시 읽기 쉽다. 반면 프론트엔드는 최종 결과가 렌더링된 화면이다. viewport, 폰트, 상태 조합, hover, empty state, 다크 모드, locale, 느린 네트워크 같은 변수가 한꺼번에 얽힌다. 원문 글에서 지적한 것도 결국 비슷했다. 모델은 브라우저의 혼잡한 실행면을 직접 통제하지 못하니, 사람 쪽에서 그 면을 검사 가능한 표면으로 바꿔 줘야 한다.
- “예쁘게” 같은 지시는 기준이 없어서 다음 턴마다 흔들린다.
- 코드만 보고는 spacing, alignment, combined state가 맞았는지 끝까지 확신하기 어렵다.
- 에이전트가 한 번 고친 뒤 스스로 브라우저를 다시 열어 보지 않으면, 맞는 척하는 완료 보고가 계속 나온다.
그래서 나는 프론트엔드 작업만큼은 “구현 → 설명”보다 구현 → 렌더 → 비교 → 다시 구현 순서를 먼저 잡는 쪽이 낫다고 본다. 이 루프가 없으면 사람은 계속 감각어를 늘이고, 에이전트는 그 감각어를 코드로 번역하다가 점점 빗나간다. 결국 수정 속도보다 오판 속도가 더 빨라진다.
2. 내가 바로 복붙해둘 최소 Playwright 루프
오늘 기준으로 제일 실용적인 기본값은 Playwright visual comparisons였다. 공식 문서도 핵심을 아주 단순하게 말한다. await expect(page).toHaveScreenshot() 로 기준 이미지를 만들고, 다음 실행부터는 그 기준과 비교한다. 중요한 건 화려한 시각 회귀 시스템을 크게 도입하는 게 아니라, 프론트엔드 작업 한 파일에도 이 비교점을 먼저 심어 두는 일이다.
npm i -D @playwright/test
npx playwright install
npx playwright test tests/ui/landing.spec.ts
import { test, expect } from '@playwright/test';
test.use({
viewport: { width: 1440, height: 900 },
colorScheme: 'light',
});
test('landing hero', async ({ page }) => {
await page.goto('http://127.0.0.1:3000');
await expect(page).toHaveScreenshot('landing-hero.png', {
maxDiffPixels: 80,
stylePath: './screenshot.css',
});
});
여기서 baseline PNG를 먼저 저장소에 넣고, 에이전트에게는 “이 화면을 건드린 뒤 반드시 스크린샷 비교를 다시 통과시켜라”라고 계약을 거는 식이 가장 단순했다. 화면이 바뀌는 작업인데 이 기준 파일이 없으면, 결국 검수는 다시 사람 눈과 긴 대화에 의존하게 된다.
내가 여기서 특히 좋게 본 건 검수 기준이 문장형 취향에서 파일형 기준으로 내려온다는 점이다. “조금 더 정돈된 느낌”, “버튼이 덜 답답하게” 같은 문장은 사람끼리는 통하지만, 에이전트에게는 매 턴 번역이 달라진다. 반대로 landing-hero.png 같은 기준 파일이 있으면, 에이전트는 감상문 대신 실패 영역을 다시 맞추는 쪽으로 움직인다. 프론트엔드에서 이 차이가 꽤 크다.
3. diff가 자꾸 흔들릴 때 먼저 고칠 것
Playwright 문서에서 내가 제일 중요하게 본 경고는 기준 이미지를 만든 환경과 비교 환경을 최대한 같게 유지하라는 부분이었다. OS, 브라우저, 설정, 하드웨어가 바뀌면 스크린샷도 달라진다. 이건 모델 성능 문제가 아니라 측정면이 흔들리는 문제라서, 프롬프트를 더 잘 쓰는 것보다 환경을 먼저 고정하는 쪽이 맞다.
- viewport, colorScheme, locale를 먼저 고정한다.
- 시계, 광고, 랜덤 아바타처럼 흔들리는 영역은 stylePath로 숨긴다.
--update-snapshots는 의도된 UI 변경이 확실할 때만 쓴다.- diff 수치는 정답이 아니라 중단선이다. 숫자 하나보다 실패한 영역을 같이 보게 만드는 게 더 중요하다.
/* screenshot.css */
[data-live-clock],
[data-random-avatar],
iframe {
visibility: hidden;
}
Hacker News 댓글에서는 ImageMagick으로 목업과 실제 결과를 계속 비교했다는 경험담도 있었는데, 내가 보기엔 핵심이 도구 이름은 아니었다. 에이전트가 “수정했다”에서 멈추지 않고 “기준 화면과 다시 맞췄다”까지 가게 만드는 게이트가 있느냐가 핵심이었다.
4. 에이전트에게 넘길 때는 작업 계약을 이렇게 얇게 둔다
프론트엔드 작업에서 프롬프트가 길어지는 이유는 보통 취향 설명이 길어서다. 그런데 실제로는 취향보다 검증 순서를 짧게 고정하는 편이 더 잘 먹혔다. 나는 아래 정도만 있어도 꽤 충분하다고 본다.
1. Open the target page at 1440x900.
2. Make the smallest UI change for the requested issue.
3. Run the Playwright screenshot check.
4. If diff fails, inspect the failing region and retry.
5. Report changed selectors and whether the screenshot passed.
이렇게 하면 에이전트가 미학을 이해한 척하는 문장을 길게 늘어놓기보다, 브라우저에서 확인 가능한 결과를 기준으로 움직인다. 실제로 사람이 마지막에 확인할 때도 훨씬 편하다. 무엇이 바뀌었는지, 어디가 아직 어긋나는지, 기준 이미지를 업데이트해도 되는 변경인지가 전부 한 장의 실패 캡처로 모이기 때문이다. 프론트엔드 작업에서 이 정도로 피드백이 압축되면 턴 수가 눈에 띄게 줄어든다.
오늘 내 결론도 딱 그거였다. 프론트엔드 바이브코딩에서는 코드보다 화면을 먼저 계약하자. 참고한 링크는 원문 글, HN 토론, Playwright visual comparisons, Playwright screenshots, 그리고 공식 저장소다. 앞으로 프론트엔드 작업을 에이전트에게 넘길 때 내가 제일 먼저 붙일 한 줄은 이것 같다. 수정 완료 보고 전에 스크린샷 diff부터 통과시키기.
'[개발 깨알 상식_Tips]' 카테고리의 다른 글
| curl API 에러에서 본문 버리지 않기: --fail-with-body와 -w 같이 보기 (0) | 2026.04.14 |
|---|---|
| Claude-Mem에서 세션 메모리를 통째로 주입하지 않기: 3단계 검색으로 좁혀 쓰기 (0) | 2026.04.14 |
| Claude Code·Cursor·Codex에서 코드베이스를 그대로 넣지 않기: 압축 프록시 먼저 두기 (0) | 2026.04.12 |
| JSONL 비교를 줄 번호로 하지 않기: id 기준으로 먼저 정렬해 보는 습관 (0) | 2026.04.08 |
| curl 에러를 숫자 하나로 넘기지 않기: --fail-with-body와 -w를 같이 쓰는 습관 (0) | 2026.04.06 |