우테코: 최종 코딩테스트 복기

1차 합격, 최종 코딩테스트

메일, 12월 11일

우테코 1차 합격 메일

12월 16일 잠실에 있는 우테코 캠퍼스에서 최종 코딩테스트를 보러 가게 됐다. 사실 프리코스가 종료되고 1차 합격 결과까지 대략 한 달의 공백이 존재했기 때문에, 1차 결과 발표날을 약간 잊고 살았다. 당일에 달력에 적어둔 걸 보고 ‘오늘이 1차 발표날이군.’ 정도만 인식했다. 그리고 대망의 15시가 되었고, 1차 합격 발표 메일을 받게 되었다.

준비, 12월 12일 ~ 15일

1차 합격 발표를 받고 5일의 시간이 존재했다. (1차 합격 메일은 12월 11일에 받았고 시험은 12월 16일이었다.)
12일에 대학교 마지막 시험이 남아있었기에 11일은 기말고사 공부를 하고 그 주에 해당하던 모든 약속을 취소하고.. 코딩테스트 공부에 매진했다.
최종 코딩테스트 준비 과정은 해당 글에서 확인할 수 있다.

최종 코딩테스트, 12월 16일

최종 코딩테스트날 눈이 펑펑 내리고 갑자기 한파가 시작된 날이었다. 마치 수능을 치러 가는 것 같았다. 잠실로 가는 버스를 타고 근처 스타벅스에서 음료를 사서 시간을 때웠다. 너무 긴장이 돼서… 아무것도 하지 않고 그냥 노래 들으면서 커피를 마셨다. 스타벅스에 사람이 굉장히 많았는데, 노트북 보는 사람이 많았다. 확실하진 않지만 나처럼 우테코 최종 코테 시험을 보러 온 사람들 같았다.

우테코 잠실 캠퍼스 사진1

카페에서 조금 시간을 보내다가 우테코 잠실 캠퍼스에 미리 갔다. 먼저 온 사람들이 생각보다 많았고, 복도에서 대기하다가 입실시간에 맞춰 신분증 확인을 진행한 후 시험장에 입실했다.

우테코 잠실 캠퍼스 사진2

신분증 확인 후, 배민 굿즈를 받았다. 작은 노트와 펜 2개, 스티커였다. 펜에 적혀있는 ‘어머, 펜이에요~’가 센스 넘친다고 생각했다.

우테코 잠실 캠퍼스 사진3

시험생들을 위해 간식과 물도 준비되어있었다. 안 먹을 줄 알았는데.. 시험 시간이 5시간이 되다보니 나도 모르게 긴장이 완전히 풀리면서 배가 고파져서.. 간식을 가져와서 먹었던 기억이 난다.

우테코 잠실 캠퍼스 사진4

약간 긴장은 됐으나 최대한 긴장을 풀려고 노력했다. 노래 듣고 음료 마시면서 릴렉스 하려고 했고 캠퍼스도 구경했다. (코치님들이 언제 올 수 있을지 모르니 맘껏 구경하라고 하셨다.)

우테코 잠실 캠퍼스 사진5

인터넷 연결로 인해 시험시간이 30분 늦춰져서 다시 긴장이 올라올뻔 했으나, 문제 해결 후 그냥 대기하는 시간이 주어지다보니 긴장이 완전히 풀렸다. 오죽했으면, 시험보면서 노래 듣는데 리듬에 맞춰서 몸을 움직였다..ㅎ; 그래서 덕분에 온전한 실력이 잘 나온 것 같다.

우테코 잠실 캠퍼스 사진6

시험 종료 1시간 전에 한가지 기능 구현 미완성과.. 에러로 인해.. 갑자기 긴장이 엄청 됐지만.. 나의 영원한 친구 Chat GPT 덕분에 에러를 잘 찾아서 해결할 수 있었다.. 기능 구현도 잘 완료했고!

시험을 치르며

OnCall 미션 기능 구현

5시간의 제한 시간동안 해당 문제를 테스트코드까지 완벽하게 작성하기에는 다소 시간이 부족했다. 난이도도 약간 있었다고 생각이 든다. 문제 설명이 굉장히 길고, 기능을 이해하는데도 시간이 좀 걸리는 문제였다고 생각이 든다. 그리고 개발자가 생각해야 할 요소가 다분히 존재하는 문제인 것 같다.

최종 코딩테스트: 개발자 비상근무(oncall) Repository

예제 테스트 실행 결과

그래도 나의 목표인 예제 테스트는 잘 실행을 완료할 수 있었다. 이것으로 굉장히 만족한다.

에러 해결

EmergencyShiftNumber 클래스를 실행하면 weekdays와 holidys의 값이 이상하게 변경되는 문제 (sort의 잘못된 사용)
이번 미션을 진행하면서 해결하는데 가장 오래 걸린 문제였다.

값 에러 이유
#validateListSameValue(weekdays, holidays)를 통해 두 배열의 입력된 값이 동일한지 확인한다. 이때, 동일한 값인지 빠르게 확인하고자 sort()를 활용하였다. weekdays와 holidays를 sort하여 정렬하면 두 배열의 값과 순서가 모두 동일하게 될 것이다. 따라서 sort를 사용하였다. 이게 에러의 원인이었다.
sort 할때 처음에 그냥 week.sort()로 했다. 이러면 안된다.. sort()를 사용하면 원본 배열에도 영향을 준다.
나의 코드는 const week = weekdays.sort(); 였는데, week에만 정렬되는 것이 아닌 weekdays에도 sort()가 적용되어 해당 클래스를 사용하고 난 후, weekdays를 출력하면 값이 변경됐던 것이다.

EmergencyShiftNumberContorller 코드 EmergencyShiftNumberContorller 코드

에러 해결
에러를 해결하는 방법은 구조분해할당을 하여 weekdays의 모든 값을 구조분해하여 새롭게 배열을 생성하고 그 배열을 정렬하면 된다.
const week = [...weekdays].sort();를 해야 원하는 결과로 잘 출력된다. 이렇게 하면 원본 배열인 weekdays에도 영향을 주지 않고 유효성검사를 할 수 있다!

EmergencyShiftNumber 클래스의 #validateListSameValue() EmergencyShiftNumber 에러 해결 코드

최종 코딩테스트 마친 소감

