이번주 과제는 로또 게임이다. 로또 게임이란, 사용자에게 구매 금액을 입력받고, 로또를 구매 금액만큼 사서 출력한 뒤, 당첨 번호도 사용자에게 받아 수익률을 계산하는 게임이다. 사용자에게 다시 당첨 번호를 받는게 ... 로또가 맞나 ...? 싶긴 하지만 프로그램이기에 넘어가보자 !
먼저, 구현할 기능 구현 목록을 작성했다.
기능 구현 목록
구입 금액을 입력받습니다. 금액은 1000원 단위로 입력받아야합니다.
만약 금액이 1000원 단위로 입력이 되지 않았을 경우, throw문을 통해 예외를 발생합니다.
입력받은 금액이 유효하다면, 반복문을 통해 구매 가능한 로또의 수 만큼 중복되지 않는 무작위의 6자리의 값을 배열에 저장합니다.
구매 내역을 출력합니다.
당첨번호를 입력받습니다.
만약 당첨번호가 유효하지 않은 경우, throw문을 통해 예외를 발생시킵니다.
보너스 번호를 입력받습니다.
만약 보너스 번호가 유효하지 않은 경우, throw문을 통해 예외를 발생시킵니다.
당첨 통계를 출력하기 위해 입력값과 배열의 로또 구매 내역을 비교하여 수 일치를 확인합니다.
만약 5개가 일치한다면, 나머지 1개의 수가 보너스 숫자와 일치하는지 확인합니다.
구매한 각 로또마다 몇개의 변호가 맞았는지 확인했다면, 당첨 통계를 저장할 수 있는 객체를 만들어 값을 업데이트 해줍니다.
당첨 통계를 출력합니다.
수익률을 계산하여 출력합니다.
이런식으로 구현하면 되지않을까? 라고 생각했고, 바로 코드 작성을 시작했다.
이번 과제에서는 특별히 생각해봐야 할 점이 Lotto 클래스를 조금 작성해서 제공한다는 점이었다. 이 클래스를 무조건 사용하면서, 작성된 코드의 변수는 변경할 수 없었다.
class Lotto {
#numbers
constructor(numbers) {
this.validate(numbers)
this.#numbers = numbers
}
validate(numbers) {
if (numbers.length !== 6) {
throw new Error()
}
}
// TODO: 추가 기능 구현
}
위처럼 제공되었다. 처음에는 이걸 어떻게 써야하나 싶어서 고민했고, 아예 Lotto 클래스에서 전체적인 코드를 작성했었다.
그랬더니, 생각보다 너무 가독성이 떨어지고 내가 코드를 짜는데도 혼란스러워서 과제에서 의도한 부분이 이게 아니겠다라고 생각했다. 그래서 로또번호를 입력받게된다면, Lotto클래스에서 검증하는식으로 작성해보았다.
생성자에 유효성 검증이 끝난 numbers가 this.#numbers로 되어있는걸로 보아 차후 반환받아서 사용해야하는것으로 판단했다.
과제를 하면서 대략 5일정도 걸린것 같다. 물론 과제 제출기한 전까지 계속 수정해갈 예정이지만...
이번 과제를 끝마치면서 저번주 과제를 보았을 때, 내 생각보다 조금 더 많은 발전이 있었던것 같다. 저번주 과제도 의식해서 상수를 사용하고, 리펙토링하는데에 주력했지만.. 지금 보니까 부족한 부분이 보이기도 해서 시간이 흐를수록 발전하고 있음을 알 수 있어서 신기했고 뿌듯했다.
먼저 else문의 사용을 최소화하기위해 노력했다. 로또 등수가 5개나 되니까 어쩔수 없이 else if 문을 써야하는 경우가 생겼는데, 이것을 어떻게 바꿀까 굉장히 고민을 많이 했던 것 같다.
예를들자면 이런식이다.
countWinning(lottoInfo) {
if (lottoInfo.numberOfCorrectNumbers === 3) {
lottoInfo['rank5'] += 1;
}
else if (lottoInfo.numberOfCorrectNumbers === 4) {
lottoInfo['rank4'] += 1;
}
else if (lottoInfo.numberOfCorrectNumbers === 5 && lottoInfo.isIncludeBonusNumber === true) {
lottoInfo['rank2'] += 1;
}
else if (lottoInfo.numberOfCorrectNumbers === 5) {
lottoInfo['rank3'] += 1;
}
else if (lottoInfo.numberOfCorrectNumbers === 6) {
lottoInfo['rank1'] += 1;
}
}
countWinning() {
const rankCheck = {
3: 'rank5',
4: 'rank4',
5: 'rank3',
6: 'rank1',
7: 'rank2',
}
this.lottoInfo[rankCheck[this.lottoInfo.numberOfCorrectNumbers]]
+= LOTTO_INFO_VALUES.COUNT_WINNING;
}
같은 함수를 이런식으로 고쳐주었다. 코드 컨벤션을 참고하며 코드를 짜보니 배울 점이 많아서 좋은것 같다. if문을 사용하지 않은것만으로도 코드가 깔끔해진다니 ... 신기했다.
테스트는 저번주보다 더 열심히 생각해서 만들어보았다. 어떤 부분에서 에러가 발생하는지 생각하면서 더 세심하게 테스트를 만들어보았다. 이런 고민을 하며 코드에서 부족한 부분을 채워나갈 수 있었던것 같다. 처음에는 기능별 테스트 구현이라고 해서 모든 함수와 메서드 별로 테스트를 해봐야하나... 싶었지만.. 그건 그것대로 아닌것같아서 적당히 클래스별로 테스트를 했었다.
기능 단위 테스트
ApplicationTest
- 기능테스트를 수행합니다.
- 예외 테스트를 수행합니다.
BuyLottoTest
- 클래스를 통해 반환하는 배열이 적절한 배열인지 검사합니다.
InputMoneyTest
- 구입 금액의 입력값이 숫자가 아닐경우 예외가 발생하는지 검사합니다.
- 입력값이 음수인 경우 예외가 발생하는지 검사합니다.
- 입력값이 자연수가 아닌 경우 예외가 발생하는지 검사합니다.
- 입력값이 1000원 단위가 아닌 경우 예외가 발생하는지 검사합니다.
LottoTest
- 입력받은 로또 번호의 갯수가 6개가 넘어가면 예외가 발생하는지 검사합니다.
- 로또 번호의 갯수가 6개 미만일 경우 예외가 발생하는지 검사합니다.
- 로또 번호에 중복된 숫자가 있으면 예외가 발생하는지 검사합니다.
- 로또 번호에 문자가 포함된다면 예외가 발생하는지 검사합니다.
- 로또 번호에 적절하지 않은 숫자가 있으면 예외가 발생하는지 검사합니다.
- 보너스 번호가 적절하지 않으면 예외가 발생하는지 검사합니다.
- 보너스 번호가 로또 번호에 포함된다면 예외가 발생하는지 검사합니다.
테스트 목록을 이런식으로 작성했다.
벌써 3주차가 지나고 있다. 그 동안 내가 익숙해져있던 코딩 스타일을 고치느라 고생을 좀 한것 같은데, 생각보다 빠른 시간 안에 변화가 보여서 놀라웠다. 벌써 마지막 과제만을 앞두고 있는데, 기대되고, 유종의 미를 거둘 수 있으면 좋겠다.
'우테코 프리코스' 카테고리의 다른 글
[우테코 프리코스] 4주차 (0) | 2023.02.19 |
---|---|
[우테코 프리코스] 2주차 (0) | 2023.02.19 |
[우테코 프리코스] 1주차 (0) | 2023.02.19 |
2022년 우테코 프리코스 지원기 (0) | 2023.02.19 |