console.log 10개의 기도: 문제를 찾는 신입의 방식

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('왜 안 돼'); 이건 내일 지우자.

에러 뜨면 일단 새로고침, 이게 최고의 디버깅 방법입니까

에러 뜨면 일단 새로고침, 이게 최고의 디버깅 방법입니까

에러 뜨면 일단 새로고침, 이게 최고의 디버깅 방법입니까 아침부터 빨간 글씨 출근했다. 커피 마시고 컴퓨터 켰다. 어제 작업하던 코드 실행했다. 빨간 글씨가 뜬다. 일단 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번 줄었다. 진짜다.

'이거 간단한 건데' 라는 말이 가장 두려운 이유

'이거 간단한 건데' 라는 말이 가장 두려운 이유

'이거 간단한 건데' 라는 말이 가장 두려운 이유 그 말을 들으면 심장이 멈춘다 오전 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시간 만에 끝났다. 물어보길 잘했다.간단한 게 어딨어. 다 어렵다. 그냥 익숙해지는 것뿐이지.

TypeScript any 남발 사건, 또는 선배한테 혼난 날

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 썼을 거다.

PR 올릴 때마다 손이 떨리는 이유

PR 올릴 때마다 손이 떨리는 이유

오늘도 PR 올렸다 키보드 앞에 앉았다. 손가락이 떨린다. Create Pull Request 버튼이 초록색으로 빛난다. 클릭하면 끝이다. 그런데 못 누른다. 3일 동안 짠 코드다. 로그인 페이지 리팩토링. 선배가 "이거 좀 정리해봐" 했던 건데, 막상 열어보니 스파게티 코드였다. 일단 작동은 한다. 로컬에서 10번 테스트했다. 근데 확신이 안 선다. 뭔가 놓친 게 있을 것 같다.체크리스트를 본다 노션에 적어둔 체크리스트를 연다. 로컬 테스트 완료 콘솔 에러 없음 코드 주석 달기 커밋 메시지 확인 PR 템플릿 작성다 했다. 근데 또 본다. 3번째다. 테스트는 했다. 근데 엣지 케이스는? 내가 모르는 케이스가 있을 수도 있다. 콘솔 에러는 없었다. 근데 warning은 2개 있었다. 괜찮은 건가. 나중에 물어봐야지. 주석은 달았다. 근데 너무 많나. 선배가 "주석 달지 말고 코드로 설명해" 했던 게 기억난다. 3개 지웠다. 커밋 메시지는 "feat: refactor login page UI"다. 괜찮은 것 같다. 근데 refactor인가 fix인가. 또 헷갈린다. PR 템플릿은 채웠다. "변경 사항", "테스트 방법", "스크린샷" 다 넣었다. 근데 너무 길다. 줄였다. 또 너무 짧다. 다시 늘렸다. 손가락이 계속 떨린다.마우스를 올린다 버튼 위에 마우스를 올렸다. 클릭만 하면 된다. 근데 못 한다. 머릿속으로 시뮬레이션한다.PR 올린다 슬랙에 알림 간다 선배가 본다 코드리뷰가 달린다여기서 멈춘다. 코드리뷰가 뭐가 올라올까. "이거 왜 이렇게 짰어요?" 이런 거. "useEffect 여기서 쓸 필요 없는데?" 이런 거. "타입 좀 제대로 써요" 이런 거. 다 맞는 말이다. 근데 매번 들으면 심장이 쿵 내려앉는다. 내가 모른다는 걸 또 들키는 기분이다. 물 한 모금 마셨다. 손은 여전히 떨린다.클릭했다 에라 모르겠다. 눌렀다. 초록색 버튼이 회색으로 바뀐다. "Pull Request #247 created" 심장이 빨라진다. 이제 돌아갈 수 없다. 슬랙을 연다. #dev-frontend 채널에 알림이 떴다. "이신입 님이 PR을 올렸습니다: feat: refactor login page UI" 선배 3명이 온라인이다. 누가 먼저 볼까. 5분이 지났다. 아무도 안 본다. 10분이 지났다. 김선배가 PR에 들어왔다. 빨간 점이 보인다. 손에 땀이 난다. 15분 지났다. 아직 코멘트 없다. 코드를 보는 중인가. 20분 지났다. 드디어 알림이 왔다. "Comment on your PR: 수고했어요. 몇 가지 코멘트 남겼습니다." 들어가본다. 코멘트가 7개다. 첫 번째: "여기 useState 초기값이 null인데 타입 명시 안 하셨네요" 맞다. 놓쳤다. 두 번째: "이 부분 조건문 중복인 것 같은데 함수로 빼면 어떨까요" 아. 그렇게 하는 거구나. 세 번째: "console.log 지워주세요" 아. 이런. 네 번째부터는 안 봤다. 일단 고쳐야 한다. 고친다 코멘트 하나씩 확인한다. useState에 타입 추가했다. useState<string | null>(null) 이렇게. 조건문은 validateInput 함수로 뺐다. 3줄이 1줄이 됐다. 깔끔하다. console.log 3개 지웠다. 디버깅할 때 찍어둔 건데 까먹었다. 나머지 4개도 다 고쳤다. 커밋 메시지는 "fix: apply code review feedback" 푸시했다. 다시 떨린다. 또 볼 건데. 또 뭐가 나올까. 30분 지났다. 김선배가 approve 눌렀다. "LGTM. 고생했어요" Looks Good To Me. 처음 봤을 땐 뭔 뜻인지 몰랐다. merge 버튼이 활성화됐다. 눌렀다. "Pull Request successfully merged and closed" 끝났다. 가슴이 내려앉는다. 후련하다. 근데 또 복잡하다. 왜 떨렸을까 매번 이렇다. PR 올릴 때마다 손이 떨린다. 머지되고 나면 괜찮다. 근데 올리기 전이 제일 무섭다. 뭐가 무서운 걸까. 틀릴까 봐. 모르는 게 들킬까 봐. 또 혼날까 봐. 다 맞다. 근데 제일 큰 건 이거다. 내가 잘하는지 모르겠다. 3일 동안 짠 코드인데, 이게 맞는지 확신이 없다. 작동은 하는데 잘 짠 건지 모르겠다. 선배들은 보면 안다. 한눈에 본다. "여기 이렇게 하면 안 돼요" 딱 집어낸다. 나는 모른다. 10번 봐도 모른다. 그게 무섭다. 코드를 올린다는 건 내 실력을 보여주는 거다. 숨길 수가 없다. "이 정도밖에 못 해요" 말하는 거랑 같다. 그게 떨리는 이유다. 그래도 올린다 근데 올려야 한다. 안 올리면 일이 안 된다. 코드는 혼자 짜는 게 아니다. 리뷰받아야 배운다. 혼자 공부하는 것보다 10배 빠르다. 김선배 코멘트 보면서 배웠다. useState 타입 명시하는 거. 조건문 함수로 빼는 거. console.log 지우는 거. 다 당연한 거다. 근데 나는 몰랐다. 이렇게 하나씩 배운다. 3개월 전 내 PR이랑 지금 PR 비교하면 다르다. 코멘트가 15개에서 7개로 줄었다. 그래도 떨린다. 여전히 떨린다. 근데 괜찮다. 이게 배우는 과정이다. 손 떨리는 게 부끄러운 게 아니다. 안 올리는 게 부끄럽다. 내일도 PR 올릴 거다. 또 떨릴 거다. 그래도 올린다.오늘 PR 7개 코멘트. 다음엔 5개로 줄여보자.