목표와 회고

우테코 프론트엔드 5기 - 최종 코딩 테스트 후기

Creative_Lee 2022. 12. 21. 00:38

12월 17일 토요일, 최종 코딩 테스트를 치렀다.
이번 후기에서는 프리코스 종료부터 시험 이후의 복기까지의 과정과 
우테코 지원 과정을 최종적으로 마치며 드는 생각을 정리해 보려고 한다.

📆 1차 합격자 발표까지 주어진  3주

프리코스 4주 차를 마치고, 1차 합격자 발표까지는 3주 정도의 시간이 있었는데,
프리코스 종료 안내 메일에서는 2~4주 차 미션을 다시 구현해 보길 권했다.
매주 미션을 진행하면서도 스스로 부족함을 느낀 부분이 많았고,
제출했던 미션 코드를 보면서 경악을 했던 기억도 있던 터라 자체적으로 프리코스를 연장해서 진행했다.


🚴‍♀️ 기존 미션 복습

프리코스 종료 이후 바로 숫자 야구, 로또, 다리 건너기 미션을 복습했다.

복습을 하면서, 이전 제출 코드와는 확연히 비교되는 코드를 작성할 수 있었다.

물론 이미 한 번씩 구현해 본 기능들이라 익숙하기도 했지만, 이를 감안하더라도 분명한 발전이 있었다.

간단히 정리하자면 다음과 같다.


새로운 클래스로 기능을 나누고자 할 때, 분리의 기준이 생겼다.

분리를 통해 어떤 필드 변수를 생성하게 될지, 분리로 인한 이점과 단점은 어떤 것일지 생각하고 분리할 수 있게 되었다.

기존에 비해 생각할 시간이 더 필요해졌는데, 이전까지는 너무 가볍게 생각하며 분리한 게 아닌가 싶다. 

밑줄 친 필드는 모두 같은 데이터이다.

2주 차 미션 제출 코드를 보면 기준 없는 클래스 분리의 결과가 그대로 나타난다. 
각 클래스에 같은 데이터인 필드가 3개나 중복되어 존재한다. 물론 중복되어 존재할 이유가 없다.
이제는 더 이상 이런 코드를 작성하지 않을 것이다.

 


테스트에 대한 생각을 하며 기능 코드 작성을 할 수 있게 되었다.

제어할 수 없는 코드가 무엇인지 구분할 수 있게 되었고,
이를 인지해서 미리 도메인 로직에서 분리할 수 있도록 코드를 작성하는 능력이 생겼다.

해당 코드를 도메인 로직이 있는 클래스에서 사용하게 되었을 때, 테스트가 어려워진다는 사실을 4주 차에서 경험했기 때문이다.
또한 '좋은 코드란 무엇인가?'에 대해 테스트를 관점으로 생각할 수 있는 능력도 생겼다.

4주 차 제출 코드

처음엔 제어할 수 없는 코드의 개념을 몰랐기에 흐름이 자연스럽다고 생각하면 그대로 작성했었다.

개념을 알고 난 후에는 코드의 문제점을 파악하여 리팩토링할 수 있게 되었다.

최종적으로 현재는, 처음부터 충분한 생각을 통해 제어할 수 없는 코드를 도메인 로직에서 분리할 수 있다.

물론 아직 미션과 같은 콘솔 미니게임 형식 외의 코드에서 해당 상황을 접한 적은 없지만,

이런 부분들도 고려해야 한다는 것을 인지하게 된 것만으로도 큰 발전이라고 생각한다.


🚴‍♀️ 커스텀 미션 만들어 풀어보기!

미션 복습 이후에는 무기 강화 게임 커스텀 미션을 만들어 커뮤니티에 공유하고, 직접 풀어보기도 했다.

 

만약 최종 테스트 기회가 주어진다면 새로운 미션을 마주해야 했기 때문에

과연 새로운 미션에서도 학습한 내용을 녹여낼 수 있을지 테스트해보고 싶었기 때문이다.

 

