본문 바로가기
우아한테크코스 프리코스

[우아한테크코스 6기] 최종 코딩테스트: 비상 근무표 작성

by shyun00 2023. 12. 17.

우아한테크코스 선발과정의 정말 마지막 단계가 끝이났다.

 

1차 심사를 통과할거라고 약간의 기대조차 하지 않았기때문에 최종 코딩 테스트는 너무나도 감사한 기회였다.

(다른분들의 과제를 봤을때 잘하는분들이 정말 많았고, 거기에 비해 내 코드는 개선할 부분이 많다고 생각했다.

오히려 개선할 부분이 많아서 1차 통과를 한건가....?)

 

 

코딩테스트를 보게될거라고 생각을 못해서, 간단한 솔로 프로젝트를 해보려고 구상중이었다.

메일을 받자마자 해당 프로젝트는 잠시 미뤄두고 온전히 최종 코딩테스트 준비에 몰입했다.


< 준비내용 >

1. 먼저, 1~4차 과제를 다시 풀어보는 연습을 했다.

요구사항을 읽고 정리하고, 프로젝트 구조를 구상하고, 필요한 로직들을 작성하는 순서로 진행했다.

리팩토링과 테스트코드 작성을 제외하고 대략적으로 2~3시간정도에 모든 과제를 완성할 수 있었다.

 

2. 지난 기수 최종 코딩테스트 문제를 풀어보았다.

5기 최종 코딩 테스트 문제를 풀어보았다. 일주일간의 코치별 추천 메뉴를 작성해주는 프로그램이었다.

마찬가지로 요구사항을 정리하고 코드 구현까지 3시간 조금 넘는 시간이 걸렸다.

새로운 프로젝트로 시간 내 어느정도 구현을 완료해보고나니 자신감이 조금 생겼었다.

 

3. Java 기본 문법학습, 필요한 코드나 영어 단어를 준비했다.

1~4차 과제나 이전 최종테스트 과제를 풀어보면서 유사한 기능이나 코드가 사용된다는걸 느꼈다.

그래서 일부 필요한 코드(ex. 배열을 List로 변경, 배열에서 중복된 요소 있는지 검증하기, Enum 순회하면서 해당 값 찾기 등)를 정리했다.

그리고, 과제를 하면서 중요하다고 느꼈던 "네이밍"을 위해 영어 단어들을 정리했다.

메서드나 필드명을 작성할때 자주 사용되는것들이 있는데, 가끔 어떤것이 좋을지 고민되는 경우가 있어 해당 내용을 정리해보았다.

Java 스트림이나 컬렉션 등 기본적인 문법에 대한 학습도 다시한번 진행했다.

 

--> 그런데 실제로 현장에서는 준비해간 자료들을 참고하지 않았고 정리하면서 머리에 남아있던 내용으로 작성했다.

       정리된 자료나 구글링 결과를 많이 쓰게 될거라고 생각했는데, 시간적인 부분이나 진행 흐름상 아는 내용을 바탕으로 바로바로 작성하는것이 효율적이었다.


< 테스트 당일 >

12시부터 입실 시작이었고 12시 20분쯤 입실을 완료했다.

벌써 꽤 많은 참가자 분들이 와있어서 뒤쪽에 자리잡게됐다. 이전에 다른분들의 후기대로 책상은 좁은편이었다.

그래도 준비해간 장비가 많지 않아서 딱 적당하게! 준비하고 기다릴 수 있었다.

다과도 준비되어있고 기념품도 제공된다. 그런데 5시간동안 집중해서 하다보니 다과 먹을 시간도 없었다..!

시험 1시간 전쯤, 아래와 같이 시험 관련 안내 메일이 도착했다.

예전 기수 후기에서도 봤던 문구였지만, 다시 봐도 울림이 있는 문구였다. "돌아가는 쓰레기", "이상과 현실의 경계"라니.

