- 06 Dec, 2025
점심시간, 편의점 삼각김밥과 함께 강의 보기
점심시간, 편의점 삼각김밥과 함께 강의 보기 12시 30분, 편의점 가는 길 점심시간이다. 팀원들이 우르르 나간다. "신입님도 가시죠?" 물어본다. "저는 도시락 싸왔어요." 거짓말이다. 도시락 같은 거 안 쌌다. 그냥 혼자 먹고 싶다. 대화가 피곤하다. 무슨 말 해야 할지 모르겠다. "요즘 뭐 공부해요?" 물어보면 대답이 막힌다. 엘리베이터 타고 1층 내려간다. 편의점은 건물 옆이다. 2분 거리. 바람이 시원하다. 8월인데도 오늘은 좀 선선하다. 이럴 땐 밖에서 먹을까 생각했다가 관둔다. 노트북 들고 나오기 귀찮다.편의점 삼각김밥 고르기 편의점 문 열고 들어간다. 시원하다. 삼각김밥 코너로 간다. 오늘은 뭐 먹지. 참치마요? 아니 어제 먹었다. 김치참치? 별로다. 불고기? 그거 밥이 너무 적다. 결국 스팸마요 집는다. 항상 먹는 거다. 바나나우유도 하나 집는다. 2900원이다. 계산하고 나온다. 사무실로 돌아간다. 책상에 앉는다. 주변에 아무도 없다. 다들 밥 먹으러 나갔다. 1시까지는 조용하다. 노트북 켠다. 슬랙 알림 끈다. 유튜브 연다.'10분 안에 이해하는 useEffect' 오늘 볼 강의는 이거다. '10분 안에 이해하는 useEffect 완벽 정리'. 조회수 12만. 댓글 보면 다들 "이제 이해했어요!" 이런다. 나도 이해할 수 있을까. 재생 누른다. 삼각김밥 뜯는다. "안녕하세요 여러분~" 강사가 밝게 인사한다. 나는 스팸마요 한 입 먹는다. 맛있다. "useEffect는 React의 생명주기를 다루는..." 설명이 시작된다. 고개 끄덕인다. 두 입 먹는다. 강의는 계속된다. "의존성 배열에 따라서..." 뭔 소리지. 세 입 먹는다. 바나나우유 빨대 꽂는다. 빨대 소리가 좀 크다. 주변 둘러본다. 아무도 없다. 괜히 부끄럽다. 강의는 4분째다. 나는 절반 먹었다. 이해는? 잘 모르겠다.멀티태스킹이라는 착각 강의 들으면서 먹으면 더 잘 들어온다고 생각했다. 거짓말이다. 삼각김밥 먹는 데 집중한다. 씹는 데 집중한다. 우유 마시는 데 집중한다. 강의는 배경음악이다. 귀로는 들린다. 머리로는 안 들어온다. "그래서 cleanup 함수를 사용하면..." 강사가 말한다. cleanup? 뭐였지. 지난주에 찾아봤던 것 같은데. 되감기 누른다. 10초 전으로 돌아간다. 다시 듣는다. "cleanup 함수를 사용하면..." 아 맞다. 정리 함수. 컴포넌트 언마운트될 때. 근데 언마운트가 정확히 뭐였지. 일시정지 누른다. 검색한다. "react 언마운트 뜻". 블로그 글 하나 연다. 읽는다. "컴포넌트가 DOM에서 제거될 때..." 아 그거구나. 알 것 같다. 다시 강의 재생한다. 벌써 7분 지났다. 삼각김밥은 다 먹었다. 10분 강의, 25분 소요 강의는 10분이다. 나는 25분 걸렸다. 되감기 3번. 일시정지 5번. 다른 탭 열어서 검색 7번. 강의 끝났다. "오늘도 시청해주셔서 감사합니다!" 강사가 웃는다. 나는? 이해했나? 글쎄. useEffect는 알겠다. 의존성 배열도 알겠다. cleanup도 알겠다. 근데 내 코드에 어떻게 쓰지? 모르겠다. 내일 또 찾아볼 것 같다. "useEffect 의존성 배열 언제 써야 하나요". 이런 거. 휴지로 입 닦는다. 쓰레기 버린다. 시계 본다. 12시 57분. 3분 남았다. 슬랙 알림 켠다. 메시지 17개. 읽는다. "신입님 오후 3시 회의 있어요." 아 맞다. 잊고 있었다. 오후 3시 회의 전까지 회의까지 2시간이다. 오전에 못 끝낸 작업 이어서 한다. 버튼 컴포넌트 만들기. 간단해 보였다. 근데 props 타입 정의하는 게 헷갈린다. interface? type? 뭘 써야 하지. 검색한다. "interface vs type typescript". 블로그 10개 열린다. 읽는다. "interface는 확장 가능하고..." "type은 유니온 사용 가능하고..." 뭔 소리야. 그냥 선배 코드 본다. 선배는 interface 썼다. 나도 interface 쓴다. interface ButtonProps { children: React.ReactNode; onClick: () => void; }복사 붙여넣기 한다. 수정한다. 에러 난다. "Type 'MouseEvent' is not assignable to..." 뭐라는 거야. ChatGPT 연다. 에러 복사해서 붙여넣는다. "이 에러는 이벤트 타입이..." 답변 나온다. 코드 복사한다. 붙여넣는다. 에러 사라진다. 신기하다. 저장한다. 커밋한다. 푸시한다. 시계 본다. 2시 50분. 회의 10분 전이다. 화장실 간다. 볼일 보고 나온다. 손 씻는다. 거울 본다. 피곤해 보인다. 회의실 간다. 아직 아무도 없다. 자리 잡고 앉는다. 노트북 연다. 사람들 들어온다. "신입님 먼저 오셨네요?" 웃으면서 말한다. "네..." 대답한다. 회의 시작한다. 회의 중 멍때리기 "지난주 작업 현황 공유드리겠습니다." 팀장님이 말한다. 파워포인트 화면 바뀐다. 간트차트 같은 게 나온다. 빨강 노랑 초록 막대기들. "A 프로젝트는 80% 진행..." 고개 끄덕인다. A 프로젝트? 내가 하는 건가. "B 프로젝트는 일정이 지연..." 또 끄덕인다. 지연? 누구 때문이지. 나는 아니겠지. "신입님은 버튼 컴포넌트 작업 어떻게 돼가요?" 갑자기 내 이름 나온다. 놀란다. "아... 네. 거의 다 했습니다." 대답한다. 거의? 사실 70%도 안 됐다. "언제까지 가능할까요?" 팀장님이 묻는다. 언제까지? 모르겠다. 내일? 모레? "내일까지 하겠습니다." 입에서 나온다. 후회한다. 내일은 목요일이다. 할 수 있을까. "좋습니다. 그럼 다음..." 화면 넘어간다. 안도한다. 회의는 계속된다. 나는 멍하니 듣는다. 점심시간에 본 강의 생각난다. useEffect. 의존성 배열. cleanup. 아직도 잘 모르겠다. 내일 또 찾아봐야겠다. 퇴근 후 다시 보는 강의 9시에 퇴근한다. 집 가는 지하철. 앉아서 폰 꺼낸다. 유튜브 연다. 점심시간에 본 강의 다시 연다. '10분 안에 이해하는 useEffect 완벽 정리'. 이번엔 제대로 볼 거다. 집중해서. 이어폰 꽂는다. 재생 누른다. "안녕하세요 여러분~" 익숙한 목소리다. "useEffect는 React의 생명주기를..." 설명 시작한다. 3분 듣는다. 이해된다. 오 점심시간보다 낫다. 5분 듣는다. 눈이 감긴다. 피곤하다. 7분 듣는다. 깬다. 뭐라고 했지. 되감기 누른다. 10분 끝난다. 내 역이다. 내린다. 집 들어간다. 씻는다. 침대에 눕는다. 노트북 켠다. 강의 또 들어야 하나. 고민한다. 내일 하자. 눈 감는다.삼각김밥 먹으면서 보는 강의는 맛있지만, 머리엔 안 들어온다. 내일 또 볼 거다.
- 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('왜 안 돼'); 이건 내일 지우자.
- 04 Dec, 2025
에러 뜨면 일단 새로고침, 이게 최고의 디버깅 방법입니까
에러 뜨면 일단 새로고침, 이게 최고의 디버깅 방법입니까 아침부터 빨간 글씨 출근했다. 커피 마시고 컴퓨터 켰다. 어제 작업하던 코드 실행했다. 빨간 글씨가 뜬다. 일단 F5 눌렀다. 다시 빨간 글씨. F5 한 번 더. 또 빨간 글씨. 세 번째 새로고침 후에야 콘솔창을 봤다. "Cannot read property of undefined" 어쩌고. 무슨 말인지 모르겠다. 선배가 지나가다가 물었다. "뭐 안 돼?" "네... 에러가..." "콘솔 뭐라고 나와?" "아... 지금 보는 중이에요." 사실 방금 봤다. 세 번 새로고침 한 다음에.새로고침이 답인 줄 알았던 시절 부트캠프 때는 진짜 새로고침이 답이었다. 강사님이 말했다. "안 되면 새로고침 해보세요." 그래서 했다. 됐다. 신기했다. 개발서버 꺼졌을 때도 새로고침. 포트 번호 잘못 쳤을 때도 새로고침. 코드 저장 안 했을 때도 새로고침. 새로고침 3번이 안 되면 캐시 삭제. 그것도 안 되면 컴퓨터 재부팅. 이게 내 디버깅 프로세스였다. 입사 첫 주. 선배가 PR 코멘트 달았다. "이 부분 에러 핸들링 필요합니다." 무슨 말인지 몰랐다. 에러가 나면 새로고침 하면 되는 거 아닌가. 두 번째 주. 선배가 내 화면 보고 말했다. "새로고침 말고 콘솔 좀 보세요." 뜨끔했다. 들켰다. 콘솔은 무서운 곳 콘솔창을 열면 빨간 글씨가 가득하다. 숫자도 많다. :3742, :1849, :52. 뭔지 모른다. 줄번호라는 걸 3개월 차에 알았다. 에러 메시지는 영어다. 긴 영어다. 읽기 싫다. "Uncaught TypeError: Cannot read properties of undefined (reading 'map')" 읽어도 모른다. map이 뭐? undefined가 뭐? 다 아는 단어인데 합치니 모르겠다. 그래서 일단 새로고침 한다. 에러가 사라지면 좋겠다. 안 사라진다. 당연하다. 근데 매번 기대한다.3번의 법칙 내 디버깅 순서는 이렇다. 1번: 새로고침 2번: 새로고침 3번: 새로고침 4번: 콘솔 본다 왜 3번일까. 모른다. 그냥 3번은 해야 할 것 같다. 마법 같은 거다. 3번 하면 될 것 같은 기분. 선배가 물었다. "그거 왜 계속 새로고침 해요?" "아... 혹시 몰라서요." "혹시 뭐가요?" "그냥... 될까 봐서요." 선배가 한숨 쉬었다. 나도 안다. 이게 답이 아니라는 거. 근데 습관이다. 지금도 에러 뜨면 손이 먼저 간다. F5로. 생각보다 빠르다. 콘솔 읽는 것보다 빠르다. 새로고침이 진짜 답일 때 가끔은 진짜 새로고침이 답이다. 개발서버 재시작했을 때. 환경변수 바꿨을 때. 빌드 다시 했을 때. 이럴 땐 당당하다. "새로고침 하셔야 해요." 선배한테도 말한다. "캐시 문제일 수 있어요." 전문가 같다. 근데 대부분은 아니다. 새로고침이 답이 아닌 경우가 90%다. 아니, 95%다. 그래도 한다. 혹시 모르니까. 이번엔 5% 안에 들 수도 있으니까.에러 메시지를 읽기 시작한 날 3개월 차 어느 날이었다. 에러가 떴다. 새로고침 했다. 안 됐다. 또 했다. 안 됐다. 세 번째 했다. 여전히 안 됐다. 선배를 부를까 고민했다. 부끄러웠다. 또 새로고침만 했다고 혼날 것 같았다. 그래서 콘솝을 봤다. 천천히 읽었다. "data.map is not a function" data를 콘솔에 찍어봤다. console.log(data). 객체였다. 배열이 아니었다. 아. map은 배열에만 쓰는 거구나. 처음 알았다. 아니다, 알고는 있었다. 근데 까먹었다. 코드를 고쳤다. 됐다. 신기했다. 새로고침 안 하고 고쳤다. 뿌듯했다. 선배한테 말하고 싶었다. "저 혼자 해결했어요!" 근데 말 안 했다. 너무 당연한 걸 자랑하는 것 같아서. 여전히 새로고침부터 한다 그 뒤로도 나아졌을까. 아니다. 여전히 새로고침부터 한다. 지난주도 그랬다. API 호출이 안 됐다. 새로고침 했다. 안 됐다. 또 했다. 세 번째 후에 네트워크 탭을 봤다. 403 에러였다. 토큰이 만료됐다. 새로고침으로 해결될 리가 없다. 알고 있었다. 그래도 했다. 이게 습관이다. 나쁜 습관. 고쳐야 하는 습관. 근데 쉽지 않다. 선배가 말했다. "에러는 친구예요. 뭐가 잘못됐는지 알려주는 거예요." 맞는 말이다. 근데 친구가 빨간 글씨로 영어로 말하면 무섭다. 새로고침 카운터를 만들까 농담 반 진담 반으로 생각했다. 크롬 확장 프로그램. 새로고침 할 때마다 카운트. 하루에 몇 번 했는지 보여주기. "오늘 새로고침 237회. 그 중 의미 있었던 새로고침 2회." 부끄러울 것 같다. 근데 도움될 것 같다. 숫자로 보면 충격받을 것 같다. 동기한테 말했다. "나 새로고침 너무 많이 해." 걔도 그랬다. "나도. 습관임." 다들 그런가보다. 신입들은 다 그런가보다. 위안이 됐다. 근데 위안이 되면 안 되는데. 진짜 디버깅을 배우는 중 요즘은 조금 나아졌다. 에러 뜨면 일단 읽는다. 안 읽고 새로고침 하는 건 참는다. 손이 근질거려도 참는다. 콘솔에 console.log를 찍는다. 데이터가 어떻게 생겼는지 본다. undefined인지 null인지 빈 배열인지. 네트워크 탭도 본다. API 응답이 뭔지. 상태 코드가 뭔지. 200인지 400인지 500인지. 천천히 읽는다. 영어도 읽는다. 번역기 돌려서라도 읽는다. 시간이 오래 걸린다. 새로고침이 더 빠르다. 근데 새로고침은 답이 아니다. 알고 있다. 선배가 칭찬했다. "요즘 많이 늘었네요." 뭐가요? "에러 보고 물어보는 거. 예전엔 '안 돼요'였는데 요즘은 '이 에러가 이런데 이게 왜 이런 거죠?' 물어봐요." 기분 좋았다. 진짜로 늘은 건가. 아니면 그냥 새로고침 덜 하는 건가. 언제까지 이럴까 아직도 새로고침부터 할 때가 많다. 급할 때. 선배가 옆에 있을 때. 데모 직전일 때. 손이 먼저 간다. F5로. 고치고 싶다. 진짜 개발자는 이러면 안 될 것 같다. 에러를 읽어야 한다. 로그를 봐야 한다. 디버거를 써야 한다. 근데 쉽지 않다. 습관은 무섭다. 8개월 동안 만들어진 습관. 하루아침에 안 고쳐진다. 동기가 물었다. "너 요즘 어때?" "그냥... 살아있어. 근데 나 아직도 에러 나면 새로고침부터 해." "나도. 우리 언제 고쳐지려나." 모른다. 1년 차? 2년 차? 아니면 평생? 선배들도 새로고침 한다. 가끔. 진짜 필요할 때. 근데 그 '가끔'이 나랑 다르다. 나는 '항상'이니까. 그래도 나아지고 있다 3개월 전보다는 낫다. 새로고침 3번에서 2번으로 줄었다. 가끔은 1번만 하고 콘솔 본다. 가끔은 바로 콘솔 본다. 에러 메시지가 익숙해졌다. "Cannot read property" 나오면 undefined 체크 안 한 거다. "is not a function" 나오면 타입 확인해야 한다. 구글링도 늘었다. 에러 메시지 복사해서 검색한다. 스택오버플로우 답변 읽는다. 10개 중 1개는 도움된다. 선배한테 물어보는 것도 나아졌다. "안 돼요" 대신 "이 에러가 나는데 제가 이렇게 해봤는데도 안 되는데 혹시 뭐가 문제일까요?" 물어본다. 선배 표정이 달라졌다. 느리다. 진짜 느리다. 근데 나아지고는 있다. 신입에게 새로고침은 새로고침은 마법이 아니다. 알고 있다. 머리로는 안다. 근데 손은 모른다. 에러는 친구다. 무섭지만 친구다. 뭐가 잘못됐는지 알려주는 친구. 읽어야 한다. 천천히. 영어라도. 모르는 단어라도. 새로고침은 마지막이다. 콘솔 보고, 로그 찍고, 구글링하고, 그래도 안 되면. 그때 한 번. 이게 정답인 걸 안다. 근데 실천이 어렵다. 8개월 차 신입의 고백이다. 아직도 새로고침부터 한다. 부끄럽다. 근데 솔직하다. 언젠간 고쳐질까. 모르겠다. 그래도 오늘보다 내일이 나을 것 같다. 조금씩.오늘도 새로고침 57번. 어제보다 3번 줄었다. 진짜다.
- 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
TypeScript any 남발 사건, 또는 선배한테 혼난 날
TypeScript any 남발 사건, 또는 선배한테 혼난 날 사건의 발단 오늘 아침에 PR 올렸다. 회원가입 폼 기능 추가. 이틀 걸렸다. 자신 있었다. 일단 돌아갔으니까. 로그인도 되고 회원가입도 되고. 테스트도 다 통과했다. 내가 봐도 깔끔했다. 점심 먹고 돌아왔는데 슬랙 알림 6개. 심장이 쿵 내려앉았다. "이신입님, PR 확인 부탁드립니다." 선배 멘션이었다. 그것도 김민수 선배. 우리 팀에서 제일 무서운 분. 클릭했다. 코멘트 12개. 빨간 줄이 화면을 가득 채웠다. 첫 줄부터 시작됐다. "any 타입 왜 이렇게 많나요?"any가 뭐가 문제인데 처음엔 이해가 안 갔다. 돌아가는데 뭐가 문제야. TypeScript 배울 때 강의에서 들었다. "타입을 지정하세요." 근데 any도 타입 아닌가. 에러도 안 나는데. const handleSubmit = (data: any) => { // 이게 뭐가 문제지? }이렇게 쓰면 편했다. 빨간 줄도 안 생기고. 일단 돌아가니까. 김민수 선배 코멘트를 하나씩 읽었다. "여기 data 타입 명시 필요합니다." "any 쓰면 TypeScript 쓰는 의미가 없어요." "FormData 타입 만들어서 쓰세요." FormData? 그게 뭔데. 또 다른 코멘트. "response도 any네요. 이것도 인터페이스 만드세요." 인터페이스. 들어본 적은 있다. 근데 어떻게 만드는지 모른다.변명의 시간 일단 답장을 써야 했다. "아... 네네 수정하겠습니다." 손이 떨렸다. 뭘 어떻게 고쳐야 할지 모르겠는데. 5분 뒤에 선배가 또 슬랙을 보냈다. "신입님, 잠깐 통화 가능하세요?" 끝났다. 진짜 혼나는 거다. 구글 미트 켰다. 선배 얼굴이 나왔다. 화난 것 같지는 않았다. 그게 더 무서웠다. "신입님, any 타입 많이 쓰셨네요." "아... 네... 그게..." 변명이 나왔다. "타입을 어떻게 지정해야 할지 몰라서요. 에러가 계속 나서..." 선배가 한숨을 쉬었다. 조용한 한숨. 실망한 한숨. "TypeScript는 타입을 지정하라고 쓰는 건데, any 쓰면 JavaScript랑 다를 게 없어요." 알았다. 머리로는. "근데 제가 타입을 몰라서..." "그럼 공부하셔야죠." 할 말이 없었다. 선배의 수업 선배가 화면 공유를 시작했다. 내 코드가 떴다. const handleSubmit = (data: any) => { console.log(data); // ... }"이거부터 볼까요. data가 뭐가 들어올지 알죠?" "네... 이메일이랑 비밀번호요." "그럼 이렇게 쓰면 돼요." interface FormData { email: string; password: string; }const handleSubmit = (data: FormData) => { console.log(data.email); // 자동완성도 됨 }아. 이렇게 하는 거구나. 선배가 계속 설명했다. "이렇게 하면 타입 안전성이 생겨요. data.eamil 이렇게 오타 내면 에러 나죠." 신기했다. 그동안 난 뭐 한 거지. "response도 마찬가지예요." const response: any = await fetch('/api/login');"이거 말고," interface LoginResponse { success: boolean; token?: string; error?: string; }const response: LoginResponse = await fetch('/api/login').then(r => r.json());"이렇게 쓰면 response.token 자동완성도 되고, 오타도 방지되고." 머리가 띵했다. 이렇게 쓰는 거였구나.any를 쓴 이유 선배가 물었다. "근데 왜 any를 이렇게 많이 쓰신 거예요?" 솔직하게 말했다. "타입 지정하려고 하면 빨간 줄이 너무 많이 생겨서요. 에러 메시지도 무슨 말인지 모르겠고." "'Type string is not assignable to type number' 이런 거요?" "네... 그래서 일단 any 쓰면 없어지니까..." 선배가 웃었다. 비웃는 게 아니라 이해한다는 웃음이었다. "저도 처음엔 그랬어요. any 쓰면 편하죠. 근데 나중에 더 힘들어져요." "어떻게요?" "코드가 커지면, any 때문에 어디서 에러 날지 모르거든요. 런타임에 터져요." 런타임. 그게 뭐지. 모르는 척했다. 일단 고개만 끄덕였다. "그리고 any 쓰면 자동완성도 안 돼요. 매번 뭐가 들어있는지 확인해야 하고." 아. 그래서 내가 맨날 console.log 찍었구나. 고치는 시간 통화 끝나고 코드를 다시 봤다. any가 17개였다. 하나씩 고쳤다. 선배가 알려준 대로. 첫 번째. FormData 인터페이스 만들기. interface SignupFormData { email: string; password: string; name: string; age: number; }age는 number구나. 당연한데 몰랐다. 두 번째. API response 타입. interface ApiResponse { success: boolean; data?: any; // 이것도 any네... error?: string; }data도 타입을 지정해야 했다. 뭐가 들어올까. 회원 정보니까. interface UserData { id: number; email: string; name: string; }interface ApiResponse { success: boolean; data?: UserData; error?: string; }이렇게 하니까 깔끔했다. 뭔가 프로 같았다. 세 번째부터는 좀 빨라졌다. 패턴이 보였다.any 찾기 뭐가 들어오는지 생각하기 인터페이스 만들기 적용하기2시간 걸렸다. any가 0개가 됐다. PR 다시 올렸다. 코멘트 달았다. "any 타입 모두 수정했습니다. 확인 부탁드립니다." 다시 코드리뷰 30분 뒤에 선배가 답글 달았다. "훨씬 좋아졌네요 👍" 심장이 두근거렸다. 칭찬이다. 선배한테 칭찬 들은 건 처음이다. "몇 가지만 더 수정하면 될 것 같아요." 또 코멘트가 달렸다. 3개. 아까보다 훨씬 적었다. "여기 optional 타입 물음표 빼도 될 것 같아요." "이 부분은 타입 추론 되니까 명시 안 해도 돼요." "Union 타입 쓰면 더 정확할 것 같네요." Union 타입? 또 모르는 용어다. 검색했다. string | number 이런 거였다. 아 이런 것도 있구나. 고쳤다. 다시 올렸다. 10분 뒤에 Approve 떴다. "LGTM! Merge 하셔도 됩니다." LGTM. Looks Good To Me. 이건 안다. 부트캠프에서 배웠다. Merge 버튼 눌렀다. 초록색으로 바뀌었다. "Merged". 기분이 이상했다. 뿌듯한데 부끄러웠다. 이제야 제대로 한 거 같은데, 진작 이렇게 했어야 했는데. 그날 저녁 퇴근하고 편의점 갔다. 맥주 2캔 샀다. 삼각김밥도. 원룸 들어와서 노트북 켰다. 인프런에 TypeScript 강의 검색했다. "타입스크립트 올인원" 결제했다. 66000원. 아깝지만 필요했다. 첫 강의 재생했다. "TypeScript가 뭔가요?" 알 것 같으면서도 모르겠다. 제대로 배워본 적이 없으니까. 강의 들으면서 메모했다. 노션에.any는 최대한 쓰지 말기 인터페이스로 타입 정의하기 타입 추론 활용하기 Union 타입 (|) Optional 타입 (?)메모하다가 든 생각. 나 지금까지 뭐 한 거지. 부트캠프 6개월. TypeScript 2주 배웠다. 근데 any만 썼다. 제대로 배운 게 없었다. 입사하고 8개월. 그동안 계속 any 썼다. 아무도 안 알려줬다. 물어보지도 않았다. 선배가 오늘 처음 짚어줬다. 그것도 코드리뷰에서. 부끄러웠다. 강의 1시간 들었다. 눈이 떠지는 기분이었다. "타입은 문서예요. 코드를 설명하는." 아. 그래서 타입을 정확히 써야 하는구나. "any는 타입 시스템을 무너뜨려요." 내가 한 짓이 그거였다. 타입 시스템을 무너뜨린 거. 다음날 아침 출근했다. 9시 8분. 오늘은 일찍 왔다. 슬랙 켰다. 김민수 선배가 메시지 보냈다. "신입님, 어제 수정 잘 하셨어요. 앞으로도 타입 꼼꼼히 지정하시면 좋을 것 같아요." "네 감사합니다. TypeScript 강의 결제했습니다." "오 좋네요. 궁금한 거 있으면 언제든 물어보세요." 물어봐도 되는구나. 몰랐다. 항상 혼자 끙끙댔는데. 오늘 작업 시작했다. 새로운 기능 추가. 장바구니 API 연결. 이번엔 달랐다. 먼저 타입부터 정의했다. interface CartItem { id: number; name: string; price: number; quantity: number; }interface CartResponse { items: CartItem[]; total: number; }코드 쓰기 전에 타입 먼저. 선배가 알려준 대로. 신기했다. 자동완성이 됐다. item. 찍으니까 id, name, price, quantity가 뜬다. console.log 안 찍어도 됐다. 뭐가 들어있는지 알았으니까. 에러도 빨리 찾았다. item.price 를 item.cost로 잘못 썼는데 바로 빨간 줄 떴다. "Property 'cost' does not exist on type 'CartItem'." 아. 이게 TypeScript구나. 2주 후 PR 올렸다. 장바구니 기능 완성. any는 0개. 김민수 선배가 리뷰했다. 코멘트 2개. "타입 정의 깔끔하네요." "LGTM!" 2개. 처음으로 한 자릿수 코멘트. Approve 바로 떨어졌다. Merge 했다. 슬랙에 선배가 또 메시지 보냈다. "신입님 많이 늘었어요. 타입 쓰는 거 보니까." 기분이 좋았다. 진짜 좋았다. 인정받는 기분. 선배한테 혼난 지 2주 만에. 그날 저녁에 부트캠프 동기 단톡방에 썼다. "너네 TypeScript any 쓰지 마. 진짜로." "왜? 편한데?" "나 그거 때문에 혼났어. 제대로 배워." "ㅋㅋㅋ 오케이." 얘들도 언젠가 혼날 거다. 나처럼.any는 마약이었다. 당장 편하지만 나중에 독이 됐다. 2주 동안 TypeScript 강의 10시간 들었다. 이제야 TypeScript 쓰는 이유를 알았다. 선배한테 혼나서 다행이다. 안 그랬으면 계속 any 썼을 거다.