전체적인 틀은 4주 차 미션을 바탕으로 잡았고, 테스트 코드를 비롯한 조건을 변형하여 미션을 만들었다. 

이후 완성된 커스텀 미션을 풀어보고 스터디원과 코드 리뷰하는 시간을 가졌는데,
프리코스에서 학습한 내용을 바탕으로 좋은 피드백을 주고받을 수 있었다.

 

또한 해당 미션을 우테코 지원자 커뮤니티에도 공유했다.

기분이 이상하더이다...
하하...ㅎ

그 결과... 인생 처음으로 누군가 내 저장소를 fork 하는 경험을 할 수 있었고,

미션의 완성도는 낮았겠지만, 지원자 동료들에게 작게나마 도움이 된 것 같아 뿌듯했다.

 가져가서 풀어주신 분들께 감사하다는 말씀을 전합니다!👊


🤞 1차 심사 발표 결과 합격!!

그렇게 3주가 흘러 합격자 발표 당일 오후...

프리코스를 후회 없이 마쳤기 때문에 덤덤하면서도, 기대 반 걱정 반으로 메일을 확인했다.

감격...

 

결과는 1차 합격... 메일 확인하면서 '됐다!' 하며 크게 소리 질렀던 게 기억난다.


🤔 오프라인 테스트... 5시간의 시간 제한...

한 5분쯤 1차 합격의 기쁨을 누렸을까... 갑자기 엄청나게 긴장이 되기 시작했다.

최종 코딩 테스트는 오프라인 테스트였고, 5시간이라는 한정된 시간 동안 최종 미션을 구현해야 했다.

자랑은 아니지만... 사실 나는 실력에 대해 평가를 받은 경험이 없었다...
(현재는 '우테코 오프라인 최종 테스트' 라는 경험이 생겼다😀)

흔하다면 흔한 온라인 코딩 테스트 응시 경험도 없었고,
프로그래밍 공부를 시작하기 전에
근무했던 직장들도 면접 외에  '테스트'의 개념은 없는 회사였다...


👊 최종 코딩 테스트 까지... 단 3일

발표 당일인 수요일부터 최종 테스트 날인 토요일까지

수, 목, 금  딱 3일이 남았었다.

당장 내가 해야 할 것은 무엇인가 생각해 봤고, 시간 내에 과제를 구현하는 연습이라고 생각했다.

 

사실 프리코스 과정에서 스스로 구현 속도가 느리다는 것을 어림 짐작으로 느끼고 있었다.

아침 9시부터 새벽까지 매일 구현했는데도 막상 구현한 것은  얼마 되지 않는 상황이 여러 번 있었다. 대부분 가까스로 끝냈던 것 같다.

때문에 남은 3일을 구현 연습에 모두 사용하기로 했다.


📝 기능 구현 목록 작성 연습

나는 구현 과제의 시작이었던 2주 차 미션에서 기능 구현 목록 작성에만 하루 이상이 걸렸었다.

2주 차 공통 피드백

위 2주 차 공통 피드백을 통해 첫 작성 시 내용을 간소화하고자 했고, 구현하며 업데이트하는 식으로 개선했었다.

그럼에도 목록 작성에 꽤나 많은 시간을 소모했다고 생각했기에, 기능 구현 목록 작성을 따로 연습했다.

2~4주 차 미션부터 커스텀 미션까지 구현 목록만 쭉 써보면서 시간을 최소한으로 사용하려고 했다.

 

연습을 하면서 느꼈던 점은 애플리케이션의 전체적인 흐름을 이해하는 것이 제일 중요하다는 점이다.

흐름을 충분히 잘 이해했다면, 세부적인 조건과 제약사항은 그때그때 녹여낼 수 있다고 생각했다.


💫 커스텀 미션 모의 고사 결과...

최종 테스트 하루 전 금요일에는 스터디원이 만들어 공유해 준 커스텀 문제를 받아 1시부터 6시까지 모의고사를 진행해 보았다.

