[우아한테크코스 5기 프리코스] 2주차 후기

96프로지망생·2022년 11월 17일
0

숫자야구게임을 만들어보자

https://github.com/ilgon0110/javascript-baseball/tree/ilgon0110

2주차 의도사항
1. 테스트 도구에 익숙해지자 : TDD같은 키워드로 검색
2. 더 빠르게 피드백을 받자
(기능 목록을 작게 쪼개면, 테스트 작성하기도 쉽다.)
3. 남은 테스트 코드도 큰 자산이 된다.
4. 테스트 코드 얼마든지 추가해도 된다.

eslint와 prettier 설정

Quick Set up Eslint with Airbnb Style Guide.

요구사항에 명시되어 있는 JavaScript 코드 컨벤션을 지키기 위해 eslint와 prettier를 JS airbnb 컨벤션에 맞게 설정했다. 작성하고 컨벤션을 지켰나 확인하는 것보다 이미 많은 사람들이 쓰고있는 linter를 사용해 개발환경에서 컨벤션을 강제하는 것이 훨씬 편하다고 생각한다. package.json을 변경하지 말라고 했으니 package 관련 푸시는 하지 않았다.

Class…?

javascript를 쓰면서 class를 애써 무시해왔다. React를 공부할 때 class component를 사용했지만, 얼마 뒤 useState()useEffect()가 출시되고 함수형 컴포넌트로 넘어가서 사실상 다 까먹었다. 기능 요구사항을 작성하긴 커녕 VS Code를 열면 무엇을 해야 할 지도 모르는 상태. this? constructor? 다 들어봤지만 제대로 사용해본 적은 없는 것들이다. 기본기 부족을 느꼈다.
모던 자바스크립트 딥다이브 책을 읽으면서 감을 잡았다. 부족한 부분은 다른 지원자들이 어떻게 생성자와 메서드를 사용했는지를 보면서 공부했다. 함수형 컴포넌트로 바꿔 진행한 지원자들도 꽤 있었지만, 문제에서 Class로 주어진 김에 Class로 하고 싶었다.

기능 구현 목록 작성

우테코에선 문서작성을 굉장히 강조한다. 문서를 작성하고 문서에 맞게 개발을 진행하는 프로세스를 요구하고 있다. 이런 경우 문서 작성에 너무 매몰되어 개발을 체계적으로 진행하기 위해 문서의 도움을 받는 것이 아닌 문서를 지키기 위한 개발이 되어버릴 수가 있어 주객전도가 되지 않기 위해 조심했다. 다음은 2주차 공통 피드백 때 우테코 코치 Jun님이 하신 조언이다.

⚒️ 기능 목록 작성 Tip(by Jun)
1. 일단 최대한 작게 쪼개봐라(최대한 빠르게 피드백을 받을 수 있을 만큼)
2. 그 다음 이정도까진 묶어도 되지 않을까..?그 단위로 묶어보자.
3. 가장 핵심 요구사항부터 작게 쪼개보자.(MVP기능부터 만들자)
4. 커밋 - 여러분이 읽어 봐라. 이해가 되냐? 그럼 좋은 커밋이다.(사람이 읽고 이해하기 위해 커밋을 작성하는 것)

⛔ 요구사항이 불분명하다.(의도한 것)
예외처리를 직접 만들고, “소프트웨어라면 이래야 한다!” 라는 생각으로 본인이 직접 생각하여 최대한 예외사항을 구현해봐라
(1주차에는 입력값이 제한사항을 적용했다고 판단. 그게 아니였군…앞으로는 예외처리에 엄청 신경써야 할 듯)
요구사항을 직접 분석하고 예외처리를 스스로 만드는 것이 프리코스의 제 1의 목표같다.

다음은 내가 작성한 기능 구현 목록이다.

MVP 기능

  • 상대방(Computer)의 Random 숫자 만들기
  • User의 입력값 받기
  • User와 상대방(Computer)의 숫자 비교하기
  • 게임이 끝날 시 다시 시작하거나 끝내는 선택창 출력하기

[x] 1. 상대방(Computer)의 Random 숫자 만들기

예외처리

  • 숫자가 아닌 경우
  • 각 숫자가 1~9 범위가 아닌 경우
  • 값에 중복된 숫자가 있는 경우
  • 길이가 3이 아닌 경우

