[우아한테크코스 FE 5기] 프리코스 2주차 숫자 야구 미션 회고

Chex·2022년 11월 9일
0

우아한테크코스

목록 보기
2/19
post-thumbnail

⚾️ 숫자 야구 미션


🚀 기능 요구 사항

기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.

  • 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 낫싱이란 힌트를 얻고, 그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다.
    • 예) 상대방(컴퓨터)의 수가 425일 때
      • 123을 제시한 경우 : 1스트라이크
      • 456을 제시한 경우 : 1볼 1스트라이크
      • 789를 제시한 경우 : 낫싱
  • 위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 서로 다른 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한
    결과를 출력한다.
  • 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
  • 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
  • 사용자가 잘못된 값을 입력한 경우 throw문을 사용해 예외를 발생시킨후 애플리케이션은 종료되어야 한다.

입출력 요구 사항

입력

  • 서로 다른 3자리의 수
  • 게임이 끝난 경우 재시작/종료를 구분하는 1과 2 중 하나의 수

출력

  • 입력한 수에 대한 결과를 볼, 스트라이크 개수로 표시
1볼 1스트라이크
  • 하나도 없는 경우
낫싱
  • 3개의 숫자를 모두 맞힐 경우
3스트라이크
3개의 숫자를 모두 맞히셨습니다! 게임 종료
  • 게임 시작 문구 출력
숫자 야구 게임을 시작합니다.

실행 결과 예시

숫자 야구 게임을 시작합니다.
숫자를 입력해주세요 : 123
1볼 1스트라이크
숫자를 입력해주세요 : 145
1볼
숫자를 입력해주세요 : 671
2볼
숫자를 입력해주세요 : 216
1스트라이크
숫자를 입력해주세요 : 713
3스트라이크
3개의 숫자를 모두 맞히셨습니다! 게임 종료
게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.
1
숫자를 입력해주세요 : 123
1볼
...

🔗 관련 링크


🐾 기능목록

1. 게임시작 문구 출력하는 기능

2. 컴퓨터가 1부터 9까지 서로 다른 수로 이루어진 세 자릿수를 고르는 기능

3. 서로 다른 3자리의 수를 입력받는 기능

  • ‘숫자를 입력해주세요 : ‘ 문구 출력
  • (예외처리) 사용자가 잘못된 값을 입력한 경우 애플리케이션 종료
    • 1~9로 이루어진 숫자가 아닌 경우
    • 3자리의 수가 아닌 경우
    • 서로 다른 수가 아닌 경우

4. 입력받은 수에 대한 결과를 계산하는 기능

  • 같은 수가 같은 자리에 있으면 스트라이크
  • 같은 수가 다른 자리에 있으면 볼

5. 입력받은 수에 대한 결과를 출력하는 기능

  • 볼, 스트라이크 개수가 모두 0인지 판별하는 기능
  • 볼, 스트라이크 개수 출력
  • 하나도 없는 경우 ‘낫싱’ 출력

6. 3개 숫자를 모두 맞힌 경우 재시작/종료를 구분하는 1 또는 2를 입력받는 기능

  • 3개의 숫자를 모두 맞혔는지 판별하는 기능
  • ‘3개의 숫자를 모두 맞히셨습니다! 게임 종료’ 출력
  • ‘게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.’ 출력
  • (예외처리) 사용자가 잘못된 값을 입력한 경우 애플리케이션 종료
    • 입력값이 1 또는 2가 아닌 경우

7. 게임을 재시작하는 기능

8. 게임을 종료하는 기능

  • ‘숫자 야구 게임을 종료합니다.’ 출력
  • 애플리케이션 종료

🔎 후기

✅ 진행방식

  1. 개발환경: node.js v14.20.1, Visual Studio Code로 세팅하였습니다.
  1. 자바스크립트 코드 컨벤션Airbnb 자바스크립트 스타일 가이드를 참고하였습니다.
  2. 커밋 메시지 컨벤션커밋 메시지 컨벤션 가이드를 참고하였습니다.
  3. 기능을 구현하기 전에 기능목록을 만들었습니다.
  4. 문제의 요구사항 대로 기능 단위로 커밋하는 방식으로 진행했습니다.
  5. indent depth가 3이 넘지 않도록 구현했습니다.
  6. Jest를 이용하여 기능 목록이 정상 동작함을 테스트 코드로 확인하였습니다.

