
1주 차 미션은 숫자 야구 미션입니다.
우선 읽어야 할 내용이 많아서 README를 읽었습니다.
미리 생각해놓아야할 내용은 컨벤션이 였습니다.
프리코스에서 프로그래밍할 때 JavaScript 코드 컨벤션을 지켜야 하며 기본적으로 Airbnb 자바스크립트 스타일 가이드를 기준으로 한다고 합니다.
이후 GitHub을 활용한 제출 방법에 관한 내용을 읽고 Fork와 Clone을 하였고 깃헙 닉네임으로 브랜치를 만들었습니다.
진행 방식에 기능을 구현하기 전 docs/README.md에 구현할 기능 목록을 정리해 추가하고 나와있었습니다.
README 작성이 서툴어 다른 사람들은 어떻게 하였나 찾아봤는데 처음부터 기능목록을 완벽하게 작성하는 것은 힘들기 때문에 중간중간 변해가 된다는 글을 보고 당장 생각나는 것 부터 적었습니다.
1주차에서 신경 썻던 것은 크게 보면 아래의 4가지가 있었습니다.
구현할 기능 목록 작성
우테코 제공 라이브러리
게임의 진행과 종료 방법
우테코 제공 jest test 통과
@woowacourse/mission-utils의 Console API를 사용하여 입력값 받기Console.readLineAsync 사용throw문을 사용하여 예외 발생@woowacourse/mission-utils의 Random API를 사용하여 Random 값 추출@woowacourse/mission-utils의 Console.print를 사용하여 출력우테코의 README 요약같은 느낌으로 작성했습니다.
기능을 구현할 때 우테코에서 제공하는 라이브러리 사용하라는 안내가 있었습니다.
이외에 별다른 설명이 없어서 많이 당황스러웠습니다.
어떤 라이브러리인지 확인하기 위해 node_modules에 들어가서 파일을 찾았습니다.
Console.readLineAsync()는 인자에 입력받기 전 메시지를 전달하면 메시지 출력과 입력 받기를 하는 기능을 가졌습니다.
// node_modules/@woowacourse/mission-utils/src/console.js
static readLineAsync(query) {
return new Promise((resolve, reject) => {
// 조건에 충족되지 못하면 reject
if (arguments.length !== 1) {
reject(new Error("arguments must be 1"));
}
if (typeof query !== "string") {
reject(new Error("query must be string"));
}
const rl = readline.createInterface({
input: process.stdin,
// 터미널의 입력을 읽습니다.
output: process.stdout,
// 터미널에 출력합니다.
});
// question 메서드는 query를 터미널에 출력하고 터미널에 입력한 데이터가 input으로 전달됩니다.
rl.question(query, (input) => {
rl.close();
// 조건에 충족됐다면 resolve에 input을 넘깁니다.
resolve(input);
});
});
}
정답을 맞출 때 까지 게임을 종료하지 않고 입력을 받아야 했습니다.
while문과 재귀 중 재귀함수로 구현을 했는데 while문이 더 나았을 것 같습니다.
async runGame(answer) {
try {
const userGuessInput = await this.getUserInput();
inputValidator(userGuessInput);
const result = this.compareNums(userGuessInput, answer);
this.printResult(result);
if (result.strike === MAGIC_NUM.MAX_BASEBALL_NUM) {
return this.getRestartInput();
}
// result.strike가 3이 아닐 경우 runGame 매서드를 재귀함수로 실행
this.runGame(answer);
} catch (error) {
throw error;
}
}
게임 종료를 가장 먼저 생각했을 때 process.exit() 가 떠올랐습니다.
하지만 프로그래밍 요구사항에서 process.exit()를 사용하지 말라는 안내가 있었습니다.
그래서 정상 종료 시에는 이후 실행될 코드를 작성하지 않아서 종료하게 만들었고, 잘못된 입력으로 인한 종료 시에는 throw new Error()을 통해 종료하였습니다.
코드 기능을 구현하고 우테코에서 제공해준 jest의 test를 실행했는데 통과되지 않았습니다.
처음부터 잘해보려고 아는 지식 모두 끌어 코드를 복잡하게 작성했더니 거대해진 코드에서 실패의 원인을 찾는데 찾아지지 않아, 이부분에서 가장 많이 고생했습니다.
결국 코드를 가장 간단한 모양으로 다시 작성했습니다.
> javascript-baseball@1.0.0 test
> jest
console.log
숫자 야구 게임을 시작합니다.
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
숫자 야구 게임을 시작합니다.
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
246
at BaseballInput.log (src/BaseballInput.js:18:15)
console.log
낫싱
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
135
at BaseballInput.log (src/BaseballInput.js:18:15)
console.log
3스트라이크
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
3개의 숫자를 모두 맞히셨습니다! 게임 종료
게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
597
at BaseballInput.log (src/BaseballInput.js:18:15)
console.log
1볼1스트라이크
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
589
at BaseballInput.log (src/BaseballInput.js:18:15)
console.log
3스트라이크
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
3개의 숫자를 모두 맞히셨습니다! 게임 종료
게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
숫자 야구 게임을 시작합니다.
at Function.value (node_modules/@woowacourse/mission-utils/dist/mission-utils.cjs:1:4763)
console.log
1234
at BaseballInput.log (src/BaseballInput.js:18:15)
RUNS __tests__/ApplicationTest.js
/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:51
throw new Error("[ERROR] 확인1");
^
Error: [ERROR] 확인1
at BaseballInput._callee$ (/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:51:21)
at tryCatch (/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:10:1062)
at Generator.<anonymous> (/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:10:3012)
at Generator.next (/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:10:1699)
at asyncGeneratorStep (/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:11:103)
at _next (/Volumes/projects/woowacourse/6th/javascript-baseball-6/src/BaseballInput.js:12:194)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
원인은 두 가지 였습니다.
첫 째는 '볼'과 '스트라이크' 사이 띄어쓰기의 부재 였습니다.
// 문제의 코드
printResult({ ball, strike }) {
if (ball || strike) {
Console.print(
(ball ? `${ball}볼` : '') + (strike ? `${strike}스트라이크` : ''),
);
} else Console.print(INFO_MESSAGE.NOTHING_MESSAGE);
}
// 해결된 코드
printResult({ ball, strike }) {
if (ball || strike) {
Console.print(
(ball ? `${ball}볼 ` : '') + (strike ? `${strike}스트라이크` : ''),
);
} else Console.print(INFO_MESSAGE.NOTHING_MESSAGE);
}
차이가 보여지시나요?
${ball}볼 다음 띄어쓰기를 추가하니 통과되었습니다.
이 문제로 3일간 코드를 엎었는데, 고생을 너무 해서 앞으로 이럴 일은 없을 것 같습니다...
둘 째는 잘못된 예외처리 였습니다.
구글링하면서 문제의 원인을 찾아보았지만 결국 알아내지 못했습니다.
일단 테스트는 통과해야한다는 마음으로 throw와 try/catch, 그리고 return을 이곳저곳 바꿔가면서 사용했는데 어찌저찌 통과했습니다.
jest test에서 통과하지 못한 예외처리에 대해 추가적인 학습이 필요해 보입니다.
그리고 메서드의 return 유무에 따라 테스트의 통과, 실패가 갈렸습니다.
특히 startNewGame에서 return 이 필요한 이유를 정확하게 알아내지 못했습니다.
이 부분은 시간 날때 연구해볼 계획입니다.
// App.js
startNewGame() {
return this.runGame(generateRandomNum());
}
async runGame(answer) {
try {
const userGuessInput = await this.getUserInput();
inputValidator(userGuessInput);
const result = this.compareNums(userGuessInput, answer);
this.printResult(result);
if (result.strike === MAGIC_NUM.MAX_BASEBALL_NUM) {
return this.getRestartInput();
}
this.runGame(answer);
} catch (error) {
throw error;
}
}
async play() {
this.printStart();
await this.startNewGame();
}