진짜 1차 심사를 통과할 줄은 상상도 못했다.
워낙 경쟁률이 치열하기도 하고 발표 전날까지도 노션에 올린 증빙 자료 조회 수가 올라가지 않아서 발표 전날엔 이미 '그래도 매 순간 열심히 했으니까 됐다.'라며 스스로 위로하고 있었다.
그런데 이메일의 미리 보기로 "이 메일을 받는 분들은 최종 코딩 테스트 대상자입니다."를 봤을 때 그 기분은 정말.. 대학 합격했을 때 보다 더 기뻤다. (교수님 죄송합니다.) 여기저기에 응원해줘서 고맙다고 연락 돌리고 싶었는데 축하 인사를 받으면 들뜰 나 자신을 알기 때문에 꾸욱 참고 코딩 테스트 준비에만 일념했다.
프리코스가 끝나자마자 스터디 모집 글이 올라와서 바로 참여했다. 스터디는 일주일에 두 번, 총 6번의 실전 경험을 쌓고 5~10분 정도의 회고 시간을 갖는 스터디였다. 1차 심사 결과는 불투명했지만 이 회고 시간을 바라보며 올출 했다. 문제를 풀면서 겪었던 고민이 비슷했기에 공감대도 있었고, 하나의 문제를 두고 다양한 시각과 접근 방식을 접할 수 있어서 많은 것을 배워가는 시간이었다. 다시 한번 좋은 기회 만들어 주신 스터디 장님께 감사 인사를..🙏
스터디가 끝나면 개인적인 분석 타임도 가졌다. 커밋 로그를 보며 하나의 태스크를 만드는 데 어느 정도의 시간이 걸리는지 적고, '정보를 객체로 구조화하는 것이 약하구나'라던가 '이런 구조는 짧은 시간 안에 만들기 힘들구나' 같은 내 약점을 파악했다. 이렇게 쌓인 기록이 시험 전날 전략을 재정비하는 데 큰 도움이 됐다.
최종 코테는 선릉과 잠실 두 곳에서 나눠서 치르는데 나는 잠실 캠퍼스에서 보게 됐다. 엘리베이터를 타고 14층까지 올라가는 순간 긴장감이 올라와 가슴이 너무 뛰었는데 막상 도착하고 보니 따뜻하고 밝은 분위기여서 갑자기 좋은 에너지가 차오르는 기분이었다.
기념품과 다과도 준비되어 있어서 짐을 놓고 가지러 가는데 그곳에 포비가 요정처럼 서 계셔서 긴장된 상태였는데도 나도 모르게 웃음이 나왔다. 스몰톡도 하고 싶었는데 극 내향인인 나로서는 도저히 입이 떼어지지 않았다.(ㅋㅋㅠㅠ) 시험 시작 전엔 코치님들과 포비가 '옆 사람과 페어 프로그래밍만 안 하면 된다.'라고 농담도 던지셔서 이때 긴장이 많이 풀렸다. 이런 소소한 배려가 감동이었다. 🥹
당시 네트워크 연결 이슈가 있어서 시작 시간이 30분 미뤄졌다. 프리코스 때도 문제가 발생하면 바로 대책을 마련해 주셨기 때문에 금방 해결될 것이라 믿고 oncall이라는 무슨 의미일까 예상해보는 시간을 가졌다. 단어를 검색해보니 당직, 긴급 대기 같은 의미가 있어서 혹시 근무표를 짜는 미션일까..? 생각했는데 실제 문제와 비슷해서 조금 놀랐다.
그럼에도 불구하고 문제를 보니까 떨리는 마음은 어쩔 수 없는지 설명이 눈에 잘 들어오지 않았다. 4주 차 크리스마스 이벤트와 비슷하게 롤 플레이성으로 정보가 자세하게 제공됐는데 마음이 조급하다 보니 자꾸 단어를 건너뛰고 읽게 돼 여러 번 읽어도 문제 파악이 쉽지 않았다. 😅
이러다가 패닉이 올 것 같았지만 여기서 무너지면 정말로 시간을 버리게될 것 같아 마음을 다잡고 README.md에 입력 값과 유효성 검사해야 하는 부분부터 작성했다. 문제에서 입력 값과 관련한 처리를 모두 제외하고 나니 딱 핵심적인 도메인에 관한 내용만 남아 이해가 용이해졌다. 좋은 선택이었다고 생각한다.
집에 돌아와 커밋 완료 시간을 보니 Readme.md를 작성하기 까지 20분이 채 걸리지 않았다. 당시엔 억겁의 시간처럼 느껴졌는데 모의 테스트를 봤을 때와 비교해도 별로 차이가 나지 않는 수치다. 7기에 도전하시는 분들도 막혔을 때 당황하거나 포기하지 말고 차근차근 본인이 할 수 있는 것에 집중하시길 조언한다!
문제를 파악하니 객체를 다음과 같은 역할로 분리해야겠다는 생각이 들었다.
Calendar 클래스OnCall 클래스위의 내용 중에서 2번 비상 근무 순서를 관리하는 객체는 처음엔 휴일 근무 순서를 관리하는 HolidayOnCall 과 평일 근무 순서를 관리하는 WeekOnCall 로 나누었었는데 기능을 완성하고 보니 중복되는 로직이 너무 많아 OnCall 로 합쳤다.
Calendar 클래스를 생성하고 초기화하기 위해 월별 정보를 저장하는 객체를 만들어야 했다. 위에서 언급했지만 모의 테스트를 볼 때 가장 약했던 부분이 문제에 사용될 객체를 구성하는 부분이었는데, 스터디가 끝나고 다짐한 대로 객체 배열을 사용하는 방식으로 구상했다. 게다가 크리스마스 미션에서 이중 객체를 만들어 가공에 어려움을 겪은 기억이 있어 객체 배열로 만들어야겠다는 결심이 섰고, 결론적으로 아래와 같은 코드가 만들어졌다.
export const MONTHS = [
{ month: 1, startDate: 1, endDate: 31, holidays: [1] },
{ month: 2, startDate: 1, endDate: 28 },
{ month: 3, startDate: 1, endDate: 31, holidays: [1] },
{ month: 4, startDate: 1, endDate: 30 },
{ month: 5, startDate: 1, endDate: 31, holidays: [5] },
{ month: 6, startDate: 1, endDate: 30, holidays: [6] },
{ month: 7, startDate: 1, endDate: 31 },
{ month: 8, startDate: 1, endDate: 31, holidays: [15] },
{ month: 9, startDate: 1, endDate: 30 },
{ month: 10, startDate: 1, endDate: 31, holidays: [3, 9] },
{ month: 11, startDate: 1, endDate: 30 },
{ month: 12, startDate: 1, endDate: 31, holidays: [25] },
];
export const START_MONTH = 1;
export const LAST_MONTH = 12;
export const DAYS = ['월', '화', '수', '목', '금', '토', '일'];
지금 와서 보니 startDate 같은 불필요한 정보도 있고, SSOT를 생각하면 START_MONTH나 LAST_MONTH를 할당할 때 동적으로 계산하는 것이 나았을 것이라는 생각이 든다.😅
해당 부분을 아래와 같이 리팩토링했다.
import { FIRST_ELEMENT, LAST_ELEMENT } from './constants.js';
export const MONTHS = [
{ month: 1, endDate: 31, holidays: [1] },
{ month: 2, endDate: 28 },
{ month: 3, endDate: 31, holidays: [1] },
{ month: 4, endDate: 30 },
{ month: 5, endDate: 31, holidays: [5] },
{ month: 6, endDate: 30, holidays: [6] },
{ month: 7, endDate: 31 },
{ month: 8, endDate: 31, holidays: [15] },
{ month: 9, endDate: 30 },
{ month: 10, endDate: 31, holidays: [3, 9] },
{ month: 11, endDate: 30 },
{ month: 12, endDate: 31, holidays: [25] },
];
export const START_MONTH = MONTHS.at(FIRST_ELEMENT).month;
export const LAST_MONTH = MONTHS.at(LAST_ELEMENT).month;
OnCall 도메인한 개발자가 이틀 연속 근무할 수 없기 때문에 뒷 순서와 바꿔야 한다는 요구사항을 처음 봤을 땐 직관적으로 linked list가 떠올랐다. 하지만 이 짧은 시간 내에 linked list를 구현하기엔 애매했기 때문에 잠시 고민하다가 비구조화 할당을 떠올렸다.
// 비구조화 할당으로 원래 순번과 그 다음 순번, 그리고 나머지를 받아 온다.
const [cur, next, ...rest] = onCall;
const updatedList = prev === cur ? [cur, ...rest, next] : [next, ...rest, cur];
아쉬움 많은 코드 속에서 그나마 마음에 드는 코드랄까..?
테스트 시작 전 프리미션과 다른 요구사항이 있으니 확인해 달라는 안내가 있었는데 바로 how to solve 문서를 작성하는 것이었다.
미션 해결 전략
- 본인이 이해하고 구현한 내용에 기반해 '다른 근무자와 순서를 바꿔야 하는 경우'를 자신만의 예시를 들어 설명하세요. (필수)
- 요구사항에서 제시한 앞의 날짜부터 순서를 변경하는 방법 외에 다른 방법이 있다면 어떤 방식이 있는지, 이 방법은 기존에 제시된 방식과 비교해 어떤 차이가 있는지 설명하세요. (선택)
처음 문제 이해도가 낮을 때 이 문서를 봤을 땐 엄청 막막했다. 그러면서도 시간이 부족해 빈칸으로 내는 불상사가 발생할까봐 문제에 나와있는 예시를 이름만 바꿔서 작성했다.😅
그런데 OnCall 도메인의 기능 테스트를 작성하면서 이게 결국 how to solve의 1번 문항과도 연결되지 않나..? 하는 생각에 작성한 테스트 케이스를 바탕으로 답안을 다시 작성했다.
상황 가정하기
- 5일 동안의 근무표를 짠다고 가정한다. (1일 ~ 5일, 월요일 시작)
- 공휴일이 2일과 5일에 있다고 가정한다.
- 평일 비상 근무 순번은 다음과 같다: 슬링키, 준팍, 도밥, 고니, 수아, 루루
- 휴일 비상 근무 순번은 다음과 같다: 슬링키, 준팍, 수아, 고니, 루루, 도밥
- 1일은 평일이기 때문에 슬링키의 비상 근무 차례다.
- ‼️ 2일은 공휴일이기 때문에 슬링키의 차례지만 전날 근무했으므로 준팍과 순서가 바뀐다. 따라서 준팍이 근무한다.
- ‼️ 3일은 평일이기 때문에 준팍의 차례지만 전날 근무했으므로 도밥과 순서가 바뀐다. 따라서 도밥이 근무한다.
- 4일은 평일이기 때문에 도밥과 순서가 바뀐 준팍이 근무한다.
- 5일은 공휴일이기 때문에 준팍과 순서가 바뀐 슬링키가 근무한다.
미션을 제출하고 온갖 감정이 들었는데 가족들이 마중을 나와줘서 감상에 젖을 틈도 없이 일단 밥부터 먹으러 갔다. 뜨뜻한 등촌 칼국수 국물이 들어가니까 마음이 조금 편해졌다. 볶음밥까지 먹으니까 너무 행복하긴 했다. 냠..🍚

스터디 분들에게 디스코드로 고생했다고 인사를 드리고, 집에 와서 씻고 이불 둘둘 싸매 누우니 그제서야 끝났다는 게 실감이 났다.
시험이 끝난 직후에는 심장도 아프고 머리도 아프고 전신 근육이 아파서 '결과 발표 전까지 요가 수련이나 하면서 요양해야겠다.' 다짐했는데 오늘 회고를 작성하고 나니 코드에도 아쉬운 점이 많고(리팩토링) 여권 세탁 이슈(..)가 발생해서 다음 주도 꽉꽉 찬 일주일을 보내게 될 것 같다.😂
두 달 동안 알차게 몰입했던 프리코스가 끝나고 나니 내 다음 스텝은 뭘까 궁금해진다. 이 두 달이 내 마인드와 습관을 좋은 방향으로 바꾸어 놨기 때문에 당분간은 이 에너지를 이어나가서 근본적인 변화로 이어지게 노력하는 데 집중할 것 같다. 🧘