동작하는 ?? null 을 지워야 하는 이유
API 응답을 화면용 객체로 바꾸는 코드에 ?? null 이 153곳 붙어 있었습니다. 장애는 없었지만 이 줄은 undefined 만 null 로 바꿀 뿐 어느 필드가 null 일 수 있는지는 알려 주지 않았고, 다음 변경 때 고칠 곳을 컴파일러가 찾지 못했습니다. null 정보를 명세에 두고 ?? null 을 지우기로 한 근거를 공식 문서와 직접 돌린 결…
API 응답을 화면용 객체로 바꾸는 코드에 ?? null 이 153곳 붙어 있었습니다. 장애는 없었지만 이 줄은 undefined 만 null 로 바꿀 뿐 어느 필드가 null 일 수 있는지는 알려 주지 않았고, 다음 변경 때 고칠 곳을 컴파일러가 찾지 못했습니다. null 정보를 명세에 두고 ?? null 을 지우기로 한 근거를 공식 문서와 직접 돌린 결…
서버는 진행률을 마일스톤 단위로만 주는데 화면은 연속으로 차올라야 했습니다. 브라우저에 보간을 맡기지 못한 이유와, 매 프레임 누적되는 값을 ref 원본과 state 사본으로 나눈 과정을 적었습니다.
서버가 내려주는 메뉴 데이터로 사이드바를 걸렀는데, 주소창에 경로를 직접 치면 그 화면이 그대로 열렸다. 라우트에 메뉴 키를 붙여 숨기는 판정과 막는 판정이 같은 데이터를 쓰게 만든 과정.
온프레미스로 여러 고객사에 나가는 제품에서 고객사별 차이를 어디에 둘지 세 번 바꾼 이야기. 고객사별 레포에서 한 레포 + .env 분기로, 다시 서버가 내려주는 메뉴 데이터로 옮기면서 사이드바와 검색 팔레트를 거르도록 바꾼 과정.
버튼 하나가 쿼리 세 개를 갱신하는 화면에서 조회 버튼을 막으려다 useIsFetching을 알게 됐습니다. 훅마다 isFetching을 꺼내 조합하려던 방향을 왜 바꿨는지, 그리고 이 방법을 쓰려면 쿼리 키가 어떻게 나뉘어 있어야 하는지 적었습니다.
피드가 500이 나서 열어봤더니, 마이그레이션이 5일 전부터 실패한 채 막혀 있었어요. 그 5일 동안 왜 문제를 발견하지 못했는지 하나씩 짚어봤습니다.
AI 코딩 에이전트가 과설계하는 습관을 잡아주는 오픈소스 스킬 Ponytail을 직접 붙여 써봤습니다. YAGNI 사다리로 코드를 덜 쓰게 만드는 원리와, 디바운스 훅 하나를 서른 줄에서 두 줄로 줄인 체험을 정리했습니다.
truncate와 line-clamp는 동작 기반이 다릅니다. flex와 함께 쓰면 왜 조용히 안 잘리는지, 그럴 때 무엇부터 확인해야 하는지 정리했습니다.
프론트 작업 중 인덱스 검증 화면을 만나, SQL 인덱스를 처음부터 다시 파봤습니다. 인덱스가 뭔지부터 옵티마이저·EXPLAIN PLAN·INVISIBLE 인덱스까지, "만든 인덱스가 정말 쓰이긴 하는가"라는 질문을 따라가며 정리한 1편입니다.
앞에서 익힌 인덱스 지식을 들고 인덱스 검증 React 컴포넌트를 한 줄씩 읽었습니다. created/utilized 두 축이 어떻게 표가 되는지, 복사 버튼이 왜 이름이 아니라 DDL을 복사하는지를 도메인 제약으로 되짚은 2편입니다.
웹스토어에 올라가 있지 않은 크롬 확장을 zip으로 받아 "압축 해제된 항목 로드(unpacked)"로 설치하는 방법을 정리했습니다.
discriminated union이 무엇인지, 그리고 종류마다 데이터가 다른 상황에서 왜 유용한지 정리했습니다. 판별자와 타입 좁히기부터 never 완전성 검사까지, 폼 필드 하나로 풀어 봅니다.
같은 필드인데 생성은 필수, 편집은 선택이라 아무도 정답을 몰랐던 폼. 타입 분리가 없는 게 문제로 보였지만 진짜 문제는 중복이었고, 중복부터 걷어낸 뒤에야 discriminatedUnion으로 도메인을 다시 모델링할 수 있었던 과정을 공유합니다.
discriminatedUnion으로 폼을 깔끔하게 짠 다음 실제로 겪은 Zod 함정 세 가지. union 에러 메시지, superRefine과 DU 사이의 선택, 그리고 defaultValues가 유니온 타입과 부딪히던 지점을 정리했습니다.
스크린샷 첨부 대신 AI에게 직접 페이지를 열어 확인하게 시키는 Playwright MCP를, 평소 쓰는 패턴과 함께 소개합니다.
매번 새 프로필로 뜨는 Playwright MCP를 평소 쓰는 Chrome 프로필에 연결하는 방법을 정리했습니다.
Headless UI 라이브러리 Radix UI와 Base UI의 설계 철학, API, 접근성, 개발 경험을 비교합니다
i18next 공식 CLI를 돌렸더니 네임스페이스 전체를 경고 없이 삭제 대상으로 잡았습니다. I18N_KEYS 상수 객체 패턴이 공식 도구와 충돌한 과정과, 커스텀 스크립트를 택한 이유.
I18N_KEYS를 진실원으로 삼는 AST 수집기의 설계. 네임스페이스 해석, 키 수집, 화이트리스트, 30% 안전 가드, 그리고 GitHub Actions 주간 cron 자동 PR까지.
ErrorBoundary를 감쌌는데 에러가 안 잡히는 상황. React Router가 내부에서 먼저 에러를 잡고 있었고, errorElement로 해결한 과정을 공유한다.
Flutter 시뮬레이터에서 잘 되던 API 호출이 실기기에서 Connection refused, localhost가 가리키는 곳이 달랐다. 원인을 찾고 device_info_plus로 자동 감지까지 구현한 과정.
Orval이 생성하는 파일 헤더의 OpenAPI spec version 때문에 500개 파일에 불필요한 diff가 생기는 문제를, 커스텀 header 함수로 해결한 경험.
Obsidian 안에서 Claude Code를 쓸 수 있는 Claudian 플러그인을 발견하고, 설치부터 블로그 글 리뷰 워크플로우까지 녹여낸 경험을 정리했습니다.
Next.js 블로그에서 콘텐츠를 app 폴더 밖으로 분리하고, Obsidian vault로 열어 글 전용 환경을 만든 과정을 정리했습니다.
Obsidian의 ![[이미지.webp]] 문법이 MDX에서 깨지는 문제를 커스텀 remark 플러그인으로 해결한 과정
메타데이터 검증으로 충분하다고 생각했지만, PDF 페이지 비율 문제를 만나면서 콘텐츠 검증이라는 새로운 레이어가 필요해졌습니다. 함수 주입 vs 설정 기반, 동기 vs 비동기 경계를 설계한 과정을 다룹니다.
업로드 상태를 통합하기 위해 만든 커스텀 훅이, 에러 시 파일을 Map에서 바로 삭제해버리는 구조였습니다. v1의 설계를 분석하고 한계를 정리합니다.
v1이 업로드만 래핑했던 한계를 넘어, 어떤 API를 훅에 포함하고 어떤 API는 제외할지 판단 기준을 세우고, v2의 인터페이스와 상태 모델을 설계합니다.
3편에서 설계한 인터페이스를 구현합니다. 에러 복구, 업로드 진행률, 동시성 제어, 취소, 확정 통합까지 v2의 핵심 구현을 다룹니다.
하나의 파일 API를 5개 컴포넌트에서 각각 useMutation으로 정의하고, 에러 처리가 제각각인 문제를 정리합니다.