시험 메일에서 언급했던 것 처럼. 돌아가는 쓰레기를… 만든 것 같다.ㅎ
하지만, 일단 제한 시간이 주어진 이상. 어떻게든 돌아가게 기능을 구현하는 것이 중요하다고 생각한다. 그래서 기존에는 기능을 구현하면서 테스트코드도 바로 작성했었는데, 최종 코딩테스트에서도 이렇게 하면 시간이 매우 부족할 것으로 예상됐다. 그래서 테스트코드는 쿨하게 버리고. 일단은 기능 구현을 중점으로 두었다.
그리고 이 선택은 잘 한 선택이었다. 테스트코드도 작성하면서 기능을 구현했더라면 제 시간에 맞춰서 기능을 완성할 수 없었을 것이다.. 종료 30분전에 기능 구현을 완료했었고, 남은 시간에 how to solve와 테스트코드 하나를 작성하니.. 시간이 종료되었다!
선택과 집중을 잘 한 것 같다.

시험을 종료한 후에 느낌이 굉장히 좋았다. 그래서 N인 나는 집 가는 버스에서 행복회로를 오지게 돌리면서 갔다..
일단 전날부터 너무 걱정됐던 ‘5시간안에 기능 구현 완료’를 못해서 예제 테스트 실패하면 어쩌지? 예제 테스트만 성공시키자.를 목표로 잡았는데, 해당 목표를 이룰 수 있어서 너무 만족스러웠다.
기능 구현도 생각보다 잘 되었다. 비록 테스트코드는 거의 작성하지 못했고 how to solve도 잘 작성하지는 못한 것 같았지만, 이상하게 종료된 후에 기분이 굉장히 홀가분하고 합격할 것 같은 느낌이 확 들었다.

그래서 일까.. 결과 및 준비과정은…! 여기서.

DrawMap: 프로젝트를 마치며. 성장하는 개발자가 되자👩🏻‍💻

DrawMap

자전거 주행으로 그리는 관광 컨텐츠 개발/공유 서비스

드로맵 로고

내가 개발한 페이지


코스개발페이지

코스개발 페이지1 코스개발 페이지2

마이페이지

마이페이지 마이페이지 수정

프로젝트를 진행하며

타 파트와의 소통의 중요성

드로맵은 팀프로젝트로 진행했기 때문에, 다른 파트 팀원과의 소통또한 중요했다. 타 파트와 소통할 때 어려운점들을 느꼈는데 프로젝트가 종료하고 나서 이렇게 개선하면 될 것 같은 사항을 적어본다.

  • 상세히 물어보기

    잘 모르겠거나 이해가 안되는 것은 상세하게 물어보자.
    내가 말하는 것 혹은 다른 파트원이 말하는 내용들이 이해가 안 갈수도 있다. 내가 엄청난 관심을 가진 분야가 아니면 기존 지식으로 이해하는 것에 한계가 존재하더라. 따라서, 조그만한 내용도 이해가 안되면 자세히! 풀어서 설명해줄 수 있는지 물어볼 수 있는 용기가 필요하다.

    타 파트의 진행 상황을 상세하게 물어봐야 한다.
    매주 단체 회의를 진행했는데 회의 시간은 항상 30분을 넘기지 않았었다. 당시에는 회의가 빨리 끝나서 마냥 좋았었는데, 끝나고 보니 이 점을 개선해야 했다고 느껴졌다.
    단체 회의때 각 파트의 진행 사항을 이야기 하는데, 단순하게 ‘저희 파트는 ~ 했습니다.’하고 끝났다. 이렇게 간단하게 말하고 끝낼 것이 아니라 진행했던 결과까지 같이 확인하면서 구체적으로 뭘 했는지까지 설명해야 했다.

    예를 들자면, API 명세서를 작성했다고 치자. 그럼 작성한 명세서와 함께 이건 어떤 데이터를 뜻하고 값으로는 뭐가 들어올 수 있는지 등을 말이다..! 그렇다.. API 명세서를 이해하지 못해서 고생했었다.
    회의때, 명세서를 작성했다고 했을 때 같이 보면서 이야기했었더라면.. 명세서를 보고 상세히 물어봤더라면.. 라는 아쉬움이 많이 남는다.

  • 잦은 소통의 필요

    다른 파트와 소통을 자주, 많이 해야 한다.
    직접 느끼게 된 계기는 API 명세서였다. 해당 프로젝트는 ‘스웨거(Swagger)’를 사용하였는데, 처음에 이게 뭔지 몰라서 (이때 처음 들었다) 회의를 하면서 찾아본 기억이 난다.
    처음 듣고 사용하게 된 것이라 찾아보면서 사용하느라 애를 먹기도 했지만, 가장 큰 문제는 이게 아니었다.

    백엔드 측에서 작성해둔 데이터 명이 뭘 뜻하는지 알 수가 없다는 것이 가장 큰 문제였다. 어떤 것은 눈치껏 데이터 값을 보고 알 수 있었지만, 도저히 이해되지 않는 데이터들이 존재했다. 또한, 프론트에서 받으려는 데이터의 갯수와 종류가 API 명세서에 적혀있는 것과 달랐다.

    처음에 API를 명세서를 이해하느라 필요없는 시간을 많이 허비했다. 심지어 겨우 이해했다고 생각했지만, 작성한 의도와 다르게 이해를 해버려서 카카오로그인 토큰이 발급되지 않은 줄 알고 헛 고생을 했던 기억이 새록새록하다.

    이런 문제가 발생했을 때, 회의에서만 물어볼게 아니라 메세지라도 지속적으로 물어봤다면 시간을 낭비할 필요가 없었을 것이다.
    그렇게 하지 못했던 것이 프로젝트를 종료하고 나서 가장 아쉬웠던 것으로 기억된다.

같은 파트원과의 소통

