활동내역.zip/개인

<우아한테크코스 2024 프리코스> 1주차 후기: 숫자야구게임, 그런데 객체로 만든다고?

TMInstaller 2023. 10. 26. 00:01
728x90

이 포스팅은 회고 겸 TroubleShooting 겸 한 주 간의 고민과정을 모두 정리해둔 글임을 알립니다

Visit GitHub Repository


프리코스가 그렇게 유명하다던데?

지난 번 Software Maestro에 도전했던 올해 초가 기억나는 시작이다.
이번에는 가장 인지도가 높고 성장하기에 특화되어있는 교육 프로그램인 <우아한 테크코스 2024>에 합류하기 위한 단계인 <프리코스>에 도전하기로 했다. 사전 과제를 통한 평가단계이고, 과제전형이기에 그냥 과제만 풀고 끝이 아닐까 싶겠지만 지난 5기때의 많은 후기들, 검증된 몰입할 수 있는 과제들이 이 자체에 참여하는것만으로도 많은 도움이 될 것이라는 신호를 보내고 있었다.
유명한 데에는 다 이유가 있었다. 1주차를 마친 나 또한 이 프리코스가 왜 유명한 지 일부나마 이해할 수 있었으며, 지금부터 1주차를 마치며 그 내용을 정리하려고 한다.


첫인상

수업 후 집에가는 길에 프리코스 OT를 들으며 집으로 돌아온 후 노트북을 열었다. 도착한 메일을 열고, 프리코스 레포에 접속하여 초기 클론을 받았다. "숫자 야구 게임", 처음 코딩을 시작한다 하면 거의 모두가 이 알고리즘을 만들어보고 프로그래밍에 대한 재미를 붙이기 시작하곤 한다. 나 역시도 20살 때 처음 자바를 이용하여 이걸 만들어 본 경험이 있어서 그런지 기분이 묘했다. 다시 처음 하는 기분으로 이걸 시작할 수 있다? 난 더 좋다는 마인드로 요구조건에 대한 간단한 사용자 플로우를 다이어그램으로 제작하고 코드를 작성하기 시작했다.

몇 번 수정하고 나니 생각보다 볼만 한 다이어그램이 나왔다.


처음 써보는 클래스 형태의 자바스크립트

요구조건은 이제 알겠어, 그런데 객체로 코드를 짜야하네?

그동안 웹개발에 입문하고 프론트엔드로 활동하며 React, Next.js 등을 써보았고, 거기에서 사용되는 함수형으로만 프로그래밍을 해 보았다. 간혹 검색할 때 옛날 코드에서 객체 형태로 코드가 짜여져 있다면 그냥 넘어가곤 했는데.. 이제는 반대로 그런 코드들을 참고해서 프로그래밍을 해야한다고? 처음에는 막막했다. 어떻게 실행시키는 지 찾는 데에만 해도 1시간 정도가 걸렸으니 정말 먼 길을 걸어가겠구나 싶었다.

하지만 그동안 해왔던 것이 허수는 아니었다!

말 그대로이다. 그래도 그동안 함수형에 대해 얼마나 많은 의문을 가졌었고, 이를 문서화하며 궁금증을 풀었는지 모르겠다. 그래서 그런가 이 둘 사이의 공통점을 찾았고, 몇 가지 깨달음을 얻을 수 있었다.

  1. 클래스와 함수형, 근본적으로 이 둘 안에 코드를 작성하는 방식은 크게 다르지 않다.
    • 이 부분은 내가 한 클래스 내에서 모든 코드를 구현해서 그런 것일수도 있다.
  2. 메서드에서 인자를 받아오는 것과 함수에서 인자를 받아오는 방식은 비슷하다.
  3. 메서드와 함수 내부에 JS 코드를 작성하는 방식은 거의 비슷하다.

일단은 이런 공통점이 있었고, 객체의 this가 무엇을 의미하는지도 알 수 있었다.

class의 this는 지금 현재 위치하고 있는 클래스를 의미하는구나!

예를들어 App 클래스 내부에서 this.method()를 통해 메서드를 호출하면 여기서 this는 App을 의미하게 되는 것이었다. 이렇게 한 번 경험해본다고 바로 이해된다니! 정말 뿌듯했다. 직접 써보면서 부딪히는 것만큼 이렇게 효과가 좋은 건 없을 것이다 싶었다.


순조로운 로직 설계

와 나 이거 3시간만에 끝내는거 아니야?

라고 생각했었다. 로직을 설계할때까지는 말이다. 전부터 기초적인 코딩 테스트 연습은 해왔다 보니 기초적으로 로직을 짜는 것은 문제가 없었다. 클래스를 실행시켜 돌려보았을 때에도 로직 자체는 제대로 돌아가는 것을 보고 "와 나 천재다" 라고 생각했었는데, 그 생각은 예외처리와 테스트코드를 돌리기 시작하면서부터 산산조각이 났다.