✅ 2주차 목표

  • 함수 분리하기(한 가지 일만 하도록 최대한 작게 만들기)
  • 각 함수별 테스트 작성에 익숙해지기

✅ 2주차 공통피드백

  • README.md를 상세히 작성한다.
  • 기능 목록을 재검토한다: 너무 세세하게X 구현해야할 기능 위주로O 예외적인 상황도 추가하기!
  • 기능 목록을 업데이트한다: 기능을 구현하면서 문서를 계속 업데이트 한다. 죽은 문서가 아니라 살아있는 문서를 만들자
  • 값을 하드 코딩하지 않는다: 문자열, 숫자 등의 값을 상수로 만들고 이름을 부여해 역할이 무엇인지 의도를 드러낸다.
  • 구현 순서도 코딩 컨벤션이다: 클래스는 필드, 생성자, 메서드 순으로
  • 한 함수가 한 가지 기능만 담당하게 한다
  • 함수가 한 가지 기능을 하는지 확인하는 기준을 세운다: 함수의 길이가 15라인이 넘어가지 않도록 구현하면 의식적인 연습을 할 수 있다.
  • JavaScript에서 객체를 만드는 다양한 방법을 이해하고 사용한다: JavaScript 객체 기본Classes 참고
  • 테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다
    - 기능 점검 + 나의 코드에 대해 빠르게 피드백을 받을 수 있음 + 학습도구로 활용
  • 처음부터 큰 단위의 테스트를 만들지 않는다

📖 배운점

1. 자바스크립트 코드 컨벤션 가이드에서 배운 것

  • 모든 참조에 const를 사용해라 var은 사용금지
  • ES6의 Property Shorthand(단축 속성명)? 객체의 keyvalue값이 같으면 한 번만 표기하는 것
  • 객체를 복사할 때 spread 문법 사용하기
  • Map함수를 실행하는 배열과 결과로 나오는 배열은 다른 객체이다.
    기존 배열을 수정하지 않고 새로운 배열을 만든다.(단, 객체가 들어있는 경우 객체는 공유된다.)
  • 여러 개의 값들을 리턴할 때 객체를 사용하면 좋다. (5.3번 참고)
  • 디폴트 값이 설정된 파라미터는 뒤로 보내라
  • 함수의 매개변수를 재할당하거나 바꾸지 말아라!!!
  • 공백 컨벤션도 참고(7.11번)
  • 하나의 식으로 구성된 함수의 경우 {}를 생략할 수 있다.
  • 메서드가 this를 반환하게 함으로써 메서드 체이닝을 할 수 있다.
  • 클래스 메서드는 외부 라이브러리나 프레임워크가 구체적으로 비정적 메서드를 요구하지 않는 이상 this를 사용하거나 해당 메서드를 정적 메서드로 만들어야 한다.
  • for-in이나 for-of 같은 루프 대신 자바스크립트의 고차함수를 사용하자. 고차함수는 불변규칙을 적용하기 때문! + 값을 반환하는 순수함수를 다루는 게 더 쉽다.
  • == 대신 === 사용하자.
  • 빈 배열 또한 true로 평가된다.
  • 마지막에 ,를 추가하자 더 깔끔하게 git diff를 확인할 수 있다.

2. 라이브러리 사용하기

  • MissionUtils 라이브러리를 사용하기 위해

       import * as MissionUtils from "@woowacourse/mission-utils";

    위 코드를 사용했더니 에러가 났다. importES6에서 도입된 키워드인데 알아보니 Node.js 에서 ES모듈을 사용하는 방법에는 2가지가 있었다.
    1. 파일 단위로 ES모듈을 적용
    파일 확장자를 js에서 mjs로 바꿔주면 importexport키워드를 사용할 수 있다. 하지만 이 방법은 파일의 확장자를 일일이 바꿔줘야하고 과제제출 시 위험할 것 같다고 생각했다.
    2. 프로젝트 단위로 ES모듈 적용
    프로젝트의 package.json을 열고 최상위에 type항목을 module로 설정한다. 이 방법 또한 프로그래밍 요구사항에 package.json을 변경할 수 없다고 나와있기 때문에 사용하지 못했다.

  • 그래서 결국 CommonJS방식으로 require키워드를 사용해서 모듈을 불러왔다.

  • 참고포스팅