‘드로맵’ 프로젝트를 진행하게 되면서 프론트엔드 팀장을 맡게 되었다. 프론트엔드 파트 회의 진행 및 의견 수렴, 일정 조정, 파트 분배 등을 일을 했다. 프로젝트가 종료된 후, 이렇게 팀장의 역할을 했었다면 더 좋았을 것 같은 점들을 적어본다.

  • 진행 상황 발표

    각자의 진행 상황은 상세히 발표하자.
    파트 회의를 진행하면서 각자 해와야 했던 일들을 같이 확인하면서 발표를 진행하지 않았던 것이 아쉬운 점으로 기억된다.

    회의 시작 시간 전에 깃허브에 push가 되어있는지 확인하고 회의에 들어갔었다. 그리고 회의때, 간단하게 ‘@@님 ~~하셨죠? 깃허브에 push를 안하셨는데 해주세요’ 정도만 하고 넘어갔었다. 이러면 안됐었다…!ㅜ
    깃허브에 올려있지 않으니, 정확히 했는지 안했는지는 해당 파트원의 말만 믿고 넘어갔었다.
    이렇게 말만으로 넘어갈 것이 아니라, 같이 해당 코드 혹은 결과물을 확인하면서 어떻게 구현했는지 꼭 같이 확인을 해야 했다.
    그래야 우리 파트의 진행 상황을 정확하게 파악할 수 있고, 정기 회의때 정확한 진척 상황을 PM에게 말할 수 있다.
    그러니 다음에는 꼭, 각자의 진행 상황을 발표하고 토의하는 시간을 가져야 겠다고 생각했다.

  • 코드 리뷰

    구현한 코드를 팀원들과 리뷰하자.
    나중에야 알게된 것인데, 코드 리뷰는 정말 중요하다. 이론적으로만 리뷰가 필요하다는 것은 알고 있었다. 하지만 이게 왜 필요한 것일지는 느끼지 못했다.
    이번 프로젝트를 진행하면서 왜 리뷰가 필요한지를 느꼈다.

    파트원들과 코드리뷰를 가져야, 다른 사람이 구현한 기능을 사용할 때 원활하게 활용할 수 있다.
    예를 들어 내가 select box를 구현했다. 이에 대한 props로 locataion과 title이 존재한다. 내가 이 props가 뭔지 설명하지 않으면, 다른 파트원이 해당 select box 컴포넌트를 사용할 때 뭘 뜻하는 건지 한번에 이해하기 어려울 것이다.
    해당 컴포넌트는 어떻게 사용하는지 코드리뷰를 하면서 설명했다면, 타 파트원이 구현을 하면서 해당 컴포넌트를 사용할 때 쉽게 이해하고 사용할 수 있을 것이다.

    또한, 코드리뷰를 통해 기능을 개선해 나갈 수 있다.
    본인이 아무리 뛰어난 코딩 실력을 가졌다고 해도, 부족한 점은 존재할 것이다. 내가 작성한 코드를 다른 팀원이 리뷰하면서 더 좋게 발전할 수 있는 사항을 찾아줄 수 있다. 또한, 내가 이상하게 혹은 잘 못 작성한 것들도 찾아 수정할 수 있을 것이다.
    항상 코딩을 하면서 느낀 것이지만, 내가 작성한 것은 잘못된 점을 찾기 어렵다. 그렇기에 제3자에게 리뷰를 받으면서 개선사항을 찾는 것이 중요하다고 생각한다.

    프론트엔드 팀장을 맡으면서 확실하게 짚고 넘어가거나 프로젝트의 성장을 위해 이끌어나가지 못한 것 같아서 아쉽다.
    위에 작성한 것처럼 했더라면, 일의 진행도 원활했을 것이고 코드리뷰를 통해 피드백을 받아 수정해나가면서 보다 완성도가 높은 프로젝트가 만들어질 수 있었을 것이라고 생각한다.

프로젝트를 종료하며

여러모로 아쉬움이 많이 남는 프로젝트다.
첫 시작부터 일정이 많이 밀린채로 시작했고, 종료 또한 완전한 완성이 아닌 상태에서 종료하게 되었다. 그래서 정말 많은 아쉬움이 남는 프로젝트인 것 같다.
처음으로 프로젝트의 프론트엔드 파트 팀장을 맡게 되면서 팀장의 역할을 제대로 하지 못한 것 같아, 같은 파트원들에게도 미안함이 든다. 더 잘 챙기고 이끌어 나갔더라면 더 좋은 결과물을 만들어 낼 수 있지 않았을까 생각이 든다.

그리고 무언가 불만사항이 있다면, 나는 그 불만사항을 해결하기 위해서 노력하였는가? 혹은 무조건 내가 다 수습하려고만 하지 않았는가?를 생각해야 할 것 같다.
내가 무조건 다 수습하는 것도 좋지 않고, 불만만 토로하고 해결을 위해 노력하지 않는 것도 좋지 않다는 것을 느꼈다.
혼자서 할 것이 아니라 이건 ‘팀’ 프로젝트니까 같이 해결해 나가고, 소통을 통해 같이 서로의 문제점을 개선해나가는 것이 중요한 것 같다.

여러모로 아쉬움은 많이 남은 프로젝트였지만, 해당 프로젝트를 진행하면서 React의 활용 능력이나 서버와의 통신, Kakao API를 활용하는 등의 능력이 많이 향상됐다는 것을 느낄 수 있는 프로젝트였다.
예전에 Kakao API를 연결한다고 애를 많이 먹었는데.. 이번에는 내가 생각한 것 보다 굉장히 빠르게 기능을 구현할 수 있었다.
나의 성장을 확인할 수 있었던 프로젝트였다.

다음번에는 좀 더 성장하여 이번에 아쉬웠던 점들을 개선하여 프로젝트를 진행하고 싶다. 성장하는 개발자가 되자.

우테코: 프리코스 2주차 미션 복기

모든 프리코스가 끝나고 이제야 작성하는 약간 늦은 2주차 프리코스 복기이다.
다 끝나고 진행해서 까먹은 개념도 존재할 것이고, 해당 복기로 인해 당시의 내 코드를 돌아볼 수 있기에 조금 늦게 작성하지만 안 적는 것 보단 낫다고 생각해서 지금이라도 작성해본다.
해당 글은 당시에 내가 작성했던 소감문을 바탕으로 작성했다.

2주차: 자동차 경주 Repository 2주차 프리코스 예제 테스트 성공 캡쳐

2주차 미션은 1주차 미션의 코드리뷰를 통해 새롭게 알게된 개념들을 적극 반영하여 구현하였다. 확실히 이전보다 코드를 읽는데 아주 약간은..! 나아진 듯 싶다.


리뷰받은 내용 반영

고차함수 사용하기