하지만 예외가 있었죠

누구나 다 그럴싸한 계획은 가지고 있다. 테스트를 돌려보기 전까진 말이다.

사실 말은 이렇게 했지만 테스트를 위한 예외 코드를 짜는 것 까지도 괜찮았었다. 그 과정에서도 throwtry/catch 가 어떻게 작동하는지에 대해 이해할 수 있기도 했고 배움도 많았지만 그래도 2일 이상 소요되는 과정은 아니었다. 10개가 안되는 메서드들을 통해 모두 구현을 하고 몇 번의 자체적인 테스트에서 잘 통과하는 것을 확인했을 때 나는 기뻐했다. 내 야구게임이 드디어 완성되었다!

재귀적인 호출이 테스트코드 순서를 변경한다고..?

하지만 예외가 있었죠. 잘 돌아가야만 하던 테스트코드에 예상과 다르게 입력되어야 할 값이 아닌 다른 값이 들어가는 일이 발생했다. 로그를 통해 확인하고, 이를 고치면서 이는 재귀적으로 호출이 될 때 이렇게 꼬이는 현상이 나타난다고 한다는 것을 알았다. 정말 놀라웠지만 생각해보니 전에도 코딩테스트 연습을 하면서 이런 일이 있었던 것 같아서 기분이 묘했다. 이 부분을 알아내기 위해 테스트코드 자체를 뜯어보면서 어떤식으로 동작하는지에 대해서도 익힐 수 있던 것을 보면 왜 프리코스에서 혼자 해결해야한다고 말했는지 알 것 같았다. 특정 문제 하나를 고치기 위해 많은 것들을 얻어가는 이런 경험은 흔하지 않은데, 뭔가 느낌이 좋다.


가장 오래걸렸던 '그 오류'

지금 보고있는 이 오류는 기간동안 풀어낼 수 없었다. 아직도 궁금하다.

분명 모든 테스트케이스, 예외처리는 정상적으로 작성되었고, 'npm test' 를 통해 Jest 환경에서 테스트를 했을 때 모든 케이스에 대한 pass가 출력되면서 잘 작성된 로직인것만 같았다. 하지만 계속해서 같은 오류가 테스트 완료 이후 발생하면서 다양한 시도를 할 수 있는 시간이 있었다. 그리고 그 오류는 아래와 같다.

Jest did not exit one second after the test run has completed.

'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.

"당신의 비동기적인 작업들이 테스트에서 멈추지 않았다." 라는 내용의 메시지로, 이를 해결하기 위해 아래와 같은 가설들을 세울 수 있었다.


가설: 이래서 테스트가 끝나지 않은 것일까?

  1. 현재 사용자의 입력을 받는 Console 라이브러리(프리코스용 커스텀 라이브러리)가 닫히지 않아 문제가 발생하였을 것이다.
  2. while(true){}, 재귀 호출 등 무한반복이 사용되었기에 특정 조건에서 탈출되지 않은 상태로 테스트가 끝났을 것이다.
  3. 예외처리가 일부 제대로 처리되지 않았지만 테스트에서는 정상적으로 처리되는 특수한 상황일 것이다.

여러 가설들을 세울 수 있었고, 이를 위해 해결하기 전에 우선 메서드 이름을 더 깔끔하게 정리하고 가고 싶었다.
그래서 기존의 구간별로 메서드를 다시 만들고 이름들을 다음과 같이 설정하였다.

  1. 시작 멘트: systemStartMent
  2. 야구게임 무작위 정답 생성: systemGenerateRandomAnswer
  3. 사용자의 정답 입력: userInputAnswer
  4. 사용자의 정답에 따른 결과 출력: systemCheckAnswer
  5. 야구게임 재시작/종료 여부 입력: userSelectRestartOrQuit
  6. 입력된 여부에 따른 시스템 처리: systemRestartOrQuitProcess

시스템, 유저의 행동임을 이름만 보고도 읽을 수 있게 바꾸었고, 전보다 메서드명이 길어지긴 했지만 가독성이 더 좋아져서 코드를 수정할 때 더 빠르게 인식할 수 있어서 좋았다.


가설검증

