성능 개선을 논할 때 보통 아키텍처나 인프라 이야기가 먼저 나온다. 그런데 실무를 들여다보면 가장 빠르고 확실한 개선은 의외로 작은 곳에 숨어 있다. 이미지 포맷을 제대로 고르는 것, URL 파라미터 하나의 역할을 명확히 정의하는 것, AI 도구를 협업 파트너로 대하는 방식. 개별로는 사소해 보이는 이 결정들이 쌓여서 사용자가 느끼는 경험의 질을 결정한다.
이미지: 가장 확실한 성능 레버
웹 페이지 평균 용량의 절반 이상이 이미지다. dev.to에 올라온 '2026 이미지 최적화 체크리스트'는 이 단순한 사실에서 출발한다. 그런데 많은 팀이 이미지 최적화를 '나중에 할 일'로 미룬다. Core Web Vitals 점수가 나빠졌을 때야 비로소 들여다보기 시작한다.
우선순위를 따지면 리사이즈가 첫 번째다. 6000×4000 원본 사진을 1200px 카드에 그냥 던져 넣는 건, 트럭으로 편지 한 통 배달하는 것과 같다. 실제로 리사이즈만으로 4.7MB 이미지를 1.1MB로 줄일 수 있다—77% 감소, 품질 손실 없이. 포맷 선택은 그 다음이다. 규칙은 단순하다. 사진은 WebP(JPEG 대비 30~50% 절감), 더 줄이고 싶다면 AVIF(추가로 30% 절감). 로고와 아이콘은 SVG, 애니메이션이라면 animated WebP가 GIF 대비 60~80% 작다. 스크린샷처럼 텍스트와 날카로운 엣지가 있는 이미지엔 손실 압축을 쓰지 말 것—아티팩트가 생겨 오히려 역효과다.
실제 수치는 더 설득력 있다. 1920×1080 스크린샷 원본 PNG 2.1MB를 리사이즈 후 WebP 75%로 변환하면 186KB, AVIF 50%로 가면 102KB다. 91~95% 감소. 이게 4초 로딩과 1초 미만 로딩의 차이다. 여기에 loading="lazy"와 width/height 속성을 함께 쓰면 LCP와 CLS를 동시에 잡을 수 있다. 브라우저 호환성이 걱정된다면 <picture> 엘리먼트로 AVIF → WebP → JPEG 폴백 체인을 구성하면 된다.
한 가지 관점이 더 있다. 대부분의 온라인 압축 도구는 파일을 서버에 올린다. 클라이언트 작업물이나 민감한 이미지를 다룰 때 이는 간과하기 쉬운 보안 리스크다. 브라우저 사이드에서만 동작하는 도구를 선택하는 것, 이것도 DX가 아니라 제품 책임의 영역이다.
URL 파라미터: SoT를 어디에 둘 것인가
velog에 올라온 글 '파라미터 1개 추가가 쏘아올린 공'은 제목이 단적으로 모든 걸 설명한다. 요청은 단순했다. 서비스 랜딩 페이지의 영문 직접 접속 URL을 만들어달라는 것. 얼핏 보면 /service?lang=en 하나 추가하면 끝날 것 같다. 그런데 기존 코드를 들여다보자 구조적 문제가 드러났다.
언어 결정 로직이 localStorage, Zustand, i18next 세 곳에 분산되어 있었다. 그리고 브라우저 언어를 확인하는 코드가 있었지만, 모든 분기가 결국 ko를 반환했다. 영어 브라우저 사용자도 항상 한국어 화면을 봤다는 뜻이다. 이 상태에서 URL 파라미터를 단순히 추가하면, 같은 URL이 사용자마다 다른 화면을 보여주는 상황이 생긴다.
개발자가 내린 결론은 명쾌했다. 이 작업은 파라미터 추가가 아니라, 언어 결정 주체를 URL로 단일화하는 구조 재설계다. 기존 localStorage 값을 무시하고, URL을 유일한 Source of Truth로 삼는 것. 이 선택 덕분에 URL만 공유하면 누구든 동일한 언어 화면을 볼 수 있게 됐다. 영업팀이 해외 파트너에게 링크를 공유하는 상황이라면 이건 단순한 기술 결정이 아니라 제품 신뢰성의 문제다.
구현 디테일도 눈여겨볼 만하다. i18next 초기화 시점에 window.location.search를 동기적으로 읽어 첫 렌더에서 한국어가 잠깐 보이는 플리커 현상을 막았다. i18n.language 대신 resolvedLanguage를 사용해 실제 적용된 언어를 정확히 참조했다. 언어 전환 버튼도 여러 상태를 직접 변경하는 대신 URL만 바꾸고, 나머지는 location 변경 구독으로 반응하게 했다. localStorage + Zustand + i18next를 동시에 건드리던 구조가 URL → i18next → 화면이라는 단방향 흐름으로 정리됐다.
SEO도 빠뜨리지 않았다. hreflang과 canonical 태그를 검토했지만, 메타데이터 정책이 아직 기획팀과 합의되지 않은 상황에서 섣불리 추가하면 오히려 혼란을 만든다고 판단해 별도 작업으로 분리했다. 두 번 일하지 않기 위한 명시적인 선택이다. 작은 URL 파라미터 하나가 던진 질문이 결국 '언어 결정의 책임을 어디에 둘 것인가'라는 프로덕트 설계 문제로 이어진 셈이다.
Claude Code: 도구가 아니라 협업 방식의 문제
Anthropic의 엔지니어들이 직접 공개한 Claude Code 활용 팁 7가지가 Hacker News에서 130포인트를 받았다. 내용의 핵심은 단 하나다. AI 코딩 도구는 잘 세팅된 워크플로우 안에서만 제 성능을 낸다.
가장 자주 범하는 실수는 컨텍스트 없이 시작하는 것이다. "버그 고쳐줘"는 최악의 프롬프트다. 프로젝트 구조, 관련 파일, 에러 메시지, 이미 시도해본 것—이 네 가지를 먼저 제공하면 결과물의 품질이 달라진다. 이를 매번 타이핑하기 싫다면 CLAUDE.md 파일이 해답이다. 빌드 커맨드, 아키텍처 결정, 코드 스타일, 알려진 기술 부채—여기에 적어두면 세션마다 반복할 필요가 없다.
태스크 분해도 중요하다. "인증 시스템 만들어줘"는 크고 검증하기 어렵다. 대신 유저 모델 생성 → 회원가입 엔드포인트 → 로그인 엔드포인트 → JWT 미들웨어로 쪼개면 각 단계마다 테스트를 돌려볼 수 있다. 코드를 쓰기 전에 탐색을 먼저 시키는 것도 효과적이다. "인증이 어떻게 구현되어 있는지 코드베이스를 먼저 살펴봐"라고 하면 AI가 기존 패턴과 컨벤션을 이해한 상태에서 코드를 생성하기 때문에 보일러플레이트 대신 프로젝트에 녹아드는 코드가 나온다.
Git 체크포인트 활용도 빼놓을 수 없다. AI가 실수했을 때 커밋 하나만 되돌리면 된다는 안전망이 있어야 과감하게 실험할 수 있다. 반대로 대화가 20~30회 이상 길어졌거나 AI가 이미 없어진 코드를 참조하기 시작하면 세션을 새로 시작하는 것이 더 낫다. 긴 컨텍스트에 쌓인 실패 이력이 오히려 노이즈가 되기 때문이다.
세 가지 소스가 공통적으로 말하는 것이 있다. 이미지 최적화든, URL 설계든, AI 도구 운용이든—표면의 요청을 그대로 실행하기 전에 한 번 더 질문을 던지는 것이 결과물의 질을 결정한다는 것이다. /service?lang=en 하나 추가하면 된다는 요청 앞에 멈춰서 언어 결정 구조 전체를 들여다봤던 것처럼. 이미지를 WebP로 변환하는 것으로 충분한지, 아니면 리사이즈부터 시작해야 하는지 먼저 따져보는 것처럼. AI에게 코드 작성을 시키기 전에 탐색을 먼저 요청하는 것처럼.
프론트엔드 DX는 거창한 스택 전환에서 오지 않는다. 포맷 선택 하나, 상태 설계 하나, 프롬프트 방식 하나—작은 결정들이 쌓여 팀이 만드는 제품의 완성도를 가른다.