Showing Posts From
프론트엔드
- 05 Dec, 2025
console.log 10개의 기도: 문제를 찾는 신입의 방식
console.log 10개의 기도: 문제를 찾는 신입의 방식 오늘도 에러가 났다. Uncaught TypeError: Cannot read property 'map' of undefined이게 뭐지. 어제까지 잘 됐는데. 일단 console.log부터 박는다. 첫 번째 기도 console.log('여기는 됨');함수 맨 위에 찍어본다. 이게 안 나오면 함수 자체가 안 도는 거니까. 콘솔에 '여기는 됨'이 뜬다. 좋아. 함수는 돈다. 그럼 문제는 안에 있다.두 번째부터 다섯 번째까지 console.log('데이터:', data); console.log('데이터 타입:', typeof data); console.log('데이터 길이:', data?.length); console.log('첫 번째 아이템:', data?.[0]);data를 온갖 방법으로 뜯어본다. 콘솔을 확인한다. 데이터: undefined 데이터 타입: undefined 데이터 길이: undefined 첫 번째 아이템: undefined아. data가 없다. 그럼 왜 없는데. 여섯 번째 useEffect(() => { console.log('useEffect 돌아감'); fetchData(); }, []);데이터를 가져오는 함수 전에 찍어본다. 'useEffect 돌아감'은 나온다. 그럼 fetchData는? 일곱 번째 const fetchData = async () => { console.log('fetchData 시작'); const response = await api.getData(); setData(response); };이것도 나온다. fetchData는 돈다. 그럼 api 응답이 문제인가. 여덟 번째 const fetchData = async () => { console.log('fetchData 시작'); const response = await api.getData(); console.log('응답:', response); setData(response); };콘솔을 본다. fetchData 시작 응답: {data: Array(0), message: "success"}어? 데이터가 빈 배열이다. 근데 성공은 했다고 나온다. 뭐지.아홉 번째 API 문서를 다시 본다. const response = await api.getData(); console.log('response.data:', response.data); console.log('response.result:', response.result);둘 다 찍어본다. response.data: [] response.result: Array(10)아. data가 아니라 result였다. 설마. 열 번째 const fetchData = async () => { const response = await api.getData(); console.log('최종 확인:', response.result); setData(response.result); };새로고침. 화면에 데이터가 뜬다. 된다. 에러가 사라졌다. 그리고 정리 console.log 10개를 지운다. 커밋 전에 전부 삭제. const fetchData = async () => { const response = await api.getData(); setData(response.result); };깔끔하다. 아무 일도 없었던 것처럼. 근데 PR 올릴 때 한 개가 남아있었다. console.log('여기는 됨');선배가 댓글 남겼다. "console.log 지워주세요" 얼굴이 빨개진다. "네 죄송합니다"왜 이러는가 디버거를 쓰면 된다는 걸 안다. breakpoint 찍고, step over 하고, 변수 값 실시간으로 보고. 근데 무섭다. 디버거 켜면 뭔가 잘못 건드릴 것 같다. console.log는 편하다. 찍고, 보고, 지우면 끝. 틀려도 상관없다. 아무도 모른다. 10개 찍든 20개 찍든. 내 화면에서만 보이니까. 선배는 안 그런다 옆자리 선배는 console.log를 안 쓴다. 에러 나면 일단 코드를 쳐다본다. 5분 정도. 그리고 정확히 문제 되는 줄로 간다. 고친다. 끝. 어떻게 아는 거지. 나는 30분 동안 console.log 10개 찍어서 찾은 걸. 언젠가는 나도 그렇게 되려나. 코드만 봐도 어디가 문제인지 아는. console.log 없이도 디버깅하는. 지금은 아니다. 지금은 console.log가 내 전부다. 10개든 20개든 찍는다. 그래도 문제를 찾는다. 그게 중요한 거다.오늘 저녁 퇴근 전에 한 개 더 찍었다. console.log('왜 안 돼'); 이건 내일 지우자.
- 03 Dec, 2025
'이거 간단한 건데' 라는 말이 가장 두려운 이유
'이거 간단한 건데' 라는 말이 가장 두려운 이유 그 말을 들으면 심장이 멈춘다 오전 10시. 슬랙이 울렸다. "신입님, 이거 간단한 건데 오늘까지 되겠죠?" 심장이 철렁했다. 손이 떨렸다. '간단한 건데'라는 말 뒤에는 항상 지옥이 숨어있다. 8개월 동안 배웠다. 이 문장이 나오면 무조건 어렵다는 걸.지난주였다. 팀장님이 말했다. "로그인 폼에 소셜 로그인 추가해줘. 간단한 거니까." 간단? 구글 OAuth 설정만 2시간 걸렸다. 리다이렉트 URI 오류로 3시간 더. 카카오는 또 다른 방식이었다. 네이버는 또 달랐다. 결국 3일 걸렸다. 간단하지 않았다. 선배의 '간단함'과 나의 '간단함' 선배한테는 진짜 간단한 거다. 인정한다. 하지만 나한테는 아니다. 선배는 React를 5년 썼다. 나는 8개월이다. 선배는 Redux 구조를 외우고 있다. 나는 useContext도 헷갈린다. 선배의 '간단함' = 30분 나의 '간단함' = 3일 이 차이를 모른다. 아니, 잊는다.한 달 전에 있었던 일이다. "API 연동 간단하니까 점심 전까지만." 간단할 리 없었다. CORS 에러부터 막혔다. 구글링했다. 해결책이 10가지였다. 다 해봤다. 안 됐다. 결국 선배한테 물어봤다. "아, 이거요? 프록시 설정하면 돼요. package.json에 한 줄만." 한 줄? 나한테는 그 한 줄을 찾는 데 3시간 걸렸다. '간단한 건데' 뒤에 숨은 것들 이 말 뒤에는 전제조건이 숨어있다. "(너가 기본 지식이 있다면) 간단한 건데" "(이미 해본 적 있다면) 간단한 건데" "(에러 안 나면) 간단한 건데" 나는 기본 지식이 없다. 해본 적도 없다. 에러는 항상 난다. 그러니 간단할 리 없다. 지난주 목요일. 선배가 말했다. "스타일 수정만 하면 되는데. CSS니까 간단하지." 간단하지 않았다. Flexbox 중첩 구조였다. justify-content와 align-items가 뭐가 다른지 또 헷갈렸다. 30분 만에 끝날 줄 알았다. 4시간 걸렸다. 부끄러웠다. CSS도 못 하나 싶었다.왜 '간단하다'고 말하는 걸까 악의는 없다고 본다. 선배들도 신입이었던 시절이 있다. 다만 잊었을 뿐이다. 처음 코드 짤 때의 막막함을. 에러 메시지가 무슨 뜻인지 몰랐던 순간을. 경험이 쌓이면 간단해진다. 당연하다. 하지만 경험 없는 사람한테 "간단하다"고 말하는 건 위험하다. 압박이 된다. '간단한 건데 왜 나는 못 하지?' 이 생각이 머릿속을 맴돈다. 자존감이 깎인다. 작년에 부트캠프 다닐 때다. 강사님이 말했다. "이거 간단하니까 집에서 복습해보세요." 복습 못 했다. 간단하지 않았으니까. 실제로 겪은 '간단한' 작업들 케이스 1: 데이터 정렬 "배열 정렬하면 되는데. sort() 쓰면 끝이야." 끝이 아니었다. 문자열 정렬인지 숫자 정렬인지부터 헷갈렸다. 한글 정렬은 또 달랐다. localeCompare라는 메서드를 처음 알았다. 2시간 걸렸다. 케이스 2: 컴포넌트 분리 "저 버튼 컴포넌트로 빼. 재사용하게. 간단하지?" 간단하지 않았다. props 어떻게 넘기지? 이벤트는 어떻게? children은 뭐고? onClick을 직접 넘겨야 하나 콜백으로 감싸야 하나? 결국 선배 코드 복사했다. 이해는 못 했다. 케이스 3: 환경변수 설정 "env 파일 만들어서 키 넣으면 돼. 간단해." .env? .env.local? .env.development? 뭐가 다른지 몰랐다. process.env로 접근한다는 것도 나중에 알았다. git에 올리면 안 된다는 것도. 30분짜리 작업이 반나절 갔다. 그래도 물어보기 어려운 이유 "이거 어떻게 하는 건가요?" 이 말을 꺼내기가 어렵다. '간단한 건데'라고 했으니까. 간단한 걸 물어보면 무능해 보일까 봐. 선배는 바쁘다. 코드리뷰하고 회의하고 자기 작업도 있다. 거기다 신입 질문까지 받으면 귀찮을 것 같다. 그래서 혼자 끙끙댄다. 3시간 걸릴 걸 10시간 걸려서 한다. 지난달이었다. useEffect 무한 루프에 빠졌다. 뭐가 문젠지 몰랐다. 의존성 배열 문제였는데. 선배한테 물어볼까 30분 고민했다. 결국 안 물어봤다. '간단한 거'라고 했으니까. 2시간 뒤에 해결했다. 스택오버플로우에서. 선배한테 물어봤으면 5분이었을 거다. '간단함'의 기준이 다르다는 걸 이해할 때 입사 6개월쯤 됐을 때였다. 후배가 들어왔다. 나보다 4개월 늦게. 내가 말했다. "이거 fetch로 데이터 가져오면 돼. 간단해." 후배가 멈칫했다. 그 표정을 봤다. 간단하지 않구나. 그제야 깨달았다. 나도 똑같이 하고 있었다. '간단하다'는 건 상대적이다. 나한테 간단한 게 남한테는 아니다. 그날 이후로 말을 바꿨다. "이거 fetch 써야 하는데, 처음이면 헷갈릴 수 있어요." 이렇게 말하니 후배가 편하게 물어봤다. 지금은 어떻게 대응하는가 '간단한 건데'라는 말을 들으면 일단 확인한다. "제가 이해한 게 맞나요? 이거 하면 되는 거죠?" 구체적으로 물어본다. 애매하게 넘어가면 나중에 더 힘들다. 시간도 여유 있게 받는다. "오늘까지요? 혹시 내일 오전까지도 괜찮을까요?" 못 한다고 솔직히 말하는 것도 배웠다. "죄송한데 이 부분 처음 해봐서 시간이 좀 걸릴 것 같습니다." 처음엔 부끄러웠다. 지금은 괜찮다. 모르는 게 당연하니까. 8개월 차의 결론 '간단한 건데'는 저주가 아니다. 단지 기준이 다를 뿐이다. 선배의 간단함과 나의 간단함은 다르다. 그걸 서로 이해해야 한다. 나도 2년 뒤엔 지금 일들이 간단해질 거다. 그땐 후배한테 조심해야겠다. '간단하다'고 쉽게 말하지 말아야겠다. 대신 이렇게 말하고 싶다. "이거 해봤어? 처음이면 좀 헷갈릴 수 있는데." 그게 진짜 선배가 하는 말 아닐까. 오늘도 '간단한 건데'라는 말을 들었다. 심장은 철렁했지만 물어봤다. "혹시 예시 코드 있으세요?" 선배가 보내줬다. 1시간 만에 끝났다. 물어보길 잘했다.간단한 게 어딨어. 다 어렵다. 그냥 익숙해지는 것뿐이지.
- 03 Dec, 2025
Next.js vs React, 신입은 둘 다 헷갈린다
Next.js vs React, 신입은 둘 다 헷갈린다 면접 때 했던 말 "React 할 줄 아세요?" "네, 할 줄 압니다." 거짓말은 아니었다. 부트캠프에서 6개월 동안 React 했다. 컴포넌트 만들고 state 쓰고 props 넘기고. Todo 앱도 만들었다. 영화 검색 앱도 만들었다. 포트폴리오에 당당하게 썼다. 근데 회사 왔더니 Next.js다. "우리 Next.js 쓰는데, React 할 줄 알면 금방이에요." 선배가 웃으며 말했다. 나도 웃었다. 속으로는 'Next.js가 뭐지?' 했다.첫날 코드 열었을 때 /pages /api index.js _app.js _document.js이게 뭐지. 부트캠프에서 본 구조가 아니다. src 폴더는? components 폴더는? App.js는 어디 갔나? 선배가 설명했다. "pages 폴더에 파일 만들면 자동으로 라우팅돼요. /about 만들려면 about.js 만들면 돼요." "아... 네네." React Router 공부한 건 뭐지. useNavigate 쓰라고 했는데. BrowserRouter 감싸라고 했는데. 다 필요 없단다. getServerSideProps가 뭔데 export async function getServerSideProps(context) { const res = await fetch('https://api...') const data = await res.json() return { props: { data } } }선배가 보낸 코드다. "이 함수 안에서 데이터 받아오면 돼요. 서버에서 실행되니까 API 키 노출 안 돼요." 서버에서 실행된다고? 나는 useEffect 안에서 fetch 하는 것만 알았다. 컴포넌트 마운트될 때 데이터 받아오는 거. 그게 React 아닌가? "아 그건 클라이언트 사이드 렌더링이고, 이건 서버 사이드 렌더링이에요." 클라이언트... 서버... 렌더링... 부트캠프에서 들어본 것 같기도 하고.그래서 뭐가 다른데 퇴근하고 검색했다. "Next.js는 React 프레임워크입니다." React가 라이브러리면 Next.js는 프레임워크. 뭔 차이지. 더 검색했다.React: 라우팅 직접 해야 함 (React Router)Next.js: 파일 기반 라우팅React: 클라이언트 사이드 렌더링Next.js: 서버 사이드 렌더링, 정적 생성, 클라이언트 사이드 렌더링 다 됨React: SEO 약함Next.js: SEO 좋음음... 알겠는데 모르겠다. 결국 ChatGPT한테 물었다. "5살 어린이에게 설명하듯이 알려줘." 답변 읽었다. 여전히 모르겠다. 실무에서 느낀 차이 일주일 지났다. 태스크 받았다. "상품 상세 페이지 만들기." Next.js에서는 이렇게 했다.pages/products/[id].js 파일 만듦 getServerSideProps에서 상품 데이터 받아옴 컴포넌트에서 props로 받아서 렌더링끝. React였으면?컴포넌트 만들고 React Router로 라우팅 설정하고 useParams로 id 받고 useEffect에서 fetch하고 useState로 데이터 저장하고 로딩 상태 처리하고더 복잡하다. 그런데 Next.js가 쉬운 건 아니다. 뭔가 자동으로 해주는 게 많아서 이해가 안 된다. "왜 이렇게 돌아가는 거지?"를 모른다.헷갈리는 순간들 상황 1: 컴포넌트에서 라우터 쓸 때 // React import { useNavigate } from 'react-router-dom'; const navigate = useNavigate();// Next.js import { useRouter } from 'next/router'; const router = useRouter();비슷한데 다르다. 자동완성 믿고 쳤다가 에러 났다. 상황 2: Link 컴포넌트 // React <Link to="/about">About</Link>// Next.js <Link href="/about">About</Link>to인지 href인지 매번 헷갈린다. 둘 다 써봤다. 당연히 에러 났다. 상황 3: 이미지 최적화 // React <img src="/logo.png" />// Next.js <Image src="/logo.png" width={100} height={100} />Next.js는 Image 컴포넌트 쓰라고 한다. width, height 필수래. 왜 필수인지는 나중에 알았다. 최적화 때문이라는데. 처음엔 귀찮아서 그냥 img 태그 썼다. 선배가 PR에 코멘트 남겼다. "Image 컴포넌트 써주세요." 고쳤다. 선배들 대화 엿듣기 점심시간. "이번에 SSG로 바꿀까 SSR 유지할까?" "트래픽 보고 판단해야지. ISR도 고려해봐." "Vercel 배포하면 자동으로 최적화되니까 괜찮을 거야." 나는 김밥 씹으면서 고개만 끄덕였다. SSG? SSR? ISR? Vercel? 또 모르는 단어들이다. 퇴근하고 검색했다.SSG: Static Site Generation (정적 사이트 생성) SSR: Server Side Rendering (서버 사이드 렌더링) ISR: Incremental Static Regeneration (증분 정적 재생성)한글로 쓰니까 더 어렵다. 결국 깨달은 것 Next.js는 React를 포함한다. React로 할 수 있는 건 Next.js에서도 다 된다. useState, useEffect, 컴포넌트, props, 다 된다. 거기에 추가 기능이 있는 거다.파일 기반 라우팅 서버 사이드 렌더링 이미지 최적화 API 라우트 등등그래서 "React 할 줄 알면 Next.js도 할 수 있다"는 말이 틀린 건 아니다. 하지만 쉬운 것도 아니다. React 개념 제대로 모르는데 Next.js 기능까지 배우려니 머리 터진다. 지금 내 상태 입사 8개월. Next.js 프로젝트 3개 했다. 아직도 헷갈린다. getStaticProps와 getServerSideProps 언제 쓰는지 헷갈린다. dynamic import는 왜 쓰는지 모르겠다. prefetch는 뭔지 감도 안 온다. 그래도 한 가지는 안다. 면접 때 했던 "React 할 줄 압니다"는 거짓말이었다는 것. 제대로 아는 게 아니었다. 겉핥기였다. 지금도 마찬가지다. Next.js 쓰긴 쓰는데 제대로 아는 건 아니다. 선배가 짠 코드 복붙해서 조금씩 수정하는 수준이다. 신입의 생존법 모르면 물어본다. "이거 왜 getServerSideProps 쓰는 거예요?" "이 페이지는 왜 getStaticProps 안 쓰나요?" "Link 컴포넌트 prefetch 기본값이 true라는데 성능 괜찮나요?" 처음엔 물어보기 무서웠다. "이런 것도 몰라?" 할까 봐. 근데 선배들 반응은 의외로 괜찮다. "좋은 질문이네요. 왜냐하면..." 설명 들으면 50%는 이해된다. 나머지 50%는 나중에 이해된다. 모르는 건 노션에 적는다. "getServerSideProps: 매 요청마다 서버에서 데이터 받아옴. 실시간 데이터 필요할 때." 이렇게 쌓다 보면 언젠가 내 것이 될 거다. 아마도. 한 가지 확실한 것 React와 Next.js는 다르다. 비슷하지만 다르다. React는 라이브러리. 자유도 높다. 내가 다 설정해야 한다. Next.js는 프레임워크. 정해진 구조가 있다. 그 안에서 작업한다. 어느 게 더 나은가? 모르겠다. 회사가 쓰는 걸 쓴다. 신입은 선택권이 없다. 그냥 적응한다. 헷갈려도 계속 쓴다. 그러다 보면 익숙해진다. 아직은 헷갈리지만.면접 때 "Next.js 할 줄 아세요?" 물어보면 뭐라 대답할까. "React는 하는데 Next.js는 헷갈려요"가 정답일 것 같다. 솔직하게.