실제 환경과 비슷하면 좋지 않을까 싶어 근처 도서관 노트북 코너에서 진행했다.

 

결과는 좋지 않았다. 2/5 정도만 구현할 수 있었고 시간이 한참 부족했다.

스스로 복기해 보니 대부분의 시간을 클래스 분리, 특정 기능 메서드의 위치 고민, 파일 분리, 변수명 고민에 사용하고 있었다.

 

평상시에 프로그래밍을 공부하면서 시간의 제약을 둘 일은 없었고, 그나마 촉박했던 것은 친구를 위한 개인 프로젝트였는데, 
이 역시도 강제성이 있던 것은 아니었기 때문에 스스로 시간 조절을 할 수 있었다.

시간의 제약이라고는 취업하기 전까지 나이를 먹어 가는 것 말고는 없었던 나로서는
어쩌면 당연한 결과일 수도 있겠다며 스스로 위로했다.

 

그리고 '조금 더 과감하게, 어떻게든 구현해 봐야겠다.' 생각하며 마인드 컨트롤을 하고 잤던 게 기억난다.


😵 대망의 최종 코딩 테스트

아침부터 눈이 펑펑 오는 바람에 예매해둔 시외버스 티켓을 취소하고 지하철로 잠실에 도착했다.

간단히 식사를 마치고 생리현상도 미리 해결한 뒤 건물에 입성했다.

고마웠던 스터디원분들에게 하나씩 드릴 겸 나도 하나 마시려고 1층 약국에서 박카스도 한 박스 샀다.

시험장에 들어가고 나서부터 긴장이 시작되었다.
몇몇 스터디원분들을 만나 가볍게 대화하면서 화이팅도 하고, 자리 양옆 분들과도 괜히 막 인사 주고받고 그랬었다. 

그럼에도 좀처럼 긴장이 사그라들지 않았다.  

 

그러던 중 시험 시작 전 안내 사항 메일을 먼저 받았다. 


시험 시작 전 안내 메일


전날 밤에 했던 구현 시간에 대한 고민과 함께 어떻게든 구현해 보자며 마인드 컨트롤했던 것이 생각나는 대목이었다.

그렇게 '보여지는 것에 신경 쓰지 않고, 돌아가는 쓰레기를 완성해 보자!' 다짐하며 긴장을 조금 덜어낸 뒤 시험을 시작했다.


💫 실전 경험의 중요성을 느끼다.

제목 그대로다.
복기해 보자면, 정말 마지막 2시간 정도는 무아지경으로 코딩하지 않았나 싶다..

 

시작은 좋았다.
연습했던 덕분에 기능 구현 목록 작성과 애플리케이션 파악은 대략 15분 정도 만에 해결할 수 있었다. 
초반부터 중반까지는 나쁘지 않은 페이스로 적당한? 쓰레기 코드를 써 내려가면서 기능을 구현했다.

이때까지만 해도 적당히 시간을 남겨서 반드시 코드 리팩토링을 해야겠다고 생각하기도 했다. (그저 꿈이었다..)

이 시점에 긴장도 거의 다 풀렸던 것 같다.

 

하지만 시간이 흐를수록 사소한 에러 하나에도 멘탈이 정말 많이 흔들렸고,

압박 속에서 기능 에러에 유연하게 대처하지 못했다.
특히 애플리케이션의 마지막 2개의 기능이었던 메뉴 추천 기능, 최종 추천 결과 출력 기능은 정말 앞만 보고 달렸다.

 

그렇게 종료시간 약 50분 정도를 남겨놓고 기능을 전부 구현했지만, 테스트 케이스에서 에러가 발생했다.

하필 문제가 발생한 코드는 앞만 보고 내달렸던 메뉴 추천 기능. 정신없이 디버깅하면서 이유를 찾고자 했다. 

남은 시간 모두를 디버깅에 쏟아부었고, 의심 가는 부분을 찾긴 했지만 끝내 에러를  잡지 못한 체 제출했다.