1주차 코드리뷰에서 고차함수를 사용해보는 것도 좋다는 피드백을 받았다. 그전에는 for이나 while을 통해 단순히 코드를 작성했었다. 코드리뷰를 통해 고차함수가 있다는 것을 알았고 for을 사용하는 것 보다 코드가 더 간단해질 수 있다는 것을 알게되었다. 그래서 이번 2주차에는 고차함수인 filter, map, forEach을 사용하여 기능을 구현했다.

  • filter를 사용하여 값 걸러내기

    자동차의 이름을 입력받을 때, 5글자 이상이거나 영어나 한글이 아니면 레이싱을 진행할 수 없도록 했다. 이때, 해당 조건에 맞는 값들만 걸러내기 위해서 filter을 사용했다.

    filter를 사용한 코드

  • map을 사용하여 입력받은 자동차 이름의 수만큼 배열에 값(0) 생성하기

    우승자를 찾기 위해 입력받은 자동차의 이름의 수만큼 0의 값이 존재하는 배열이 필요했다. 이때 map을 사용하여 입력받은 자동차의 값을 x로 하여 0의 값을 반환하도록 해서, 자동차의 수 만큼 0의 값을 갖고 있는 배열을 생성했다.

    map을 사용한 코드

  • forEach를 사용하여 배열 값 변경하기

    forEach을 사용하여 입력받은 자동차의 이름들을 이름 에서 이름 : 의 형태로 배열의 값을 변경했다.

    forEach를 사용한 코드1

    첫번째 인수(car)를 통해 각 자동차의 이름을 받고 두번째 인수(idx)를 통해 해당 값의 위치를 활용했다.

    또한 우승자의 이름을 담은 배열을 생성할 때 forEach를 사용했다. 자세한 설명은 뒤에서!

    forEach를 사용한 코드2

Set을 사용하여 중복 제거

1주차 코드리뷰 중 Set을 사용하여 중복을 제거하는 것을 추천하는 내용이 있었다. 그래서 사용하게 될 기회가 있어서 Set을 활용해보았다.
자동차 이름을 입력받을 때, 중복된 이름은 입력받지 않도록 처리해야 했다. 이때 자동차의 이름을 담은 배열의 길이와 Set을 사용하여 중복을 제거한 자동차 이름을 담은 배열의 길이를 비교하여 중복된 값이 존재하는지 확인했다.

Set을 사용한 코드

이 과정을 통해 추가로 알게된 것은 Set의 길이를 구할때는 length가 아니라 size라는 것을 알게되었다. length로 했는데 값이 안나와서.. 조콤 당황했다가 바로 찾아보고 size로 해야 한다는 것을 처음 알게 되었다.

매직넘버

코드리뷰를 통해 매직넘버의 개념을 처음 알게 되었다. 1주차에서는 boolean의 값을 1과 0 혹은 true로 단순히 명시하여 사용했었다.
매직넘버의 개념을 알게된 2주차에는 const FORWARD = true;와 같이 매직넘버를 적극 활용하여 기능을 구현했다. 사실 1주차에서 const를 사용하면 모두 upper 스네이크 케이스를 사용해야 하는 줄 알았다. 1주차 코드리뷰를 통해 그렇지 않다는 것을 알게 되었다.

매직넘버 사용한 코드

매직넘버(const)일때, 해당 값은 절대 변경되지 않을 것이기에 upper 스네이크 케이스를 사용하고 단순 const를 사용할 때에는 lower 카멜케이스를 사용하면 된다는 것을 확실하게 알 수 있었다.


2주차에 새롭게 적용한 개념

정규표현식

자동차 이름을 입력받을 때, 올바르게 입력했는지 확인하기 위해 정규표현식을 사용하였다.
이전에도 정규표현식은 알았지만 작성하는 것이 어렵다고 생각하여 사용하는 것을 회피했다. 하지만, 생각보다 그리 복잡한 것도 아니었고.. 우리에겐 챗GPT가 있기 때문에 이 친구한테 부탁하면 바로 알려준ㄷ.. ^^

정규표현식을 사용한 코드

indexOf(‘’)

우승자의 이름만을 출력하기 위해서 득점 현황만 담고있는 배열(forwardCount)에서 가장 높은 득점의 위치(MAX_COUNT)를 찾는다. 해당 위치를 가지고 이름을 담고있는 배열(carList)에서 이름만을 출력하도록(이름 배열에 전진 실행결과도 같이 존재함) indexOf를 활용했다.

indexOf를 사용한 코드

indexOf(' ')를 사용하여 첫 공백의 위치를 확인했다. carList에는 값이 soha : --------형태로 존재하는데, 첫 공백의 위치를 찾으면 0번째부터 해당 위치의-1 까지의 값만 출력하면 이름. 즉, soha만을 출력할 수 있다.

jest로 테스트코드 작성

이번 미션을 하면서 테스트 코드를 작성해보는 것은 처음이었다. 개념은 알고 있었지만 직접 기능을 구현한 코드에서 테스트 코드까지 작성하는 것은 처음이기에 좀 막막했다.
그래서 미션을 제출하는 순간에도 이렇게 테스트코드를 작성하는 것이 맞을 지 확신이 들지는 않았다. 실제로, 4주차까지 미션을 완료하고 나니.. 음 이렇게 테스트코드를 작성하는 것은 아니었다는 것을 알게되었다. 그래도 3주차부터 제대로된 테스트코드를 작성하는 방법을 알게되었다.

2주차 미션을 마치며

2주차는 1주차에 많은 역경을 견뎌서 그런지.. 1주차에 비해서 개인적인 스케줄이 많았음에도 좀 더 빨리 기능을 구현할 수 있었다. 2주차 미션을 진행하면서 개발 속도가 빨라진 것을 보고 일주일동안 정말 많은 성장을 이뤘다는 것을 몸소 느낄 수 있었다.
1주차때 애먹게 만들었던 행동도 하지 않기 위해 신경쓰고, 코드리뷰를 통해 받았던 피드백들을 적극 활용해보려고 노력했다. 이를 통해 이전보다 조금 더 코드의 가독성이 높아진 것 같다. 실제로 이때 들인 습관 덕분에 3,4주차 미션에도 잘 활용할 수 있었다.

학습 참고자료
자바스크립트 세트(Set) 완벽 가이드
Set() 함수를 이용한 중복제거 / Set 함수 객체 길이 구하기
idexOf: 문자열의 특정 문자 개수 세는 방법
코드의 매직 넘버 (Magic Number) 란 무엇일까?