어떤것을 우선으로 생각해야할지 다시한번 생각해볼 수 있었다.


< 과제 수행 >

한달간의 비상근무 스케쥴표를 작성하는 과제였다.

해당월과 시작요일, 평일 / 휴일의 근무 순번을 별도로 입력받고 해당 내용을 바탕으로 근무표를 작성하는 프로그램을 작성해야했다.

▶︎ 구현 기능 목록

더보기
## 구현 기능 목록

### 정보 입력
- [X] 비상 근무 배정 월과 요일을 입력받는다.
  - [x] 월(숫자)를 입력받는다. 1-12 범위의 숫자이다.
  - [x] 2월은 28일까지만 있다고 가정한다.
  - [x] 시작 요일을 입력받는다(일,월,화,수,목,금,토)
  - [x] 올바르지 않은 입력을 할 경우 [ERROR] 에러메세지 출력 후 다시 입력받는다.
- [X] 평일 비상 근무 순서를 입력받는다.
- [X] 휴일(토,일,공휴일) 비상 근무 순서를 입력받는다.
  - [X] 닉네임은 중복이 되지 않아야한다.
  - [x] 닉네임은 최대 5자까지 가능하다.
  - [x] 비상근무자는 최소 5명 이상이어야한다.
  - [x] 비상근무자는 최대 35명을 넘지 말아야한다.
  - [x] 평일순번, 휴일순번에 각각 1회 편성되어야한다.
  - [x] 평일 또는 휴일 순번이 올바르지 않은 경우 평일 순번부터 다시 입력받는다.

### 비상 근무 일정 수립
- [X] 공휴일은 총 8일이다. (문서 참고)
- [X] 순번에 따라 비상근무일을 배정한다.
- [X] 연속해서 2일 비상근무를 할 수 없다.
  - [x] 연속해서 근무하게될 경우 다음 근무자와 순서를 바꿔서 근무한다.
  - [x] 비상근무자 배정시 다음 근무자와 순서를 바꿔야하는경우 앞의 날짜부터 순서를 변경한다.

### 결과 출력
- [X] 월, 날짜, 요일, 이름을 출력한다.
- [X] 평일이면서 법정공휴일인 경우 요일 뒤에 (휴일)표기를 한다.

### 추가사항
- [X] how-to-solve 문서 작성

 

 

▶︎ 프로젝트 구조

 

▶︎ 코드 작성

MVC 패턴을 적용해 view에서 입력과 출력을, model에서 비즈니스 로직을, controller에서 전체 코드 제어를 담당하도록 구현했다.

최종 테스트 과제 코드: (링크)

* 부족한 부분이 많은 코드입니다. 코드 리뷰는 언제든지 환영입니다.^^

 

1) view

이번 과제에서 이전과 달랐던 부분이 있다.

평일 근무순번과 주말 근무순번을 입력받을 때, 잘못된 입력을 받으면 무조건 평일 근무선분 부분부터 다시 입력받아야했다.

이 부분은 inputView에서 평일 근무순번 / 주말 근무 순번 입력 받는 로직을 각각 작성하고

Controller에서 주말 근무순번까지 제대로 입력받을때까지 입력받는 로직을 추가했다. (do-while문)

 

2) model

