우테코 6기 최종 코딩 테스트 후기 (안드로이드 AN)

 

 

 

안녕하세요 !

우아한테크코스 안드로이드 파트로 지원 후, 최종 코딩 테스트를 진행한 회고를 작성하였습니다.

안드로이드 파트가 다른 파트에 비해 뽑는 인원이 적다보니, 후기글이 많이 없었습니다.

제 회고가 다음 시험을 보는 분들에게 도움이 되었으면 좋겠고, 궁금한 점이 있다면 참고되었으면 좋겠습니다!

프리코스 과정을 통해서 배운 점이 많아서 회고를 기록하게 되었는데요.

이번 최종 코딩 테스트 역시 배운 점과 좋은 경험이 되었던 것 같아서 회고를 남기게 되었습니다.

 

1차 합격과 최종 코딩테스트🚀

프리코스가 끝나고 최종 코딩 테스트 발표를 기다리는 동안 큰 기대를 하지 않고 있었습니다.

매주 최선을 다해서 진행하였지만, 실수도 몇 번 하였고 잘하시는 분들이 많아서 어렵다고 생각하고 있었습니다.

성장하는 과정이라고 생각하며,, 과제로 제출한 코드를 리팩토링하는 과정을 하며 시간을 보내고 있었습니다.

 

 

리팩토링과 그동안 못했던 프로젝트를 진행하면서 시간을 보내던 중에 1차 합격 메일을 받을 수 있었습니다 !! 

너무 기뻤지만, 최종 코딩 테스트까지 남은 기간이 얼마 남지 않았기에 메일을 받은 후 바로 준비를 시작하였습니다.

 

최종 코딩 테스트 공부법 🤵🏻‍♂️

가장 우선적으로 한 방법은 안드로이드, 웹, 백엔드 할 것 없이 모든 이전 기수 경험자들의 리뷰와 코드를 확인하였습니다.

실제 시험장에서 발생할 수 있는 변수가 무엇인지, 어떤 식으로 문제를 해결해 나갔는지 꼼꼼히 확인했던 것 같습니다.

 

시험장에서 실제로 시험을 본다고 상상해 보았습니다.

시간적인 제한이나, 시험장에서의 압박적인 분위기, 긴장감, 주변의 여유 있는 실력자(?) 등의 가능성을 생각하였습니다.

따라서 실수는 불가피하다고 느꼈고, 시험장에서 내가 지켜야 할 규칙을 스스로 만들게 되었습니다.

시험 전에 노션에 직접 동기적인 처리 과정을 정리하였습니다.

멀티 테스킹이 안된다는 나의 단점을 너무나 잘 알기 때문에, 저 스스로를 제어하는 공략법을 만들게 되었습니다!

 

자주 사용하는 커밋

  • Feat : 새 기능 추가
  • Test : 테스트 코드 작성
  • Refactor : 코드 리팩토링
  • Fix : 버그 수정
  • Style : 코드 포맷 변경, 코드도 수정 없이 스타일 수정
  • Docs : 문서 수정
  • Rename : 파일 명, 폴더 명 수정

빠른 진행 순서

  • 미션 꼼꼼히 확인하기
  • 테스트 코드 우선 열어보기 (객체 양식 같은 것은 없는지 확인)
  • else 문 제거 → 함수 마지막에 리턴 or map 활용
  • 이전 미션 실패 : 꼼꼼하게 요구사항을 읽지 않아서 ! 꼭 읽고 꼼꼼히 체크
  • README
    1. 요구 사항 정리
      • 개발 요구사항 정리
    2. 요구 사항에 따른 기능 분리
      • 도메인 단위 도출 + 연관 상수는 enum 클래스로 구분
    3. 예외 상황 정리
      • 예외 상황 정리
      • 모든 예외 상황 추가 + 체크리스트 작성
    4. Docs  커밋
  • 기능 구현 전 준비
    • util의 Error,Form,Rule,Message 생성
  • 도메인 단위 기능 구현
    • 내가 구현한 기능 구분할 수 있게 주석 추가 후 사용할 때 제거
    • 대표 기능 생성 (이벤트 캘린더, 키오스크 등등 )
    • 연관 상수(enum)를 통한 모델 생성
  • README 확인 + Docs 커밋
  • 사용자 기능 구현
    • 사용자 입력 검증 코드 작성과 예외처리
      • 검증 코드 작성 시 시간 오래 걸려도 최대한 심플하게
    • 사용자 입력과 출력 구현
    • 컨트롤러에 현재 구현한 기능 구현
    • README 확인 + Docs 커밋
  • 모든 기능 완료 (컨트롤러 내부)
    • README 확인 + Docs 커밋
  • 테스트 코드 문서 작성
    • 테스트 코드 작성과 예외 추가
    • README 확인 + 예외 추가
    • 테스트 코드 구현
  • 전체적인 리팩토링 + 구현 문서 확인
  • 테스트 코드 리팩토링
  • README 완성 + 커밋
  • 제출

 