우테코: 프리코스 4주차 미션 복기

드디어 마지막 4주차 프리코스 미션을 완료하게 되었다!!! 4주차는 1,2,3주차에 쌓아온 것들을 모두 종합하여 기능을 구현하는 느낌이었다. 기능구현 설명을 실제로 메일받는 것처럼 작성해서 진짜 개발자가 된 느낌..을 받을 수 있었다..ㅎ

이번 미션은 기능구현을 어떻게 해석하느냐도 중요했던 것 같고, 미션 제출을 fork가 아니라 개인 레포를 만들어서 private로 제한하는 등의 방식으로 진행했다. 여러모로 마지막을 이전과는 달리 새로운 방식으로 진행해서 색달랐다.

4주차: 크리스마스 프로모션 Repository 4주차 프리코스 미션 성공


새롭게 배운점

비즈니스 로직과 UI 로직 분리하기

해당 내용은 3,4주차의 가장 핵심이었던 목표였다고 생각한다.
1,2주차에서는 그냥 한 곳에 다 작성했다면, 3주차에서는 UI로직과 비즈니스 로직을 분리하는 것에만 그쳤고, 4주차에서는 비즈니스 로직을 더 쪼개려고 노력했다.

4주차 미션 폴더

하나의 파일/함수에 하나의 일만 책임질 수 있도록 적당한 선에서 로직들을 분리했고, 이 분리한 로직들을 하나의 파일에 다시 모아 하나의 기능을 하도록 했다.
이렇게 하다가 느낀것은 이게 MVC인건가? 라는 생각이 들었다. 이전에는 MVC가 머리로는 이해되지만.. 어떻게 하라는 건지 잘 모르겠었다. 그래서 적용해본적이 없었는데, 4주차 미션을 진행하면서 이렇게 로직을 분리하고 있는 것이 MVC인거구나를 깨달았다.

아직은 명확하게 Model과 Controller를 분리하는 기준은 잘 모르겠지만, 이번 미션을 통해 MVC는 이래서 사용하는 거구나를 깨닫게되었다.
그리고 분리한 로직들을 하나의 파일에 모아 하나의 기능을 하도록 만든 것이 모듈이라는 것을 깨달았다. 모듈을 이전에도 알고 있었지만, 정말 명확하게 알고 사용하는 용어..는 아니었는데, 이번 경험을 통해 내가 한 행동이 모듈을 만든 것이었다는 걸 알게되었다.

필드가 많으면 왜 안좋고 어떻게 개선할 수 있을까?

3주차 공통 피드백 내용에서 필드의 수를 줄이기 위해 노력해야한다는 내용이 있었다.
필드를 줄여야 한다고 했는데, 그렇다면 필드는 왜 사용하는 것일까? 라는 의문이 들었다. 그래서 필드를 사용하는 이유를 찾아보았다.

필드를 사용하는 이유는 다음과 같았다.

  • 코드가 명확해질 수 있다.
    클래스 내부에 어떤 속성이나 메서드가 속해있는지 명확하게 표현할 수 있기 때문이다.

  • 프로토타입에 직접 추가되지 않는다.
    그렇기에 인스턴스 메모리 사용을 최적화하고 상속관계를 유지하는데 도움을 준다.
  • this 바인딩을 할 필요가 없다.
    this는 constructor 내부나 메소드내에서만 유효하다. constructor 내부어서 this를 사용하는 이유는 생성자의 패러미터 이름과 동일하여 클래스 필드임을 명확하게 하기 위해서이다.
    그렇기에 constructor 내부가 아닌 class 몸체에서는 클래스 필드를 정의할 때 this 바인딩을 사용하지 않는다.
    하지만, 클래스 필드를 참조할때는 반드시 this를 붙여서 사용해야 한다.

  • 캡슐화를 유지할 수 있다.
    클래스 내부에 private한 속성을 생성할 수 있어서 외부에서 직접 접근하지 않도록 하여 캡슐화를 유지할 수 있다.

그렇다면 이런 장점이 있는데 왜 사용을 줄이라는 것일까?
필드를 사용하는 이유를 알고 나니 해당 피드백 문서에서 필드의 수를 줄이라는 것은 이런것이 아닐까 생각이 들었다.
불필요한 필드의 수를 줄이기 위해 노력할 것.
필드는 장점이 뛰어나기에 단순히 필드의 수를 줄이라는 말이 아닌 중복적으로, 굳이 사용하지 않아도 되는 필드의 수를 줄이라는 것이 아닐까?라고 생각이 들었다.

그래서 클래스를 사용할 때, 무분별하게 필드를 사용하는 것을 자제하기 위해 해당 클래스에서 정말 이 필드가 필요한 것인가? 꼭 private 해야 할까? 라는 의문을 가지며 코드를 작성했다.
해당 피드백 문서가 아니었다면 무분별하게 클래스에 private 필드를 사용했을 것이다. 해당 내용 덕분에 필드를 사용할때 정말 신중하게 생각하며 사용했다.

배열이 아닌 객체를 사용하기

이번 미션은 가지고 있어야 할 데이터가 많았기 때문에 이 데이터들을 보다 효율적으로 꺼내서 쓸 수 있도록 배열이 아닌 객체를 주로 사용했다.

기능 요구사항에 평일 이벤트로 ‘디저트’ 주문시 수량만큼 할인을 하는 요구사항이 존재했다. 이때 ‘디저트’ 종류의 메뉴를 따로 배열로 관리하는 것이 아닌, 메뉴판을 객체로 저장해두고 해당 메뉴판에서 디저트에 해당하는 메뉴만 뽑아 쓰는 것이 좋다고 생각했다.

MENU 객체

나중에 유지보수를 진행하게 될 경우, 뽑아내고자 하는 음식의 종류만 변경하면 되기 때문이다.

객체안의 객체 사용, 객체안의 배열 사용

객체를 사용하여 데이터를 저장하고자 할 때 떠오른 의문점이 있었다.
객체안에 객체를 사용하는 경우와 객체안에 배열을 사용하는 경우는 어떤 때 일까? 메뉴판 데이터를 생성하기 전에 좀 더 알맞는 데이터 구조를 만들고자 찾아보았다.