역할에 따라 총 네개의 도메인으로 구분했다.

  • Computer: 스케쥴을 만드는 핵심 기능을 한다. (컴퓨터가 자동으로 일정을 만든다는 의미에서 Computer로 명명)
              입력받은 월, 요일에 맞게 캘린더를 생성하고 스케쥴을 생성하는 역할을 한다.
              List<Schedule>을 필드로 가지며 해당 결과가 최종 데이터로 출력된다.
  • Holiday: 요일과는 별개로 휴일의 경우 휴일 순번에서 배정해야하며,
              평일 + 휴일의 경우 출력 결과에 "(휴일)"이라는 문구를 붙여야했다.
              따라서 휴일을 별도의 Enum으로 관리하고 해당 날짜가 휴일인지 검증하는 로직을 추가했다.
              혹시 휴일이 추가 및 변경될 경우 해당 부분만 수정해주면 된다.
  • Month: 입력받은 월에 따라 날짜수를 결정한다. Enum으로 생성했으며 getTotalDays() 메서드를 통해 해당 월의 총 날짜를 구한다.
  • Schedule: 하루하루의 스케쥴을 담은 클래스이다. 월, 일, 요일, 휴일여부, 해당근무자를 필드로 갖는다.
              배정받은 내용을 가지고 있으며 주말인지/휴일인지 확인하는 로직, 근무자를 지정하는 로직을 갖는다.
              최종적으로 해당 스케쥴의 정보를 출력(전달)하기 위한 로직도 포함하였다.          

3) controller

InputView, OutputView, Computer 객체들을 사용해 전체 코드 제어를 담당한다.

객체간에 필요한 데이터를 전달하고 최종 데이터를 출력할 수 있도록 했다. start() 메서드를 통해 전체 애플리케이션을 실행한다.

 

4) configurer

생성자 필드 주입을 위해 new 키워드를 사용하지 않고 AppConfigurer를 사용하고있다.

 

5) Utils

  • ConstantUtils: 출력 문구나 고정된 숫자들을 상수 처리하였다.
  • Parser: InputView에서 데이터 타입 변경이 필요한 부분은 Parser에서 처리하도록 하였다.
  • Validator: 입력받은 값의 검증이 필요한 경우 Validator에서 해당 부분을 처리하고있다.

< 최종 회고 >

살짝 아쉽기는 하지만 최선을 다했기에 후회는 없다.

 

처음 과제를 작성하고 약 3시간이 지났을때 어느정도 코드 구현이 완료되었다고 생각했다.

그런데 테스트 코드를 돌려보니 정상적으로 통과되지 않았고 이때부터 커밋 메세지에 "fix:"가 추가되기 시작했다.

인덱스를 통해 접근하거나 초기 값을 직접 설정해주는 로직이 있다보니 0, 1 이런 사소한 숫자에 따라 결과가 달라지는 부분이 있었다.

논리적으로 생각해야하는 부분들이 있어서 자칫 잘못하면 의도와 완전히 다른 방향으로 동작하기도 했다.

코드를 실행하고 여러가지 경우를 테스트해보며 오류들을 고쳐나갔고 마지막에는 정상적으로 동작하는 코드를 만들 수 있었다.

(정말 과제 종료되는 시간까지 계속해서 사용자 관점에서의 테스트와 리팩토링을 진행했다.)

 

이번에는 코드 작성과 리팩토링에 모든 시간을 써버려서 테스트코드를 작성하지 못했는데,

테스트코드를 작성했다면 이런 부분을 미리 알 수 있지 않았을까 하는 아쉬움이 있다.

 

그래도 처음 안내메일에서 언급되어있던것처럼 일단 "돌아가는 쓰레기"는 만들었다.

최대한 예쁜 쓰레기(?)를 만들어보기 위해 리팩토링도 해보고 여러가지 케이스를 통해 검증도 진행했다.

 

많은 사람들이 모여 같이 코딩하는 경험은 처음이라 아주 색다르면서도 재밌었다.

신기할정도로 타자소리와 클릭하는소리밖에 들리지 않았고(심지어 내 코드를 작성하는중에는 이 소리조차 들리지 않았다.)

모두가 몰입해서 하고있다는것이 느껴지는 시간이었다.

 

이제 결과는 과정 담당자분들께 달렸다. 이제 나는 다시 내가 하던 일에 집중하고자한다.

최종 코딩테스트를 끝으로 짧고도 길었던 한달 반정도의 일정이 끝이났고,

그 기간동안 여러가지 잊지못할 경험과 배움을 얻을 수 있어서 행복했다! 👍🏻