제출 소감문은 정말 점 하나 찍어 냈다.


시험이 종료되고 한동안 자리를 떠나지 못했다.
돌아가는 쓰레기를 만들고자 함이 목표였는데, 돌아가지도 않는 쓰레기를 만들었다는 생각을 했던 것 같다.

왜 찾지 못했을까... 이유가 뭐였을까... 그렇게 한 30분 정도 생각에 잠겼던 것 같다. 

고민 끝에 시간을 우선시 한 나머지, 뒤가 없는 코딩을 했기 때문이라고 결론지었고 짐을 쌌다.

뒤를 보니 코치님들이 모두 기다리고 계셨다... 시험 장소 정리를 하려고 하신 것 같다.

토요일이라 빨리 퇴근하고 싶으셨을 텐데 정리해야 한다는 말 한마디 없이 그냥 기다려주고 있던 코치분들께 너무 감사하고 죄송하다.


시험장 건물을 나와서는 조금 멍한 상태로 주변을 정처 없이 걸어 다녔다...
여기저기 걷다가 추워서 지하철역에 들어갔는데, 그때 정신을 딱 차렸다.
인생에서 이제 한 번 경험한 건데 처음부터 잘 할 순 없다고 위로했고, 털어버렸다.😅


🔥 끝나지 않은 에러 디버깅

기분은 나아졌으나 끝내지 못한 숙제가 남아있었다. 아직 에러를 잡지 못했다.
집으로 돌아오는 지하철에서도 원인을 찾지 못해서 집에 도착하자마자 다시 코드를 열었고,

그렇게 며칠을 하나씩 역으로 거슬러 올라가다 보니 원인을 찾을 수 있었다.

에러의 원인은 생각보다 복잡하게 연쇄적으로 얽혀있었다.


💫  원인 1. 테스트 케이스가 내포하고 있는 의미를 파악하지 못함.

테스트 코드의 입력값을 직접 입력하여 테스트할 때에는 버그 없이 잘 동작하는데,
테스트를 돌리면 에러가 발생한 이유는!

테스트 코드가 내포하는 의미의 구현 코드와 내가 구현한 코드가 일치하지 않았기 때문이다.

mock함수는 1~9 값이 들어있는 배열을 사용한다.

위 코드는 제공된 테스트 코드의 일부분이다.

여기서 sequenced 함수는 shuffle 함수를 mocking할 때 사용되는데, 
 shuffle 함수에게 전달되는 인자 배열의 값을 1~9로 매핑하는 역할을 한다.

 

내가 구현한 실제 코드 - idx 배열은 0~8 값이 들어있다.

하지만 내가 구현한 코드는
배열의 값을 0~8로 매핑한 뒤 shuffle 함수에게 전달한다.

 

1~9 배열, 0~8 배열
이 둘의 차이가 바로 에러의 첫 번째 원인이었다.


 

0-8 값을 가진 배열을 넘기는 내 코드의 경우,
shuffle 함수는 다음의 순서대로 값을 return 하게 된다. 

그 과정에서 mockQuestion 함수로 입력된 제임스의 못 먹는 메뉴인 떡볶이가 선택되어버리고,
못 먹는 메뉴 추천 시 새로운 메뉴를 다시 추천하도록 구현되어 있기 때문에, 
제임스의 첫 번째 메뉴 선택에 총 2번의 shuffle 함수 return value를 사용하게 된다.

 

최종적으로는 마지막 메뉴 추천을 받지 못한 상태이므로,  메뉴 추천 로직은 한 번 더 실행되는데
이때 더 이상 mocking된 shuffle 함수 return값이 없으므로 리턴값은 undefined가 된다.

 

(추가적으로 6번째 mock return value처럼 '9'가 0번 idx 값으로 셔플 된 경우,
menu의 9번 idx는 없으므로 undefined가 메뉴로 추천되는 경우도 발생한다.)