위와 같은 플로우를 따라서 진행하고자 하였으며, 시간적 제약을 최대한 덜 받도록 저를 통제하고자 하였습니다..!

가장 중요하게 생각한 부분은 요구사항을 최대한 꼼꼼히 확인하고, 코드적인 실수는 있어도 이해의 실수를 없애는 것이었습니다.

이전에 로또 과제를 진행할 때, 처음에 문제를 잘못 이해하고 하루를 날린 것을 생각하면

제한된 시간에서도 충분히 발생할 수 있는 실수라고 생각하였습니다.

 

요구사항을 도출하고 도메인 단위로 기능을 정리하는 것을 1시간가량 잡기로 마음을 먹었습니다.

이후에 깃 레포를 파고 1주 차부터 프리코스 과정에서 내가 지키지 않았던, 중요한 피드백이 무엇이었는지 정리하게 되었습니다.

https://github.com/jinuemong/wooteco-final

 

GitHub - jinuemong/wooteco-final: 우테코 최종 코딩 테스트 준비

우테코 최종 코딩 테스트 준비. Contribute to jinuemong/wooteco-final development by creating an account on GitHub.

github.com

 

위와 같이 최종 미션을 수행하기 위해서 피드백을 분석하고 1~4 주차 과정의 재구현과 지난 기수의 문제 풀이로 준비하였습니다.

시험장이라고 생각하고 시간을 두고 풀었으며, 이미 푼 문제들은 3시간으로 제한하고 새로운 문제는 4시간으로 제한하여 구현하였습니다.

내가 제작한 빠른 진행 순서에 맞게 꼼꼼하게 커밋하며, 테스트 코드 작성에 큰 시간을 투자하였습니다.

 

최종 시험🧑‍💻

전날에 긴장감에 잠을 많이 못 자게 되었습니다..

박카스 두 병을 들고 시험장에 들어가자 중압감과 현실감을 느끼게 되었습니다.

제가 치른 시험장에는 안드로이드 분들만 계셨고, 어떤 분이 질문을 하셨는데 총 45명이 있었던 것 같습니다.

가장 좋았던 점은 옆사람과 분리되어 있는 시험 환경이었으며, 매우 자유로웠습니다!

 

네트워크 이슈로 시험 시간이 30분 연장 되었고, 화장실을 들락거리며 긴장을 낮추려고 노력하였습니다.

1시 반에 시험이 시작하였고, 실수하지 않도록 레포를 생성하는 과정부터 차분하게 진행하였습니다.

 

첫 1시간 정도는 스스로 작성한 진행 순서를 보고 기능 정리를 우선적으로 하였습니다.

시험 문제는 확실히 프리코스 과정이나 이전 기출문제보다 어려웠습니다.

구현할 수 있지만 시간이 부족할 수 있게다 생각하였고,

리팩토링이나 테스트 코드도 중요하지만 시간을 투자해서 기능 구현을 우선으로 생각하였습니다.

 

중간에 노트북을 닫고 쉬는 시간 10분을 주셨는데 절실한 마음에 쉬지 못하고 머릿속으로 계속 기능 분리를 생각했던 것 같습니다..

쉬는 시간 동안 눈은 편하게 쉴 수 있었고, 덕분에 남은 시간 집중할 수 있었던 것 같습니다.

 

시험 시간이 약 3시간 정도 되었을 때 기능 구현이 끝났습니다.

테스트와 리팩토링 과정에서 오류를 발견하였고, 30분 정도? 오류를 수정하니 기능 구현은 완료되었습니다.

기존에 목표로 한 4시간을 꽉 채우고 기능 구현을 완료하였으므로 그나마 준비를 잘했다는 생각이 들었습니다..!

 

이후에 1시간 정도 리팩토링과 테스트 케이스 작성에 시간을 투자하였습니다.

피드백받은 대로, 도메인 단위로 테스트를 구성하였고 간단하지만 꼼꼼한 테스트를 진행하였습니다.

