테스트 전 작성한 회고
시작하며
우선, 이 글은 최종 테스트 전날 적어둔 글임을 미리 밝힌다. 최종 테스트의 소감인데, 전날 적는 게 이상할 수 있지만, 최종 테스트가 새로운 학습이라면 1차 발표가 나고 최종 테스트를 보기까지의 5일 역시 그 학습의 일환이었다 생각해서 일주일의 소감을 적어본다. 이번 일주일 간은 프리코스의 한 달간 경험한 것과는 또다른 경험을 했기 때문이다.
보조 장치를 떼었다: 글로 작성하던 스토리텔링식 설계 기법을 머릿속으로 빠르게 회전하다
최종 코딩테스트를 준비하며, 한 가지 큰 변화를 가졌다. 바로, 프리코스 기간 내내 작성하던 스토리텔링식 설계를 간단한 플로우 작성으로 대체한 것이다. 사실, 처음엔 좀 두려웠다.
4발 자전거의 보조 바퀴처럼 달고 다니던 설계법을 시간 감축을 위해 과감히 버려야 했다. 거의 6개 정도의 이전 기수 문제들을 찾아 풀어보았는데, 처음엔 스토리텔링식 설계를 못 놓아서 시간이 한 두시간 씩 오버 됐었다. 물론 설계만이 문제가 아니라, 구현 도중 리팩토링을 못 놓는 문제도 있었다. 이에 대해선 후에 서술하겠다.
프리코스 4주간 내가 했던 스토리텔링식 설계의 목적은 결국 플로우를 보다 상세하게 작성해 기능 구현 목록을 쉽게 작성하기 위함이었다. 바꿔 말하면, 스토리텔링식 설계가 익숙해져서 어느 순간 본능적으로 머릿속에서 이가 이루어진다면 훨씬 적은 플로우 작성만으로도 이전과 동일한 퀄리티의 기능 구현 목록을 작성할 수 있단 거다.
그리고 이를 이루어냈다. 이루어냈다 하면 거창할 수도 있지만, 의식적으로 연습하다보니 되었다. 일주일이란 시간동안 절대 시간 내에 못 풀 거 같던 문제를 이젠 풀어내는 내 모습을 보며 성장했다 느꼈고 보람찼다. 그리고 이 경험은 개발자로서 성장의 쾌감을 영위하는 데에 도움이 될 것이다.
물론 간절할 수록 긴장을 많이 하는 성격이라, 실제 시험에서도 연습했던 것만큼 잘 풀어 내길 간절히 빌고 있다. 준비한 걸 100% 쏟아내고 올 수 있으면 좋겠다. 덧붙이자면, 사실 살면서 이렇게까지 긴장을 많이 한 적은 정말 처음인 거 같다. 프리코스 기간동안 경험한 우테코는 내게 너무나 즐거운 경험이었고, 우테코에서 10개월 간 동료들과 성장에 매진하고 싶은 마음이 굴뚝 같다. 내일 제발 긴장해서 실수하지 않기를 간절히 빌고 또 빈다.
돌아가는 프로그램 vs 클린코드: 새로운 연습이 필요했다
현업에 갔을 때 클린한 코드만 존재하는 건 매우 이상적인 일이라 생각한다. 서비스가 빠르게 커나간 기업은 수많은 voc를 감당하느라 놓쳤을 수 있고, 개발 문화가 정착된 지 얼마 안되었거나 오래된 서비스라면 역시 클린한 코드만 존재할 순 없다. 그렇기에 레거시 코드 활용 전략이나 리팩터링과 같은 책들이 존재하는 것이고 말이다. 두 책도 언젠간 꼭 온전히 이해하고 싶다.
그렇다면 이번 일주일 간 내가 짠 코드는 어땠을까? 처음엔 프리코스 한 달간 내가 지켜온 수칙들을 잘 놓지 못했다. 따라서, 코드를 짜다가 중간 중간 리팩토링을 하는 여유를 부렸다. 물론 시간이 부족했다. 변화가 필요했고 의식적으로 클린하지 못한 코드를 눈 딱 감고 넘어가며 시간 안에 돌아가는 기능을 만들기 위해 노력했다. 즉, 위에 언급한 현업에 존재할 잘 동작하지만, 클린하지 못한 레거시를 만드는 경험을 해보았다.
내가 연습한 문제는 3기 마지막 주차, 3기 최종 테스트, 4기 최종 테스트, 5기 마지막 주차, 5기 최종테스트, 6기 마지막 주차였다. 이 여섯 문제를 정확하게 5시간씩 타이머를 재며 풀었다. 처음엔 6시간, 7시간이 걸려 좌절했지만 설계와 리팩토링 시간을 단축해 후엔 4시간, 5시간 만에 푸는 법을 익혔다.
단순히 좀더 빨리 푸는 법을 익힌 게 아니라, 돌아가는 기능을 빠르게 만들어내는 법을 배울 수 있어 좋은 경험이 되었다. 그리고 이 내가 만든 레거시 코드를 리팩토링 하는 것도 꽤나 재밌을 거란 기대가 되었다.
앞으로를 계획하며
테스트를 준비하며 하루에 최소 한 문제에서 많게는 두 문제씩 풀다보니 하루동안 10시간을 완벽하게 집중하는 경험을 한 게 즐겁고 뿌듯했다. 물론, 휴식도 필요하겠지만 우테코 최종 테스트 준비는 내게 버닝 타임이 되었다. 앞으로도 이번주 같았던 버닝을 자주 가져 보려 한다.
행복한 삶은 뭘까? 사람마다 다르겠지만 나는 내가 하고 있는 일이 보람차고 내 일에 대한 프라이드를 가질 때 행복하다. 나는 프리코스 과정부터 최종 테스트 준비까지 일련의 과정이 행복했고, 이는 개발자로서 평생을 살고 싶단 확신을 더 깊게 주었다. 앞으로도 행복한 개발자가 되어 보겠다.
테스트 후 작성한 회고
수월했는가
시험이 끝나고 집에 도착해서 작성하는 소감임을 밝힌다. 처음에 설계부터 구현까지 수월했다. applicationTest 동작, 이하 최소 기능은 확실시 해둔 상태에서 문제가 됐던건, 핵심 기능이었다. 최소 기능과 핵심 기능을 동일하게 볼 수도 있지만, 굳이 나눠보자면 이번 테스트에서 최소 기능은 아무 연속 당직이 없는 상태에서 당직표를 만드는 것이었고, 핵심 기능은 연속 당직까지 고려한 당직표를 만드는 것이었다.
수월하다 생각한 순간 위기가 찾아왔다
최소 기능은 연습한대로 요구사항을 제대로 파악하고 문서를 잘 만들어둔 덕에 정말 빠르게 완성했다. 문제는 핵심 기능이었다. 연속 당직에 대한 요구사항을 README에 예시까지 작성해보며 꼼꼼히 정리했음에도, 너무 긴장한 나머지 치명적인 실수를 했다. 바로, 당직을 선 사람들 리스트의 가장 마지막 사람이 새로 넣을 사람과 동일한 사람인지 확인하면 되는 걸 당직을 선 사람들 리스트에 새로 넣을 사람이 존재하는지 확인하는 코드로 잘못 작성한 것이다. 즉, equals 만 조건으로 걸어주면 끝나는 문제를, 실수로 contains 를 조건으로 걸어두고 한참 해맸다. contains를 걸었더니 당연히 조건을 만족하게 될 수 없었고 무한 반복이 돌았다.
내 코드를 난도질해보았다
무한 반복을 해결하는 과정에서 contains를 찾지 못해 점점 긴장감은 고조되었고, 거의 두 시간 가량을 헤맸다. 멀쩡한 코드를 이리 저리 고쳐보고, 마지막엔 쓸수 없게 되어 지웠지만 테스트코드도 짜보고, 디버거도 돌려보며 한참을 헤맸다. 그 과정에서 기존 코드를 급하게 수정했는데, 그러다보니 정말 이쁘지 않은 코드가 나왔다. 결국 제출 20분 전에야 무한 반복 이슈를 해결해서 핵심 기능을 구현해냈고, 다시 이쁜 코드로 돌아갈 시간은 남아있지 않았다. 내 기능이 제대로 동작하는지 확인하는 게 우선이었기 때문이다.
그럼에도 목표를 이루었다
그럼에도 시험장을 실실 웃으면서 나왔다. 내가 이번 테스트를 준비하면서 목표했던 이쁘진 않아도 돌아가는 코드 만들기를 성공했기 때문이다. 즉, 일주일간 테스트를 준비하며 연습했던 걸 적어도 실제 테스트에서 다 보여주고 나올 수 있어서 기뻤다. 요구사항에 있는 기능들을 돌아가게 구현하는 게 내 목표였다. 그 과정에서 프리코스 과정 중에 내 나름대로 쌓아온 클린코드에 대한 규칙들을 잠시 내려놓게 되더라도 말이다. 일단 구현을 최우선으로 생각했다.
앞으로를 고대하며
물론, 아쉬움이 없냐하면 그건 아니다. 만일 contains를 빨리 발견했더라면, 애초에 코드 짜는 과정에서 긴장 하지 않아서 구현 목록에 내가 써둔 대로 equals를 썼더라면, 하는 아쉬움이 머리 끝 조그만 공간에서 빼곰히 떠오르는 건 사실이다. 그랬다면, 아마 2시간 전에 핵심 기능까지 완성하고 여유로운 리팩토링과 테스트를 즐겼을 것이다. 처음의 클린했던 코드가 더러워지는 일도 없었을 것이고 말이다.
그럼에도 후회하지 않는 이유는, contains를 발견해서 결국은 시간 안에 핵심적인 기능을 구현하는 걸 성공해냈음이 너무나 감사하기 때문이다. 또, 리팩토링 할 요소로 어떤 것들이 있는지 스스로 인지하고 있기 때문이다. 이는 내가 프리코스 기간동안 배운 것들이 절대 헛되지 않았다는 걸 의미한다. 실제 현업에 나가서도 결국은 이상과 현실 사이에서 고민해야 하는 때가 올 텐데, 그 사이에서 어떻게 해야 조금이라도 그 괴리를 좁힐 수 있을지 앞으로 더 배워나가고 싶다. 우아한테크코스에서 말이다.
최종 테스트 코드에서 우선적으로 리팩토링 하고 싶은 요소
•
근무자들을 배정하는 로직에서 근무자들 클래스로 들어가서, 평일 근무자인지 주말 근무자인지 확인 후 수행하면 되는 로직들을 바깥에서 근무자를 확인해와 굳이 (심지어 else까지 따라 붙은) if문을 써서 분기해주고 있다. 급하게 코드를 수정하다 작성하게 된 부분인데, 전부 고쳐주자. 즉, 현재 요일을 인자로 넘겨주고 평일 근무자를 사용하는 로직과 주말 근무자를 사용하는 로직을 내부에서 알아서 분기해주게 고쳐줌으로써, 외부에선 분기 없이 하나의 함수만 사용해도 되게 만들어주자.
•
Holiday를 법정공휴일이란 단어로도 쓰고, 주말과 법정공휴일을 합한 단어로도 쓰고 있다….. 두 단어를 꼭 구분해주자. 굉장히 가독성을 떨어트리고 있다. 실제로, 코드 수정하면서 나조차 헷갈렸다.
•
모든 모델 이름이 OnCall을 붙이고 있는데, 전부 제거해줘도 괜찮을 거 같다. 처음에 붙이고 시작했던 이유는, Calendar의 경우 내장된 Calendar와 내가 만든 Calendar클래스 중 import 실수를 할까봐였다. 하지만 가독성을 떨어트리기도 하고, oncall 패키지 안에 존재하고, 현재처럼 볼륨이 크지 않은 프로젝트에선 굳이 안붙여줘도 될 거 같다.
•
how-to-solve에 대한 답을 거기에 적어야 하는 건줄 모르고 README.md에 적어뒀다. 옮겨주자.
•
dto에 값 넣는 걸 급하게 짜다 보니 모델에서 해버렸는데, dto가 모델을 받아서 매핑하게 수정해줌으로써 유지보수를 쉽게 하고 코드 가독성도 높이자.
•
월(달력의 월)도 enum으로 만들어줌으로써 하드코딩을 없애자.
•
employees에 만들었다가 사용 안하게 된 함수가 무려 네 개나 존재한다… 사용 안하는 코드 최대한 지웠음에도 시간에 쫓기다 놓쳤다. 지워주자.
리팩토링 요소를 생각하다 든 마지막 결심
시험장에서 웃으며 나왔던 것과 대비되는 일이지만, 리팩토링 요소를 찾다 주말 내내 점점 싱숭생숭해졌다. 그 이유는, 첫째로 미션 해결 전략 문항에 대한 답변을 how-to-solve가 아닌 readme에 적었다는 걸 깨달았기 때문이고 (시험 당시엔 how-to-solve 문항에 대한 답변을 readme에 언급하란 뜻으로 이해해버렸다), 둘째론 마음이 차분해진 상태에서 다시 생각해보니 더 완벽하게 로직을 짤 수 있었단 게 떠올랐기 때문이다. 너무 기대하고 긴장했던 나머지 시험장에서 한 실수가 떠오르며 아쉬움은 점점 커져만 갔다.
마인드컨트롤이 필요하다 생각 되었고, 우선 “최선을 다했는가?”에 대한 의문을 던졌다. 솔직하게 되돌아봤을 때 최종테스트 준비과정엔 내가 할 수 있는 한 최선을 다했다 생각되어 조금 진정이 되었다. 인터넷에 돌아다니는 “우테코 최종 코테” 관련한 블로그 글들은 죄다 읽었을 정도로 준비에 진심이었다. 책상 위에 올려 둘 물건까지 계획하며 준비했고, 풀 수 있는 기출들은 하루 10시간씩도 최대한 풀었다.
더 나아가, 그렇다면 내가 지금 할 수 있는 건 무엇일까 생각했다. 어차피 내 손아귀를 떠나간 테스트를 계속해서 떠올리며 싱숭생숭해지는 것보단 현재에 집중하기로 했다. 따라서, 계획을 짰다. 계획 대로 하루 하루를 집중하기로 했다. 긴장되고 싱숭생숭할 땐 무언가에 몰입하는 게 최고로 효과가 좋기 때문이다. 돌이켜보면 나는 무언가 간절한 결과를 기다릴 때마다 꽤나 공부를 많이 했던 거 같다. 이번에도 열심히 내 공부를 하며 하늘의 뜻을 기다리려 한다.