3. 클래스의 정적메서드 사용에 관하여

  • 2주차 미션 종료 후 코드리뷰를 요청했는데 정적메서드에 관한 좋은 코멘트를 받을 수 있었다.
    2주차 미션 코드리뷰 요청
    2주차 미션 코드리뷰 코멘트
  • 숫자 야구 게임의 App클래스 안의 메서드들이 전부.. 특정 인스턴스가 아닌 클래스 전체에 필요한(공통적인?) 기능이라고 생각해서 static메서드로 작성했는데 클래스 내부에서 메서드들끼리 의존성을 갖고있다는 부분은 생각하지 못했다. 코멘트처럼 유효성검사를 위한 메서드들은 유틸 클래스를 만들고 static을 사용한다면 좋을 것 같다.

4. 테스트에 관한 것

  • 미션 수행 중 어떤 한 부분에서 계속 테스트 실패가 떴었는데 원인을 몇 시간 동안 찾다가 발견했다.
const logSpy = jest.spyOn(MissionUtils.Console, "print");
  • 위 코드를 보고 여기서 logSpyMissionUtils.Console.print()에 대한 테스트구나를 깨닫고 다시 내 코드를 살펴보니 "3스트라이크" "3개의 숫자를 모두 맞히셨습니다! 게임 종료"를 분리하지 않고 readLine에 "3스트라이크\n3개의 숫자를 모두 맞히셨습니다! 게임 종료"를 넣어서 사용하고 있었다. 출력은 요구사항과 똑같이 잘 되어서 문제를 발견하는 데에 정말 오랜 시간이 걸렸는데 지금 생각해보면 저 출력문들도 처음부터 상수로 분리해서 만들어줬으면 readLine에 통으로 넣지 않았을 것 같다. "3스트라이크"를 print에 추가했더니 테스트가 통과했다.

  • 문제를 통해 테스트코드를 더 뜯어볼 수 있었다. 만약 처음부터 다 통과했다면 테스트코드를 자세히 살펴보지 않았을지도.. 하지만 여전히 테스트에 대한 이해도는 높지 않다고 느낀다. 더 공부해봐야겠다!

✏️ 느낀점

2주차에는 깊은 몰입을 경험할 수 있었습니다. 다른 일정과 겹쳐 시간이 부족할지도 모른다는 생각에 자면서도 코딩하는 꿈을 꿨습니다.. 하루는 오전 5시반에 눈이 떠졌는데 오후11시까지 정말 밥만 먹고 코딩만 했던 것 같습니다. 신기하게도 몰입을 하니, 눈이 침침해지고 피곤하긴했지만 잠이 오지도 않았고 배도 고프지 않았습니다. 그리고 뭔가 제 자신이 멋지다고 생각했습니다. (몰입하는 나 자신!) 다음날 코드를 다시 확인해보니 확실히 실수한 부분도 많이 보였지만 정말 좋은 경험이었습니다.

2주차 미션에는 'JavaScript 코드 컨벤션 지키기'가 프로그래밍 요구사항에 들어가서 Airbnb 자바스크립트 스타일 가이드를 먼저 공부했습니다.

코드 컨벤션 가이드를 읽으면서 특히 '와 이건 대박이다!'싶었던 건 별거아닐지 모르지만
5.3 Use object destructuring for multiple return values, not array destructuring.
이 부분이었습니다.

여러 가지를 리턴할 때 배열이 아닌 객체로 넘겨주면 받을 때 인자의 순서, 개수 상관 없이 받을 수 있어서 편리하게 쓸 수 있다는 내용인데 그동안 저런 경우에 코드를 위 아래로 학인하면서 순서를 확인하고 맞추느라 불편했던 경험이 있었기 때문에 저 내용을 읽었던 때가 저에겐 큰 깨달음의 순간이었습니다.