시험 시간 30분 정도를 남겼을 때 제출할 수 있었고, 이번 과제에 새로 추가된 과제 진행 요구 사항 how-to-solve 작성과

최종 소감만을 남긴 채로 2-30분 정도의 시간이 남았었습니다.

 

시간이 많지 않다 보니 소감문은 그리 길게 작성하지 못하였는데요.

어떤 마음 가짐으로 임하게 되었고, 절실함과 성장할 수 있었던 점, 기회를 주셔서 감사한 점에 대하여 작성하였습니다.

 

 미션 해결 전략은 정확하게 작성하지 못한 것 같습니다.

1. 본인이 이해하고 구현한 내용에 기반해 '다른 근무자와 순서를 바꿔야 하는 경우'를 
자신만의 예시를 들어 설명하세요. (필수)

 

위와 같은 질문을 주셨는데, 예시를 들어서 설명하기보다는 구현한 내용을 기반으로 상세하게 작성한 것 같습니다.

 

  • 근무지를 배정하는 경우 DutyManager 클래스를 사용하였으며, 아래와 같은 순서로 구현하였습니다.
    1. 각 주말과 평일 근무자의 인덱스를 0으로 초기화하였습니다.
    2. 근무를 배정할 캘린더를 받아, 첫 일 수부터 확인합니다.
    3. 각 캘린더의 휴일, 주말, 공휴일 여부를 확인한 후 allocateWeekDay를 통해서 근무를 배정합니다.
    4. 근무자로 배정될 경우 checkDoubleWork를 통해 이전에 2번 근무한 근무자를 찾습니다.
    5. 새로 등록할 근무자와 2번 근무한 근무자의 2번째 근무날을 교체해줍니다. -> changeAddUser
    6. 2번 근무한 근무자가 아니라면 단순히 근무자를 추가합니다.
  • 이와 같은 방법으로 근무자를 순서대로 배치하였습니다.

위와 같이 답변하였는데, 예시를 들지 않고 작성하는 실수를 했습니다🥲

내가 어떻게 문제를 이해했고, 어떤 방식으로 풀었는지 설명하고자 하였고 직접 구현했다는 점(?)을 어필하였습니다..

 

다른 질문은 선택사항이었습니다.

2. 요구 사항에서 제시한 앞의 날짜부터 순서를 변경하는 방법 외에 다른 방법이 있다면 어떤 방식이 있는지, 
이 방법은 기존에 제시된 방식과 비교해 어떤 차이가 있는지 설명하세요. (선택)

 

적은 시간이었지만, 문제의 의도를 생각해 보았습니다.

"앞의 날짜부터 순서를 변경하는"이라는 말의 의미를 생각해 보았는데요.

저는 근무지 순번을 아예 변경하는지, 겹치는 날만 변경하는지의 차이라고 생각하였습니다.

제가 구현한 방법은 근무지가 겹치면 그 자리만 둘로 변경하고, 근무 순서는 원래대로 유지하는 것이었습니다. (겹치는 근무만 변경)

하지만 근무 순서를 아예 바꿔가면서 유기적으로 배정하는 방법이 있을 것 같았습니다. (근무 순서를 변경)

따라서 이를 해결하기 위해서 큐 자료구조를 생각하였고, 그에 관하여 작성하였습니다.

  • 근무자 리스트를 스택으로 생각하고, 마지막 값이 새로 들어갈 근무자와 같다면 제작해 둔 큐에 새로 들어갈 근무자를 넣습니다.
  • 이후에 다음 근무자를 추가할 때, 큐에 바꿔야 하는 근무자가 있다면, 둘의 순서를 바꿔줍니다!
  • 기존에 제시한 방법은 이미 넣은 수를 변경하는 것이고, 새로 구상한 방법은 넣기 전에 따로 담아둔 후 처리한다는 특징이 있습니다.
  • 큐에 대한 메모리를 조금 더 쓰지만, 기존에 있는 근무자들을 확인할 필요가 없으므로, 적은 시간복잡도를 소모할 것 같습니다.

위와 같이 작성하였는데, 이제 보니 조금 횡설수설로 썼군요..

시간이 부족해서 생각나는 대로 바로 작성하다 보니 제가 전달하고자 하는 의도와는 다르게 작성한 것 같았습니다..!

그나마 둘의 차이를 이해하고 있는 것처럼(?) 작성하여 다행인 것 같습니다..

 

최종 제출 폴더 구조를 확인해 보았습니다.

 

 

도메인 단위로 테스트를 이루고자 하였고, MVC 패턴에 준수하여 기능을 분리하였습니다.

 