기능구현

  • Missionutils를 사용해 Randow 숫자 생성

[x] 2. User의 입력값 받기

예외처리

  • 입력된 값이 숫자가 아닌 경우
  • 입력된 값의 각 숫자가 1~9 범위가 아닌 경우
  • 입력된 값에 중복된 숫자가 있는 경우
  • 입력된 값이 3개의 숫자가 아닌 경우
  • 입력된 값에 공백이 있을 경우

기능구현

  • Missionutils를 사용해 입력값 받기
  • 입력값이 들어올 때 까지 다음 단계로 넘어가지 않기

[x] 3. User와 상대방(Computer)의 숫자 비교하기

기능구현

  • Strike: User의 숫자들과 상대방(Computer)의 숫자의 값이 같고 같은 자리에 있을 경우
  • Ball: User의 숫자들과 상대방(Computer)의 숫자의 값이 같고 다른 자리에 있을 경우
  • 낫싱 : User의 숫자들과 상대방(Computer)의 숫자들이 모두 동일하지 않은 경우
  • 알맞은 출력값을 출력해 준 후 2번 상태로 돌아가 다시 입력 받기

[x] 4. 게임이 끝날 시 다시 시작하거나 끝내는 선택창 출력하기

예외처리

  • 1 2 이외의 다른 입력이 들어오는 경우

기능구현

  • 안내문구와 함께 선택창 출력하기
  • 1번을 입력받을 경우 프로그램 다시 시작하기
  • 2번을 입력받을 경우 프로그램 종료하기

Jest와 친해지자

‘테스트 도구와 익숙해지자.’ 가 무슨 말인지 알겠다. Jest를 이용해 CLI에 메시지를 띄우고, input을 받고, 그 input에 알맞는 output을 나타내고, 다 끝났을 시 다시 시작하는 테스트 환경을 만들어야 했다. 1주차에선 그냥 npm test하면 끝이였는데, 이번 과제에 핵심은 Jest에 대한 이해다.

목-금 내내 헤매는중.
내 생각은 터미널에서 npm test를 입력하면 사용자가 터미널에 숫자를 입력하고, 그 숫자에 맞는 답이 출력되는 것이 반복되야 한다. 근데 도대체 어떻게…? npm test치면 에러가 나던 말건 그냥 테스트가 진행되고 숫자를 입력하는 행위는 할 수가 없다. 구글링에서 해답을 얻는데 실패하고 다른 지원자들의 코드를 복붙해와서 npm test를 입력하고 있지만, 사용자가 입력할 수 있는 테스트는 나오지 않는다. 이게 아닌가..?

Jest와의 싸움 종료

목~일동안 로직은 만들지도 못한 채 테스트코드를 이해하려고 노력했다. 일단, 사용자가 콘솔에 숫자를 입력하는 테스트는 말이 안 된다는 것을 동기에게 물어보고 나서야 이해했다. 질문 자체를 이해 못하는 동기를 보면서 ‘단단히 잘못 왔구나’를 단번에 느낄 수 있었다. Application.js에 있는 테스트 코드를 이해하려는 노력이 부족한 내 불찰이였다. 다시 찬찬히 코드를 살펴보기 시작했다.

이번 과제에서 제일 중요한 것은 mockQuestionmockRandom함수를 이해하는 것이라고 생각한다. 1주차 과제에선 테스트 코드를 이해할 필요가 없었기에(함수명만 봐도 이해되기도 했고) 이번에도 그러려니 했지만, 전혀 아니였다. mockspyOn이 뭔지, 어떤 기능을 하는지 꼭 알아야 테스트 코드를 이해할 수 있었고, 그래야만 터미널에 값을 입력해서 테스트한다는 말도 안되는 생각에서 벗어날 수 있었다. 혹시 나와같은 생각을 하며 이 글을 읽고 있다면 당장 나가서 mockspyOn 관련 문서를 읽도록 하자.

mockQuestion 함수는 터미널에서 User의 숫자를 입력받는 함수를 mock하여 사용자의 입력값을 answer의 값으로 만들어주는 테스트 코드였다. Mission.Console.readline 함수가 있으면 그 함수를 mocking 하여 테스트 환경에서 마치 Console.readline처럼 구동되는 함수였다.

