고백할 게 있다. 나는 프론트엔드 개발자 3년차인데, 아직도 flexbox 중앙 정렬을 구글링한다.
justify-content가 가로인지 세로인지, align-items가 뭘 정렬하는 건지, 매번 헷갈린다. flex-direction: column을 쓰면 축이 뒤바뀐다는 거 알고 있다. 알고 있는데 막상 코드를 칠 때 되면 확신이 안 선다. 그래서 검색한다. "css flex center both axes." 이미 브라우저 즐겨찾기에 CSS-Tricks Flexbox 가이드가 있다. 그 유명한 개구리 그림 있는 거. 한 달에 세 번은 들어간다.
이거 나만 그런 건 줄 알았는데, 회사 동료한테 넌지시 물어봤더니 그 사람도 검색한다고 했다. 5년차였다. 그 사람은 grid-template-areas 문법을 매번 검색한다고 했다. 우리 둘 다 웃었다. 안심이 됐다.
이건 비밀인데 — 아마 비밀도 아닐 거다 — 대부분의 개발자가 비슷하다. 그래서 매번 구글링하는 것들을 솔직하게 적어보려고 한다.
1. Flexbox 중앙 정렬
이미 말했다. display: flex; justify-content: center; align-items: center; 이거 세 줄이다. 세 줄인데 매번 순서를 잊는다. align-content라는 게 또 있어서 더 헷갈린다. place-items: center 쓰면 한 줄로 되는 거 아닌가? 된다. 근데 이게 grid에서만 되는 건가? flex에서도 되나? 또 검색한다.
2. Date 객체 포맷팅
JavaScript의 Date 객체는 인류의 적이다.
"2026년 3월 12일"을 만들고 싶을 뿐인데 getMonth()가 0부터 시작한다는 걸 매번 잊는다. 3월이면 2를 리턴한다. 왜. 대체 왜. 누가 이렇게 설계한 거냐.
toLocaleDateString의 옵션도 외우는 걸 포기했다. { year: 'numeric', month: 'long', day: 'numeric' }이었나? '2-digit'이었나? 매번 MDN을 연다.
요즘은 그냥 date-fns 쓴다. 아, date-fns에서 format 함수 토큰도 검색한다. yyyy가 연도인 건 아는데 MM이 월이고 mm이 분인 건 맨날 헷갈린다. 대문자 소문자 하나 차이로 "2026-15-12" 같은 괴상한 날짜가 나온 적이 한두 번이 아니다.
3. 정규표현식
정규표현식을 유창하게 쓰는 사람은 인간이 아니다. 아니면 매일 쓰는 사람이거나.
이메일 검증 정규표현식을 처음부터 짜라고 하면 나는 못 한다. 매번 복사한다. ^[^\s@]+@[^\s@]+\.[^\s@]+$ 이거 외워본 적은 있다. 3일 만에 까먹었다.
/g 플래그를 붙이면 lastIndex가 기억되면서 test() 결과가 번갈아 나오는 버그도 매번 당한다. 몇 번째인지 모르겠다. true, false, true, false... 이게 뭐냐고 30분 동안 디버깅하다가 "아 또 이거네" 하는 순간의 자괴감이란.
lookahead, lookbehind 같은 건 존재한다는 것만 안다. 매번 regex101.com에서 테스트하면서 맞춘다.
4. Array 메서드 리턴값
splice가 원본을 바꾸는 건지 새 배열을 리턴하는 건지. 원본도 바꾸고 잘라낸 것도 리턴한다. 맞나? 검색해보겠다. 맞았다.
slice랑 splice. 이름이 왜 이렇게 비슷한 건지 모르겠다. 하나는 순수하고 하나는 파괴적인데, 어느 쪽이 어느 쪽인지를 매번 확인한다. slice가 순수한 거다. 아마도. 맞다.
reduce의 초기값 위치도 매번 본다. 콜백이 첫 번째 인자고 초기값이 두 번째인 건 아는데, 콜백 안의 파라미터 순서가 (accumulator, currentValue)인 건지 (currentValue, accumulator)인 건지 사실 자신 없다. 전자가 맞다. 하지만 1초 동안은 확신이 안 섰다.
5. git rebase 명령어
git rebase를 사용하는 건 좋다. 히스토리가 깔끔해지니까. 문제는 매번 사용법을 까먹는다는 거다.
git rebase -i HEAD~3을 치면 에디터가 뜨는데, pick을 squash로 바꿔야 하는 건지 fixup으로 바꿔야 하는 건지 매번 헷갈린다. 둘 다 합치는 건데, 하나는 커밋 메시지를 남기고 하나는 안 남긴다. 어느 쪽이 어느 건지. 검색한다.
rebase 중 충돌 나면 --continue인지 --abort인지 --skip인지도 매번 순간적으로 불안해진다. 보통 --continue인데, 잘못해서 --abort 치면 다 날아가니까. 사실 안 날아간다. 근데 왠지 날아갈 것 같은 느낌. 그 느낌 때문에 검색한다.
6. border-radius로 원 만들기
50%인지 100%인지 매번 확인한다. 답은 50%다. 그런데 border-radius: 9999px을 쓰는 사람도 있다. 둘 다 된다. 근데 왜 9999px이 되는 건지 원리를 매번 까먹는다. 요소 크기의 절반보다 큰 값이면 원이 된다는 거다. 아마 맞을 거다.
7. position: sticky의 조건
분명 position: sticky를 적용했는데 안 먹히는 경우. 이거 범인 찾는 데 최소 30분은 쓴다.
부모 요소에 overflow: hidden이 있으면 안 된다는 거. 이걸 몇 번을 당한 건지 모르겠다. 알고 있다. 아는데 당한다. 왜냐하면 overflow: hidden이 직계 부모가 아니라 조상 어딘가에 숨어 있으면 찾기가 어렵기 때문이다. DevTools에서 한 단계씩 올라가면서 overflow 속성을 확인하는 나를 발견할 때의 자괴감이란.
8. localStorage에 객체 저장
localStorage.setItem('user', user)를 하면 [object Object]가 저장된다. 이거 아는데 또 실수한다. JSON.stringify를 빼먹는다. 읽을 때 JSON.parse를 빼먹는다. 1년에 두세 번은 이걸로 5분을 날린다. 5분이면 다행이다.
9. async/await 에러 핸들링
try/catch로 감싸야 하는 건 아는데, Promise.all에서 하나가 실패하면 전부 실패한다는 걸 매번 재확인한다. Promise.allSettled가 있다는 것도 안다. 근데 allSettled의 리턴값 구조가 { status: 'fulfilled', value: ... }인지 { status: 'resolved', value: ... }인지 매번 헷갈린다. fulfilled가 맞다. 방금 확인했다.
10. TypeScript의 Omit과 Pick 문법
둘 다 유틸리티 타입인 건 안다. Omit<User, 'password'>가 password를 빼는 건지 password만 남기는 건지. Omit이 빼는 거다. Pick이 남기는 거다. 이름 그대로인데 왜 매번 3초 동안 멈칫하는지 모르겠다. 아마 영어가 모국어가 아니어서 그런 거라고 자기 합리화를 하고 있다.
11. 이벤트 버블링 막는 방법
stopPropagation인지 preventDefault인지 매번 헷갈린다. 둘 다 이벤트 관련인 건 아는데, 하나는 이벤트가 상위로 전파되는 걸 막는 거고, 하나는 브라우저의 기본 동작을 막는 거다. 폼에서 엔터 키 누르면 페이지가 새로고침되는 거 막으려면 preventDefault. 모달 바깥 클릭 이벤트가 모달 안으로 전파되는 거 막으려면 stopPropagation. 맞나? 맞다. 하지만 작성하는 순간에는 항상 한 박자 멈추고 확인한다.
e.stopPropagation()이랑 e.stopImmediatePropagation()의 차이도 있다. 후자는 같은 요소에 등록된 다른 이벤트 리스너의 실행도 막는다. 이건 1년에 한 번 정도 필요한데, 필요할 때마다 검색한다.
12. JSON.stringify의 세 번째 인자
개발하다가 콘솔에 JSON을 이쁘게 출력하고 싶을 때가 있다. JSON.stringify(data, null, 2). 이게 들여쓰기 2칸으로 포맷팅되는 건 아는데, 두 번째 인자 null이 뭔지를 매번 까먹는다. replacer라는 건데, 보통 안 쓰니까 null을 넣는다. 근데 혹시 null이 아니라 undefined여도 되나? 된다. 빈 자리가 문제인 건가? 그냥 null 넣으면 된다. 이 고민을 매번 3초씩 한다.
매번 검색하는 건 나쁜 게 아니다
이 목록을 쓰면서 "와, 나 진짜 아무것도 모르는 거 아닌가" 싶었다. 잠깐 그런 생각이 들었다.
근데 사실 이게 핵심이다. 개발자의 진짜 실력은 문법을 외우고 있는 게 아니다. 문제를 만났을 때 뭘 검색해야 하는지 아는 거다. "css flex center"를 검색하면 1초 만에 답이 나온다. 그 1초의 검색으로 해결될 걸 굳이 머릿속에 저장하고 있을 필요가 있나.
진짜 중요한 건 검색어를 만드는 능력이다. "왜 sticky가 안 먹히지?"를 "css position sticky not working overflow parent"로 변환하는 스킬. 이게 초보와 경험자의 차이다. 초보는 뭘 검색해야 하는지 모른다. 경험자는 뭘 검색해야 하는지 안다.
그리고 하나 더. 이 목록은 시간이 지나면 바뀐다. 1년 전에는 useEffect의 dependency array를 매번 검색했는데 지금은 안 한다. 대신 새로운 게 추가됐다. React Server Components에서 'use client'를 어디에 붙여야 하는지, Next.js App Router에서 loading.tsx와 Suspense의 차이가 뭔지. 검색 목록이 바뀐다는 건 성장하고 있다는 뜻이다.
다만 Date 객체의 getMonth()가 0부터 시작한다는 건 아마 영원히 매번 확인할 것 같다.
그건 내 잘못이 아니라 JavaScript의 잘못이다. 이것만은 확실하다.
