[우아한 테크코스 5기 프리코스] FE 3주차 회고록
우아한 테크코스 프리코스 과정의 3주차 미션이 끝났다. 이번 미션을 하면서 클래스의 변수를 가져오는 과정에서 정말 많은 어려움을 겪었다. 구글 검색을 하고 또 하고 또 해서 얻은 정보들을 사용해도 오류가 발생해서 정말로 미치겠다는 표현이 계속 나왔다.
1. 우아한 테크코스 프리코스 3주차 과제
3주차 과제 내용
누구나 1등을 꿈꾸는 로또 게임을 만드는 것이 3주차 미션이었다. 로또 구매 가격을 입력하고 구매한 갯수만큼 로또 랜덤 번호를 생성하고 로또 당첨 번호를 입력해서 로또 랜덤 번호들과 당첨 번호를 비교해 일치한 갯수와 수익률을 출력하는 것이 최종 미션이었다.
이번 미션은 이전에서 더 나아가 단위 테스트 코드도 작성해야 했다. 나는 정말 많은 문제점을 계속해서 마주해야 했기 때문에 기능 구현에만 신경썼다. 그래서 단위 테스트를 구현해야 한다는 것을 잊고 있었다. 겨우 겨우 구매 가격 입력, 로또 랜덤 번호 생성, 당첨 번호 입력, 보너스 로또 번호 입력을 구현하고 이를 비교해서 결과값을 내도록 구현했다. 무려 제출해야 하는 마지막 날에 마감 3시간 전에 말이다. 그리고 단위 테스트도 구현해야 한다는 것을 떠올렸고 약 20~30분 정도 남겨두고 대략의 단위 테스트도 구현해서 제출했다. 3주차가 이런데 4주차는 해결할 수 있을지 벌써부터 걱정이다.
이번 미션에서는 하나의 함수는 하나의 기능을 해야한다는 조건과 각 함수는 15줄을 넘지 않아야 한다는 조건이 있었다. 그리고 단위 테스트를 구현해 각 기능이 제대로 동작하는지 확인해야 하는 것이 이번 미션에서 알아가야 할 내용이라고 느꼈다. 테스트에 대한 강의를 볼 때마다 단위 테스트도 항상 나왔었지만 지금 내 수준에서는 단위 테스트까지 챙길 여유는 없다고 느꼈다. 그리고 이는 이번 미션을 진행하면서 그대로 드러났다. 구현하는 것도 힘들어 한다는 것을. 그리고 어떻게 단위 테스트를 구현했지만 제대로 된 것은 아니라는 것을.
이번 미션에서 내가 잘한 것은 없지만 배운 것과 느낀 것은 정말 많았다.
2. 코드로 기능 구현
처음부터 리팩토링으로 각 기능을 분리해서 구현하는 것은 나에게 어렵다. 그래서 우선 모든 것을 구현하도록 했다. 로또 구매 입력, 로또 당첨 번호 입력, 보너스 번호 입력 순으로 기능울 구현했다. 그리고 각 기능마다 입력할 때 입력 예외 처리를 하도록 했다. (로또 당첨 번호 입력은 Lotto 클래스에서 구현했고 예외 처리도 클래스 내부에 있다.)
userBuyLotto() {
MissionUtils.Console.readLine(BUY_LOTTO, (buyInput) => {
errorBuyHandling(buyInput);
this.user.lottoBuy(buyInput);
this.userInputLottoNumbers();
});
}
userInputLottoNumbers() {
MissionUtils.Console.readLine(WINNING_NUMBERS, (lottoNumber) => {
this.lotto = new Lotto(lottoNumber);
this.userInputBonusNumber(this.lotto.getNumber());
});
}
userInputBonusNumber(lottoNumber) {
MissionUtils.Console.readLine(BONUS_NUMBER, (bonusNumber) => {
bonusNumberCheck(bonusNumber, lottoNumber);
this.user.saveBonusNumber(bonusNumber);
this.lottoGameStart(lottoNumber);
});
}
class Lotto {
#numbers;
constructor(numbers) {
this.validate(numbers);
this.#numbers = numbers;
}
validate(numbers) {
this.notComma(numbers);
this.overlapCheck(numbers);
this.lengthCheck(numbers);
this.limitedNumber(numbers);
this.notNumber(numbers);
}
notComma(numbers) {
if (!numbers.includes(',')) {
throw new Error("[ERROR] (,)로 구분하여 숫자를 입력해주세요.");
}
}
overlapCheck(numbers) {
const numberSplit = numbers.split(',');
const numberSet = new Set(numberSplit);
if (numberSet.size !== 6) {
throw new Error("[ERROR] (,)로 구분하여 중복되지 않는 숫자를 입력해주세요.");
}
}
lengthCheck(numbers) {
const commaLength = numbers.split(',').length - 1;
if (commaLength !== 5) {
throw new Error("[ERROR] (,)로 구분하여 6자리 숫자를 입력해주세요. (예. 1,2,3,4,5,6)");
}
}
limitedNumber(numbers) {
numbers.split(',').map((num) => {
if (Number(num) > 45 || Number(num) < 1) {
throw new Error('[ERROR] 숫자 1부터 45까지 입력해주세요.');
}
})
}
notNumber(numbers) {
numbers.split(',').map((num) => {
if (isNaN(num)) {
throw new Error('[ERROR] 숫자만 입력해주세요.');
}
});
}
|
그리고 실제로 로또 결과를 낼 수 있는 기능을 분리해 구현하였다.
우선 로또 당첨 번호 입력 값, 로또 랜덤 번호 값들, 보너스 입력 값, 사용자 구매 비용 값을 인자로 받아서 사용했다.
그리고 로또 번호를 비교해 결과를 낼 데이터를 객체로 구현해 resultCheck 변수에 담았다.
로또 랜덤 번호들의 길이만큼 반복해서 로또 당첨 번호와 비교해 당첨 번호가 있는지 체크한 값과 보너스 번호가 있는지 체크한 값을 각 변수에 담았다.
그리고 당첨에 해당될 경우, 객체의 count 값이 증가하도록 구현했다.
const lottoGame = (inputNumber, lottoArray, bonusNumber, userBuyMoney) => {
const resultCheck = RESULT_CHECK;
lottoArray.forEach((numbers) => {
const lottoCount = includedLotto(inputNumber, numbers);
const bonusCheck = includedBonus(numbers, bonusNumber);
if (lottoCount === 3) resultCheck.three.count += 1;
if (lottoCount === 4) resultCheck.four.count += 1;
if (lottoCount === 5) resultCheck.five.count += 1;
if (lottoCount === 5 && bonusCheck) resultCheck.fiveBonus.count += 1;
if (lottoCount === 6) resultCheck.six.count += 1;
});
printLottoResult(resultCheck, userBuyMoney);
}
그리고 결과 값이 담긴 객체와 사용자 구매 비용 데이터를 실제로 출력할 함수에 넘겼다.
그리고 총 당첨 금액과 사용자가 구매한 비용을 사용해서 수익률을 구했다.
그리고 실제로 출력할 메세지를 구현했다.
const printLottoResult = (lottoResult, userBuyMoney) => {
const allIncomePer = ((allIncome(lottoResult) / userBuyMoney) * 100).toFixed(1);
printContents(lottoResult, allIncomePer);
}
const printContents = (lottoResult, totalPer) => {
const contents = `
당첨 통계
---
3개 일치 (5,000원) - ${lottoResult.three.count}개
4개 일치 (50,000원) - ${lottoResult.four.count}개
5개 일치 (1,500,000원) - ${lottoResult.five.count}개
5개 일치, 보너스 볼 일치 (30,000,000원) - ${lottoResult.fiveBonus.count}개
6개 일치 (2,000,000,000원) - ${lottoResult.six.count}개
총 수익률은 ${totalPer}%입니다.
`;
MissionUtils.Console.print(contents);
MissionUtils.Console.close();
}
과정을 진행하면서 더 깔끔하고 이해하기 쉬운 코드를 구현하고 싶었다. 그런데 미션의 기능 구현도 어려워했다. 그래서 다른 것을 신경쓰지 못하고 기능 구현해만 모든 시간을 사용했다. 그리고 이번 미션을 진행하면서 역시나 이름을 제대로 작성하는 것에 어려움을 느꼈다. 어떻게 하면 쉽게 이해할 수 있는 이름을 지을 수 있을까? 계속 고민해도 해결되지 못하는 문제였다.
그리고 클래스로 구현할 수 있는 것들은 클래스로 구현해야 했지만 그러지 못했다. 새로운 미션을 할수록 더 나아지기보다는 문제점이 더 많아지고 배워야 할 것도 더 느는 것 같다. 나의 부족함을 더 많이 알게 됐다. 4주차는 3주차보다 나아진 코드 구현을 이루도록 노력해야겠다.
3. 3주차 과제를 하고 나서 느낀 것
(1) 한 단계 씩 순서대로 진행할 것
지금까지 미션을 하면서 기능 구현과 동시에 리팩토링을 하려고 했다. 그러나 두 가지를 동시에 하려고 하니 오히려 더 복잡해지고 이해하기 어렵게 만들었다. 이번에 느낀 것은 리팩토링을 동시에 하려고 하기 보다 우선 구현을 우선적으로 하고 나서 모든 구현을 하고 난 후 리팩토링을 하는 것이 오히려 효율적이라고 생각하게 되었다. 한 단계씩 순서대로 진행하는 것이 내가 원하는 방향으로 더욱 쉽게 갈 수 있을 것 같다.
(2) 조건 내용 제대로 읽을 것
미션을 종료되기 전 단위 테스트를 구현해야 한다는 것을 알았다. 구현 조건 내용에서 읽은 기억이 없었는데 다시 가서 읽어보니 구현 조건 내용에 단위 테스트 구현이 있었다. 내가 제대로 읽어보지 않아서 생긴 문제였다. 즉, 나의 안일함의 문제였다. 4주차 과제부터 제대로 꼼꼼히 조건 내용을 읽어서 같은 문제가 반복되지 않도록 해야겠다.
(3) 다급해하지 말 것
시간이 갈수록 더 다급해졌다. 문제를 해결하지 못하고 있는 상황에 더욱 다급해졌다. 그래서 오히려 생각이 복잡해졌다. 충분히 구현할 수 있는 것들도 다급함에 제대로 구현하지 못하고 시간만 보냈다. 미션을 해결하지 못하더라도 지금 내가 할 수 있는 것들을 침착하게 구현하고 몰랐던 지식들을 배우는 것이 이번 과정에서 얻어갈 점이라는 것을 잊고 있었다. 다급해질수록 오히려 더 침착하게, 내가 할 수 있는 그리고 배울 수 있는 것에 집중하자.
4. 부족한 것
(1) 단위 테스트 구현
단위 테스트를 구현할 때, 클래스에 구현한 것이 아닌 외부 폴더에서 파일을 생성해 해당 파일을 사용해 단위 테스트를 했다. 이는 좋은 방법이 아닌 것을 잘 몰라도 느꼈다. 나는 모든 기능을 클래스에 구현하지 않았고 시간도 약 1시간이 남아 급하게 처리해 잘못된 방법으로 구현했다. 단위 테스트를 구현하는 연습이 더 필요하다고 느꼈다. 어떻게 하면 단위 테스트를 좋은 방법으로 구현할 수 있을까? 계속 고민해야 할 부분이다.
5. 마무리
내가 최선으로 할 수 있는 부분에 집중해야 한다. 그리고 과정을 통해 배울 수 있는 것에 집중해야 한다. 결과만 생각하고 테스트 통과에만 집중하고 있는 것 같다. 배움에 집중하고 그 배움을 통해 내가 얻어갈 수 있는 것에 집중해야 한다. 결과와 상관없이 4주차도 잘 할 수 있도록 노력해야 한다.