const mockQuestions = (answers) => {
  MissionUtils.Console.readLine = jest.fn();
  answers.reduce((acc, input) => {
    return acc.mockImplementationOnce((question, callback) => {
      callback(input);
    });
  }, MissionUtils.Console.readLine);
};

const answers = ["246", "135", "1", "597", "589", "2"];
mockQuestions(answers)

//사용자가 246 -> 135 -> 1 -> 597 -> 589 -> 2 순서로 입력하는 테스트이다.

mockRandom 함수는 Computer가 Random한 숫자를 만들어내는 함수를 mock 하여 Computer의 값을 random 배열의 값으로 만들어주는 테스트 코드였다. MissionUtils.Random.pickNumberInRange 함수가 있으면 그 함수를 mocking 하여 테스트 환경에서 Random.pickNumberInRange처럼 구동되는 함수였다.

const mockRandoms = (numbers) => {
  MissionUtils.Random.pickNumberInRange = jest.fn();
  numbers.reduce((acc, number) => {
    return acc.mockReturnValueOnce(number);
  }, MissionUtils.Random.pickNumberInRange);
};

const randoms = [1, 3, 5, 5, 8, 9];
mockRandoms(randoms);

//Computer의 숫자가 135 -> 589 인 테스트이다.

솔직히 mockspyOn을 제대로 이해했냐고 물어보면 아니다. 특히 mockRandom 함수는 이게 왜 135가 됐다가 답을 맞추면 589가 되는지 모르겠다. 이번 단계에서 내 최선은 ‘mockspyOn을 이해하고 원래 테스트 코드 없이도 테스트 코드를 작성할 수 있다’가 아니라, ‘원래 작성된 테스트 코드가 어떤 결과가 나오는지는 이해했다’ 수준이였다. 백지에서 작성하라고 하면 절대 못했을 것이다. Jest라는 벽을 만난 기분..

느낀 점

Jest를 이해하는 것이 제일 큰 난관이였다. 리팩토링 관련 책과 강의도 구매한 터라 빠르게 로직을 작성하고 책과 강의를 보면서 리팩토링에 열을 올리고 싶었는데, Application.js를 이해하는 데 이번 주 과제시간의 70%를 소비한 것 같다. 처음 파일을 열어보고 mock, spyOn, mockReturnValueOnce, mockImplementationOnce… 생소한 함수들이 많아 일단 넘어가고 로직부터 짤까? 했지만 TDD방법론을 생각하며 테스트 코드에 익숙해지라는 코수타 준님의 피드백을 생각하며 기능 목록마다 테스트 코드를 실행해보는 방식으로 과제 진행 방식을 정했다. 그 다음 사용자 입력값 테스트 코드를 작성하면서 ‘터미널에서 입력을 직접 받는 것이구나. 어떻게 사용자 입력을 테스트하면서 받을 수 있지? ’라는 생각이 머리를 사로잡은 것이 이번 과제 최대의 실수였다. 처음에Application.js에 있는 코드들을 제대로 이해하려고 하지 않으려고 했기 때문에 발생한 불찰이다. 조급해하지 말라고 우테코는 항상 강조하지만, 그렇지 못했었던 것 같다. 그리고 커밋 메시지에서 (#1) , (#2) 로 기능 구현 목록을 구별했더니 다른 지원자들의 PR과 하이퍼링크가 걸린다. 이렇게 하면 안되는구나.

feat: 상대방(Computer)의 랜덤 숫자 생성 기능 구현 (#1)
이렇게 하면 안됩니다. 다른 지원자들의 PR링크가 걸림.

그래도 실전에 직접 던져놓고 이것 저것 부딪히게 만드는 프리코스의 학습 방식이 마음에 든다. 처음에는 정말 망망대해에 떨어진 것 같지만, 해결책의 실마리를 찾고 하나 하나 쌓아나가는 모습을 보면 굉장히 뿌듯해진다. 요구사항도 불분명하다고 했지만, 아직까진 완성된 테스트 코드를 제공해주는 것도 그렇고 꽤나 친절하다고 생각한다. 다음 과제가 두려우면서 기대된다. 파이팅!

0개의 댓글