그래서 위 3가지의 큰 카테고리의 가설을 검증하기 위해 나는 여러 시도를 해보았다. 그리고 아래에 적는 것들은 그 생각과정을 담아두었다.

  1. 현재 사용자의 입력을 받는 Console 라이브러리(프리코스용 커스텀 라이브러리)가 닫히지 않아 문제가 발생하였을 것이다.
    1. 우선 제공하는 라이브러리 코드가 어떤 것인 지 확인해보아야겠다
    2. 비동기적으로 사용자의 입력을 처리하는 코드가 있네? 이게 닫히지 않았던 것일까?
    3. readline이 닫히지 않는 것이 원인이라면 여기에 닫는 메서드를 추가하면 해결되겠다!
    4. 라이브러리는 수정하면 안될 것 같으니 App.js로 들고와서 확장해서 만들어보자!
    • 하지만 이 시도는 어떤 효과를 보았는지 알 수 없었다. 테스트 시간이 약간 길어진 것 외에는 동일한 오류를 출력했기 때문이다.
  2. while(true){}, 재귀 호출 등 무한반복이 사용되었기에 특정 조건에서 탈출되지 않은 상태로 테스트가 끝났을 것이다.
    1. 간혹 이 while 문이나 재귀 호출 등 반복적으로 돌아가는 로직으로 인해 종료되지 않는다는 사실이 검색하다보니 종종 보이는 것 같아
    2. 이 while문, 재귀 호출을 모두 없애면 해결되지 않을까?
    • 하지만 특정 조건에 의해 구간반복이 필요한 이 야구게임의 특성 상 둘 다를 모두 없애는 방법을 찾을 수는 없었다. 재귀의 경우 완전히 외부로 나갔다가 다시 호출하면 되지 않을까 싶었지만 어림도 없었다.
  3. 예외처리가 일부 제대로 처리되지 않았지만 테스트에서는 정상적으로 처리되는 특수한 상황일 것이다.
    1. 예외처리가 안되어서 될 만한 부분이 있었던가?
    2. 반복문에서 나갈 때 어떤 로직이 추가로 필요했는 지 알아보자!
    • 하지만 이미 반복문을 탈출하는 명확한 조건을 적어두었다고 생각했던 나는 그 해답을 찾지 못했다.

이런 과정들을 거쳤지만 결국 해결하려는 문제에 대해서는 알아갈 수 없었고, 이후에도몇몇 도전들을 해나갔다.

  • 테스트는 총 2개로 test 2에서 종료되지 않은 것이라면, 이 test 2의 내용이 지정된 문자열의 길이를 넘겨 출력했을 때 에러를 핸들링하는 과정에서 무언가 문제가 있어서 종료되지 않은 것일까?
    • 결국 에러 핸들링 후 프로그램이 제대로 종료되지 않아 발생하는 문제일 것이므로 이 부분을 수정해보자.
  • play() 메서드 내부에서 try/catch문을 Promise를 호출하도록 변경하기
    • try문에 resolve()를, catch문에 reject(e)를 넣어 출력해보았지만 결국 같은 에러로 원점화

그렇게 전부 시도했음에도 해결되지는 않았고, 어느덧 제출기간이 되었다.


마치며: 이제는 정리해볼 시간!

아무래도 다른 사람들의 PR이 올라오는 시간인 만큼 더 이상 기존 과제 branch의 코드는 수정하지 않고 새로운 브랜치를 만들어서 거기서 한을 풀어봐야겠다

제출기간은 총 2일, PR을 올리고 지원 사이트에 과제를 제출하면 끝나는 마지막 단계에 돌입했다. 지정된 양식에 맞게 PR을 보내고, 사이트에 소감과 함께 제출을 하였고 테스트를 실행했다. 오류가 떠있어서 통과하지 못하는 것이 아닐까 걱정이 되었지만 정말 다행히 모두 통과하면서 잘 마무리가 되었다. README 정도만 업데이트를 간단히 하고 코드는 손대지 않을 생각으로 제출을 완료하니 뭔가 뿌듯했다.

그리고 했던 일은 다른 사람들이 올린 코드를 구경해보는 일이었다. 커뮤니티와 오픈톡방 등에서 사람들이 "이렇게 작성하고 있어요" 라는 말을 듣고 내심 궁금했던 차 구경을 해보았더니 놀라지 않을 수 없었다.
코드를 체계적으로 분리하고, 파일을 잘 나눠두고, 객체에 문자열들을 모아서 관리하고, 몇 명 안본 것 같은데도 거의 다 다른 방식으로 잘 작성되어있었다. 나는 그저 한 파일에 모든 코드를 넣어두고 문제해결하기에 바쁘게 보냈던 것 같은데, 이런 식으로도 코드 구조가 만들어질 수 있구나 깨달았다.


마치며: 그래서 이제 뭐할꺼라고?

이 모든 일이 그저 코딩 입문이라고 볼 수 있는 숫자야구게임 하나에서 일어났다. 역시 프리코스다 싶었고, 다음 과제는 어떤 것이 나올 지 기대가 되기 시작했다. 이제 제출기한이 끝나기 전까지 후기 작성을 마치고 이 글이 올라가는 26일 00시 이후에는 PR, 코드리뷰 등을 통해 내 코드를 돌아보고 앞으로 나아갈 것이다.


End

728x90