소감 🙇‍♂️

소감문에서 작성한 것처럼 많은 지원자에 대한 코드를 확인하고 피드백을 주시는 운영진분들에게 감사드립니다..

지원자들이 많은 시간을 투자하는 것 이상으로 평가하는데 시간을 투자하시는 것이 느껴졌고, 덕분에 성장할 수 있었습니다.

함께 지원하신 분들은 꼭 좋은 결과 있으셨으면 좋겠습니다. 

저는 시험 이후에 거의 3일은 쉬었는데요, 충전하는 시간을 가지고 리프래쉬하여 원하는 결과 얻으셨으면 좋겠습니다 !

2023년 좋은 경험으로 마무리하게 되어 좋았고, 성장할 수 있는 시간이었습니다.

 

감사합니다 🙇‍♂️🙇‍♂️🙇‍♂️

 

추가 테스트🎯

우아한테크코스 프리코스 커뮤니티 디코에서 어떤 분이 고맙게도 테스트케이스를 작성해 주셨습니다.

AOS 분들이 아직 확인을 안 하신 것 같아서 피드백을 드리기 위해 테스트 케이스를 돌려보았습니다.

저는 총 10개의 테스트 중에 2가지 부분에서 테스트를 통과하지 못하였는데요.,

이유는 아래와 같았습니다.

 

닉네임의 유효성 검사 ( 문자인지)와 근무자들의 입력값을 받은 후의 예외처리 과정에서

테스트 케이스와 다른 부분이 있어서 오류가 났습니다.

첫 번째 경우는 공백이나 특수문자, dlj_1과 같은 닉네임에 제한을 두려하였고,

요구사항에는 없었지만 추가한 부분인데 어떻게 평가될지 모르겠습니다. 

요구사항에 없는 기능까지 구현하여 테스트 케이스에 걸리는 것은 아닌지,.. 걱정하게 되었습니다.🥲

 

두 번째 경우는 입출력 요구 사항 관련 부분인데요.

위 경우에 평일 비상근무를 잘못 입력한 경우 바로 평일 순번 코드부터 입력받게 테스트가 짜여있었습니다.

저의 경우는 평일에 오류가 있더라도 휴일까지 받고 새로 입력을 받게 코드를 작성하였는데요.

 

평일 순번에서 바로 에러를 케치하는 것이 맞는 것 같습니다.

두 입력값의 유효성을 한 번에 검사하여 처리하도록 코드를 작성하느냐고 놓친 부분인 것 같네요..

그래도 평일 또는 휴일의 입력 값이 올바르지 않은 경우 평일 순번부터 다시 받는다의 요구사항은 지켰으니 다행입니다!

 

나머지 기능 테스트는 모두 통과하는 것으로 보아서, 기능 구현은 오류가 없었던 것 같습니다..

새로운 테스트 케이스 덕분에 리팩토링은 할 수 있었고, 테스트 케이스 작성해신 분 너무 감사합니다.. !🔥

더욱 성장한 것 같습니다 !

코드 리팩토링

코드를 리팩토링하는 과정에서 오류를 하나 발견했습니다.🥲

출력 요구사항인 "평일이면서 법정공휴일의 경우에만 요일 뒤에 (휴일) 표기를 해야 한다."를 지키지 않은 것인데요.

코드를 고려해놓고 적용시키지 않은 것을 발견하였습니다.

주말인 경우 (휴일)을 출력하지 않도록 코드를 짜야했었는데 (1,일)이 입력 된 경우 오류가 발생하였습니다.

아래와 같이 요일을 관리하는 DutyDay에서 주말인 경우를 체크하도록 리팩토링 하였습니다.

        fun checkIsWeekday(dutyDay: DutyDay): Boolean {
            return !(dutyDay == SUNDAY || dutyDay == SATURDAY)
        }

 

캘린더에서 (휴일)표시 여부를 확인하기 위한 함수에 위에 제작한 checkIsWeekday를 적용하였습니다.

    fun getHolidayMessage(): String {
        if (dutyDayOfWeek.isHoliday() && DutyDay.checkIsWeekday(dutyDay)) return "(${dutyDayOfWeek.getInfo()})"
        return ""
    }

 

두줄의 코드를 적용하지 않은 것으로 하나의 요구사항을 만족하지 못하게 되었습니다.🥲

그래도 리팩토링 과정에서 발견해서 코드 수정으로 인지할 수 있게 되었지만,,  많이 아쉽네요..😭