shuffle 함수의 return값이 undefined 이므로 당연한 결과이다.

undefined의 0번 idx 값을 읽으려 하니 당연하게도 에러가 발생한 것이다.


🧐  해결 방법

추가된 코드

테스트 케이스의 shuffle mock함수 구현 코드의 형태로
작성한 구현 코드를 수정하여 해결 할 수 있었다.


💫 원인 2. 테스트 케이스가 요구사항과 일치하지 않음.

여전히 남아있는 문제

이후 테스트를 다시 돌려보니, undefined 에러는 해결되었지만 출력 형태가 달라 테스트는 실패하게 되는데
이 부분에서 2번째 원인을 파악할 수 있었다.

바로 테스트 케이스가 요구사항과 일치하지 않는다는 것이다.


구현 요구 사항

요구사항은 [카테고리 추천 => 1번 코치 메뉴 추천 => 2번 코치 메뉴 추천] 의 순서로 구현을 요구한다.

 

테스트 코드
테스트 코드가 원하는 결과

하지만 테스트 코드는 그렇지 않다.
테스트 케이스는
[카테고리 전부 추천 => 1번 코치 메뉴 전부 추천 => 2번 코치 메뉴 전부 추천] 의 순서로 구현을 요구한다.

 

실제로는 번갈아가며 메뉴가 정해진다.
요구사항대로 구현했을 경우의 순서

요구 사항대로 코드를 구현할 경우 mockShuffles 함수는 위에서부터 순차적으로 각 코치의 메뉴를 추천하므로

테스트를 통과할 수 없다.


🧐  해결 방법

테스트 코드 수정 시 통과 가능하다

테스트 케이스의 mockShuffles 함수 내 코드를 순서에 맞게 수정하거나, 

각 코치의 일주일 치 메뉴를 일괄 추천 하도록 구현 코드를 변경해야 한다.


📔 시험이 아닌 또 다른 교육

- 최종 테스트 안내 메일 -

코드의 에러를 수정하는 과정에서 여러 가지 생각을 하게 됐다.🤔

 

실제로 최종 테스트 진행 중에 메뉴 추천 로직을 구현하면서,

주어진 테스트 코드와 같이 '일괄 추천으로 구현하는 것이 코드 맥락을 이해하기 쉽지 않을까?' 같은 생각을 했었다.
실제로 그게 더 구현하기도 쉬웠고, 코드도 깔끔하게 정리할 수 있었다.

무엇보다도 일괄 추천으로 구현해도 최종 구현 후 기능의 동작은 똑같았기 때문이다.

(테스트 코드를 명확하게 파악하고 한 생각은 아니었다.)

하지만 이내 '요구사항은 요구사항이니 지켜야 한다' 생각하여 구현을 이어갔었다.


하지만 과연 어떤 것이 옳은 선택일까?

만약 코딩 테스트가 아니었다면, 업무 중 이런 상황이 발생했다면 나는 어떤 선택을 해야 할까?


✨ 우테코 지원과정을 마치면서...

우테코와 함께한 약 3개월간의 과정이 드디어 끝이 났다.

첫 지원, 자소서 작성부터 시작해서 운 좋게 얻게 된 최종 코딩 테스트까지...

지원할 때만 해도 '벌써 10월이네.. 시간 빠르다...' 생각했는데 어느덧 크리스마스가 눈앞이다.

 

머리를 싸매고 좌절한 적도 있었고, 약점이라고 생각한 부분을 극복하며 울컥한 적도 있었고, 

끝까지 해내는 나 자신을 보며 자신감을 얻기도 했었다.

 

이러나저러나 드는 생각은 지원하길 정말 잘했다는 생각이다.

누구라도 지원을 망설이는 사람이 있다면 고민은 넣어두고 얼른 자소서 작성하길 바란다.

 

너무 나도 많은 걸 배웠고, 앞으로 어떻게 나아가야 하는지 방향을 잡을 수 있어 행복했다.

 

정말 대단히 감사하다.