객체안에 객체를 사용하는 경우는 구조화된 데이터가 필요할때, 읽기 쉬운 코드가 필요할 때 주로 사용한다.
객체 안에 객체를 사용하면 데이터를 계층적으로 구조화할 수 있고, 이에 따라 코드가 읽고 이해하기 쉬워진다. 이러한 경우에 객체 안에 객체를 사용한다는 것을 알게 되었다.

객체안에 배열을 사용하는 경우는 순서가 중요한 데이터거나 동적 데이터일 때 주로 사용한다.
특정 순서로 진행되어야 한다거나 데이터를 쉽게 추가하거나 제거해야 하는, 동적으로 데이터를 다뤄야하는 경우에는 객체안에 배열을 사용하는 것이 더 좋을 수 있다는 것을 알게되었다.

그래서 나는 메뉴판 데이터를 생성할 때, 객체안에 배열을 사용했다. (음?)
key에는 메뉴명을 value는 배열을 사용하여 0번째에는 가격을 1번째에는 종류를 넣어, value에서 0번째 값을 꺼내면 무조건 가격만 나오도록 했다.

사실 객체안에 객체를 사용하는 것이 더 맞지 않을까? 생각하긴 했다.
객체안에 객체를 사용하는 것이 해당 메뉴의 가격과 종류를 명확하게 알 수 있어서 현재도 이것이 가장 좋은 방법일것이라고 생각한다.

그럼에도 객체안에 배열을 선택한 것은 value로 많은 값이 들어있지 않기 때문에 배열로 관리하는 것이 더 편할 것이라고 판단했다.
value의 값이 많이 존재했더라면 객체안에 객체가 훨씬 더 좋았을 것이라고 바로 판단했을 것이다. 하지만 해당 프로젝트에서는 value값으로 가격과 종류 2가지만 가지고 있기 때문에 객체대신 배열을 선택했다.

그래도 역시 장기적으로 보았을때는 객체안에 객체가 맞는 선택인것 같다..^^ 현재의 편안함을 위해 배열을 선택한..ㅎ..
그래서 어차피 복기니까! 만약 객체안의 객체로 메뉴를 만들었다면 어떻게 만들었을까? 생각이 들어서 간단하게 작성해봤다.

const MENU = {
  양송이수프: {
    price: 6000,
    type: '애피타이저',
  },
  타파스: {
    price: 5500,
    type: '애피타이저',
  },
  시저샐러드: {
    price: 8000,
    type: '애피타이저',
  },
  티본스테이크: {
    price: 55000,
    type: '메인',
  }
  ...
};

일단 메뉴의 이름을 Key로 하고 이에 대한 value로 객체를 넣어서, 해당 객체의 key로 가격과 종류를 넣었을 것 같다. 이러면 나중에 유지보수에도 편할 것 같다. 어차피 MENU 객체는 외부에서 수정할 일이 절대! 없으니까..
과거의 나는 무슨 정신으로 객체안에 배열을 쓴거지?

재입력받기, await 재귀함수가 아니라 return await

지난 3주차에서는 App 클래스 내부에서 await 재귀함수를 통해 정해진 입력형식이 아닐 경우 다시 입력받도록 했다.
이번 4주차에서는 입력받는 함수를 App.js가 아니라 Order 모듈을 생성하여 내부에서 재귀를 통해 재입력받기를 했다.

이때, 3주차와 같이 await 재귀함수를 사용하였는데 이렇게 되면 다시 입력받았던 값을 저장하지 못하고 undefined로 값이 변경되었다.
해당 오류를 수정하고자 챗GPT에게 물어본 결과.. await를 return으로 변경하기만 하면 되는 것이었다! return으로 변경하기 원하는 방향으로 잘 작동했다.

return을 사용하여 재입력받기 코드

3주차에서는 class 내부 함수로 생성했을 때는 await로 재호출하였지만 이번에는 Order이라는 함수를 새로운 파일에 생성하여 재호출을 진행하는 것이기 때문에 return을 사용해야 됐던 것이었다.
단순히 로직이 비슷하다고 해서 이전의 방식을 그대로 차용하는 것은 큰 위험이 될 수 있다는 것을 몸소 깨달았다.. 챗GPT 없었으면 하루종일 해당 에러를 잡고 있었을 생각을 하니..ㄷ

Object.freeze()?

Object.freeze()는 지난 3주차 미션의 다른 분들의 코드를 보면서 가장 많이 보았던 메서드였다.
이번에 해당 메서드를 처음 보았고, 대부분 상수를 만들때 사용하는 것을 보았다. 그래서 이 메서드를 정확히 알아보고 사용해보고자 찾아보았다.

해당 메서드는 객체를 얼릴때 사용하는 것으로 객체의 속성들을 수정할 수 없게 즉, 읽기 전용으로 만들어주는 메서드이다.
이 메서드를 활용하여 메뉴판 객체나 뱃지, 혜택 이름 리스트 등을 얼렸다. 해당 객체들을 외부에서 사용할 경우 변경되지 않는 데이터이기 때문에 Object.freeze()를 사용했다.

Object.freeze() 사용한 코드

객체를 얼리고 따로 파일을 생성하여 보관함으로, 반복되는 문구의 사용을 줄일 수 있어서 유지보수를 하는 것에 있어 큰 도움이 된다는 것을 알게되었다.

실수를 통해 배운점

객체의 길이를 알고 싶다면

객체에는 length를 바로 사용할 수 없다. 따라서 객체의 길이를 알고 싶다면 keys를 뽑아낸 배열에 length를 사용하는 방식으로 알 수 있다.

객체 길이 구하기

객체에 map함수 사용하기

map, reduce와 같은 함수는 배열에 사용하는 것이기 때문에 객체에는 바로 사용이 불가능하다. 따라서 위에 길이를 구한 방식과 동일하게 키, 값, 키-값 쌍의 형태로 배열을 출력하여 map함수를 사용하면 된다.

map함수를 객체에 사용하기

toThrow는 직접 던지면 안된다.

방문날짜 입력 테스트 실패

테스트코드를 작성할 때 toThrow를 사용했는데, 테스트 실패가 발생했다. 아무리 생각해도? 뭐가 이상한지 모르겠어서 영원한 친구 챗GPT에게 물어봤다.

toThrow 사용 에러 해결방법

음.. 그렇다! 함수를 인수로 받아 실행해야 하는데, 클래스를 직접 생성하는 코드를 전달해서 발생한 문제였다.