7.7 Use default parameter syntax rather than mutating function arguments.

이 부분에서는, '함수 매개변수를 변경하는 건 내가 1주차 때 했던 행동인데..'하면서 읽다가 really bad의 예시로 나와있어서 정말 찔렸습니다. 하하.

7.11 Spacing in a function signature. eslint: space-before-function-paren space-before-blocks
19.1 Use soft tabs (space character) set to 2 spaces. eslint: indent
19.2 Place 1 space before the leading brace. eslint: space-before-blocks
19.3 Place 1 space before the opening parenthesis in control statements (if, while etc.). Place no space between the argument list and the function name in function calls and declarations. eslint: keyword-spacing
19.10 Do not add spaces inside parentheses. eslint: space-in-parens
19.11 Do not add spaces inside brackets. eslint: array-bracket-spacing
19.12 Add spaces inside curly braces. eslint: object-curly-spacing

괄호 안에 공백을 넣거나 function키워드에 공백을 넣는 것은 1주차 때에도 고민을 했던 부분인데 이렇게 코드 컨벤션의 항목으로 나와있어서 다 비슷한 고민을 하는구나라고 생각했습니다.

7.12 Never mutate parameters
7.13 Never reassign parameters. eslint: no-param-reassign

그밖에도 함수의 매개변수를 재할당하거나 바꾸지말라는 비슷한 의미의 코드 컨벤션이 계속 나왔는데 이것을 보면서 '1주차 떄 정말 반성해야할 짓을 많이 했구나'라고 생각했습니다.. (사실 1주차 때 코드를 작성하면서도 조금 찝찝했습니다..)

그저 코드 컨벤션 가이드 문서를 읽었을 뿐인데 많은 것을 배우고 얻어갈 수 있었고 지난 제 코드에 대해 반성하게 되었습니다. 코드를 작성할 떄 한번 더 생각하고 고민하게 되는 계기가 된 것 같습니다.

2주차 미션의 목표는 함수를 분리하고 함수별 테스트 작성에 익숙해지는 것이었는데요.

최대한 작은 기능으로 함수를 분리하기 위해 인풋값의 유효성검사를 하는 작은 부분까지 함수로 분리하려고 노력했습니다. 그리고 이러한 함수분리는 테스트코드 작성 시에 진가를 느낄 수 있었습니다. 아주 작은 기능으로 함수를 분리했기 때문에 테스트코드 작성 시에도 테스트하고자하는 바가 명확했고 '아 이래서 함수는 한 가지 일만 해야하는 거구나'를 또 깨달았습니다.

이번 주차도 진행하면 할수록 부족한 부분이 무엇인지 알 수 있었던 한 주였던 것 같습니다. 테스트코드에 대해 더 공부해야하고 그리고 자바스크립트의 비동기로직에 대한 이해가 더 필요하다는 것을 느꼈습니다. 그리고 처음 구현 시엔 App클래스 하나에 모든 코드를 다 넣어놨었는데 유효성검사를 하는 함수들이 많아져서 ValidationCheck라는 클래스를 만들어 분리해보면서 어떨 때 클래스를 분리할지, 클래스를 분리하는 기준에 대해서도 고민해보아야겠다고 생각했습니다. 프리코스를 진행하면서 매주 주어진 과제만 수행해도 크게 성장함을 느낍니다.

그리고 2주차 때 처음으로 피어리뷰를 해보았는데 코드리뷰를 하는 것과 받는 것 모두 많은 것을 배울 수 있다는 것을 느꼈습니다. 다른 지원자분들의 코멘트를 보고 이렇게 구현할 수도 있구나하면서 정말 감탄을..금치 못했습니다. 코드 여러 줄이 깔끔하게 1줄로 바뀌는 것을 보고 놀라기도 하고 static 메서드 사용에 대한 의견을 주고 받으면서 더 배울 수 있었습니다. 하루하루 성장하는 느낌이 정말 즐거운 것 같아요. 3주차도 행복한 코딩이 되기를!🌝


Be the best version of you!

profile
Fake It till you make It!

0개의 댓글

관련 채용 정보