문제가 발생한 코드 방문날짜 입력 잘못된 테스트코드

따라서 함수를 인수를 받아 실행하도록 화살표 함수를 추가하여 테스트코드를 변경하였다.

문제를 해결한 코드 방문날짜 입력 올바른 테스트코드

어쩐지.. 다들 화살표함수를 추가하더니.. 다 이유가 있는 것이었다. 의문이 들때는 일단 실행해보고 왜 저렇게 사용하는지 알고 사용하도록 하자.

테스트코드 성공 방문날짜 입력 테스트 성공


프리코스를 마치며

이번 4주차까지 프리코스를 진행하면서 정말 많은 것을 배우고 얻고 느낄 수 있었다.
1주차때만 하더라도 포기할까 생각도 들었고 4주차까지 진행할 수 있을까 확신이 들지 않았다. 그런 내가 4주차까지 모든 미션을 예제 테스트 실행을 완벽히 하고 제출했다는 것이 믿기지가 않는다!!

불과 4주전까지만 해도 바닐라 자바스크립트로 기능을 구현해야 한다고 했을 때 정말 자신이 없었다. 클래스를 사용할 줄 몰랐고, 테스트코드를 직접 작성해본 적도 없으며, throw를 사용하여 예외를 던져본 적도 없었다. (과거의 나: throw가 뭐징?)
그러나 4주가 지난 지금, 라이브러리나 프레임워크 없이 기능 구현해라? 지금은 시간이 걸릴지라도 자신있게 완성은 할 수 있다고 말할 수 있는 사람이 되었다!

그리고 코딩 능력 말고 새롭게 얻은 것이 있다.
바로, 챗GPT 활용 능력. 이전에는 코딩하면서 사용한적이 손에 꼽을 정도로 없었는데, 이번 프리코스를 진행하면서 도저히 서칭만으로는.. 해결되지 않는… 문제가 많았기에 챗GPT를 적극 사용했다.
처음에는 물어봐도 뭔가 확실한 답을.. 얻을 수 없었는데, 4주동안 열심히 활용한 결과. 이제는 어느정도 원하는 답을 도출하기 위한 질문을 할 수 있게 되었다. 이제 챗GPT 없이는 못살앙… 내 영원한 코딩 친구💙

이 외에도, 문제 찾기 능력 (초보에서 중수는 된듯하다), 다른 사람 코드를 읽는 능력이 향상된 것 같다. 클래스 사용과 테스트코드 작성을 하는 방법을 도저히 감을 잡을 수가 없어서 다른 분들의 코드를 많이 봤었다. 덕분에 코드를 읽는 능력이 이전보다는 많이 향상된 느낌이랄까? 여러 파일과 폴더로 쪼개져있어도 이제는 코드를 보고 다음 파일을 따라가 읽는 능력이 향상됐다!
그리고 문제 찾기도.. 에러나는 곳을.. 정말.. 몇시간씩 찾았기에.. 안 늘수가 없는 것 같다.. 에러.. 이녀석.. 날 고통스럽게 했지만 얻는게 있었으니..! 봐준다(?)

이 4주는 몰랐던 것을 알고 배울 수 있는 시간이었고, 개발에 대한 두려움과 편견을 없애줬으며, 4주동안 꾸준히 미션을 진행한다는 명목으로 코딩을 하면서 개발에 대한 자신감과 꾸준히 공부해왔다는 자기만족감을 얻을 수 있는 시간이었다.
4주의 시간이 정말 아깝지 않은 시간이었고, 목요일 15시면 오던 메일이 오지 않는다는 것이 시원하면서도 그립다.

누군가에게 프리코스를 할까말까 고민된다면 나는 자신있게 도전해보라고 하고싶다!
프리코스는 우테코에 선발되지 않아도 많은 것을 배울 수 있는 기회니까.
한달동안 열심히 공부하며 성장했다는 것을 느낄 수 있는 기회니까!

학습 참고자료
객체에 해당 key값이 존재하는지 확인하는 방법
TIL | 객체 안의 객체 접근, 객체 안의 배열 접근
💙챗GPT💙

우테코: 프리코스 3주차 미션 복기

3주차 프리코스는 1,2주차 동안 활용해야겠다 생각했던 것들을 모두 활용할 수 있었던 미션이었다. 해당 미션부터는 클래스 활용과 테스트코드 작성이 정말 필수적이었기 때문이다.

그래서 기능 구현을 하기 전, 하루를 오로지 공부만 해야 했다. 이전에는 클래스를 사용해본적이 없기 때문이다. 학습하면서 어렵다고 느껴지고 이해가 완벽히 되는 느낌은 아니었지만, 미션 기능구현을 하면서 학습했던 개념들을 가지고 직접 코드를 작성하니 이해가 훨씬 잘 되었다.

프리코스를 마친 현재에도 해당 내용들이 잊혀지지 않고 진짜 ‘나의 지식’이 되었다는 느낌이 든다.

3주차: 로또 Repository 3주차 프리코스 미션 완료 캡쳐


새롭게 학습하고 적용한 점

reduce

2주차에 고차함수를 많이 활용하여 기능을 구현했지만 reduce는 사용하지 않았다. 이번 미션에는 마침 reduce를 사용하기 딱 좋을 기능이 있어서 활용해보았다.
reduce는 다른 고차함수랑 다르게 반환값이 배열이 아니라 값 하나이다. 그래서 수익률을 계산할때(ReturnOnInvestment.js) 해당하는 값 하나만 얻으면 됐기에 reduce를 활용하여 당첨금액을 구했다.

reduce를 활용한 코드

이전에는 reduce는 사용하기 어렵고 이해하기 힘들다!라는 느낌이 너무 강해서 사용하기 꺼려졌었다. 하지만 이번에 고차함수를 마스터해보고자 남은 하나인 reduce도 3주차에 사용하게 되었는데, 막상 사용해보니 전혀 어려운 개념도 아니고 활용하기 까다롭지도 않았다. 오히려 필요한 값만 딱 return하니 굉장히 편한 함수였다..!
그간 내가 편견을 가지고 있었다는 것을 알게 되어서, 앞으로도 이런 편견을 가지고 있던 것들을 하나씩 부숴봐야겠다 생각이 들었다.

Class

1,2주차 프리코스를 하면서 기본적으로 주는 App.js파일이 class App으로 시작하는데, class를 활용해야 겠다~ 생각만 하고 개념만 찾아봤지 직접 사용하지는 못했었다.
하지만 이번 3주차는 정말 class를 사용해야 했기 때문에 JAVASCRIPT.INFO를 정독하면서 학습했다. 해당 문서를 읽을때 완벽히 이해가 된다거나 어떻게 활용을 해야겠다 라는 느낌이 오지 않았었지만, 일단 개념을 머리에 넣어두고 기능 구현을 시작했다.

기능을 구현하면서 작성되어있는 Lotto.js 파일에서 클래스를 어떻게 활용하고 있는지, LottoTest.js 파일에서 요구하는 작동 범위가 뭔지를 먼저 파악했다. 해당 파일에서 사용한 class 사용 방식과 class를 적극 활용하신 다른 분의 2주차 코드를 참고하면서 코드를 작성하니 어느새 class를 나름 사용할 수 있는 수준이 되었다.

아직은 조금 부족하지만 클래스를 처음으로 활용한 코드! 클래스를 활용한 코드

처음에는 prefix, 클래스 필드가 어떤 건지 전혀 몰랐고, 1주차 코드리뷰에서 validate를 활용하여 예외 처리를 하는게 어떻냐는 의견을 받았을 때 validate를 뭘 어떻게 쓰라는 건지, 유효성 검사라는 서칭 내용만 뜨고 js에서 활용하는건 어떻게 하는지 전혀 몰랐었다.
이런 상태였지만 이번 3주차 프리코스를 마치니 이제는 prefix가 뭘 말하고 클래스 필드는 뭔지, validate를 어떻게 사용해야 할지를 알게되었다!

도메인 로직

도메인 로직에 단위 테스트를 구현해야 한다라는 프로그래밍 요구사항이 존재했는데, 단위 테스트는 들어봤어도 도메인 로직은 이번에 처음 들었다. 그래서 도메인 로직이 뭔지 검색했다.

내가 이해한 도메인 로직이란! 프로그램이 돌아가는데 중요한 역할을 수행하는, 이 프로그램에서 A라는 기능이 빠지면 제대로 프로그램이 돌아가지 않는다!라면 A는 도메인 로직이다 라고 이해했다. 또한 도메인 로직은 비지니스 로직과 동일한 용어라는 것도 알게되었다. (제대로 이해한거 맞겠지?!)

도메인 로직이 뭔지 알게되니 도메인 로직에 단위 테스트를 구현하라는 요구사항은 프로그램이 돌아가는데 중요한 역할을 하는 코드가 잘 실행되는지 테스트하라!는 말이라는 걸 알게되었다.

jest 테스트코드 작성

위의 도메인 로직 개념을 학습한 후, 테스트 코드를 작성하려고 하니 어떤 파일을 테스트 해야할지 단번에 알 수 있었다. (이것이 바로 학습의 힘. 아는 만큼 보인다.)
2주차 미션을 진행할 때는 전혀 감을 잡을 수 없어 얼렁뚱땅 테스트 코드를 작성했었던 것에 비해 엄청난 발전이었다.

2주차까지는 테스트 코드를 어떻게 작성해야 할지 머리는 이해했지만 가슴은 이해하지 못해 잘 작성하지 못했다. 이런 상태였지만 3주차는 테스트코드를 작성하는 것도 매우 중요한 사항이었기 때문에 어떻게든 가슴도 테스트코드 작성 방식을 이해하고자 LottoTest.js 파일과 ApplicationTest.js 파일의 코드를 정말 하나하나 뜯어가며 이해하려 했다.

생각보다 쉬웠던 테스트코드 작성 테스트 코드

이로인해 예외 테스트와 원하는 결과가 잘 나오는지 기능 테스트 코드를 작성할 수 있었다. 이번에 테스트 코드를 직접 작성하면서 느낀것은 생각보다 테스트 코드 작성하는 것은 별거 없었다.. 그냥 내가 무서워하고 있었구나를 깨달았다.

테스트코드 실행 결과

테스트코드 실행 결과


실수했던 점

예외 반환 문구랑 기능테스트 문구에서 테스트 실패

예외 반환시 [ERROR]가 잘 포함되어 출력되는데 테스트 실패가 되어서 무슨 문제일까 엄청 찾았다. 문제는.. 제공하는 Console 사용안하고 그냥 console.log로 error를 출력하고 있어서 테스트 실패가 됐던것이었다. (진짜 바보냐..ㅠ)

기능테스트 문구(ApplicationTest.js)에서도 테스트 실패가 발생했었는데, PrintValue 클래스에 작성한 출력 문구에 띄어쓰기를 하나 더 해서.. 테스트 실패가 됐던 것이었다.^^;

위와 같은 실수를 통해 작은 실수가 1시간 그 이상을 허비하게 되니 코드를 작성할 때 신중하게 작성해야겠다는 것을 뼈저리게.. 배울 수 있었다. (진짜 신경써서 한줄 한줄 작성하자.)


마치며

3주차는 1,2주차에 가볍게 넘어갔던 개념들을 적극 활용해야 했었다. class와 jest 테스트코드 작성은 이번 3주에 프로그래밍 요구사항으로 명확히 주지 않았더라면 사용하는 방법을 아직도 잘 몰랐을 것이고 어렵다는 편견을 가지고 있었을 것이다.
하지만 3주차 미션을 통해 편견을 부술 수 있었고 이제는 온전히 나의 지식이 되었다. (진짜 뿌듯하다…!!!) 앞으로도 학습에 편견을 가지지 말고 도전하려고 노력할 것이다. 지금 당장 떠오르는 건 무서워서(?) 미뤄뒀던 Redux 사용하기이다. 이번 프로젝트 리팩토링때 사용해보고자 한다!

학습 참고자료
javascript: Array.reduce() 사용 방법 정리
자바스크립트 고차 함수(Higher-Order Function) 이해하기
class(클래스)에 대해 알아보자
JAVASCRIPT.INFO / CLASS
자바스크립트 클래스 필드와 이벤트 핸들러
프로토타입과 클래스
도메인 로직이 뭐지 🧐
jest로 테스트 작성하기
TDD 시작하기 (Unit Test, Jest)
테스트 코드로 JS 의 기능 및 로직 점검하기