활동내역.zip/개인

<우아한테크코스 2024 프리코스> 3주차 후기: 로또 10억원어치 사면 당첨되나요?

  • -
728x90

 

깃허브 바로가기

 

GitHub - TMInstaller/javascript-lotto-6

Contribute to TMInstaller/javascript-lotto-6 development by creating an account on GitHub.

github.com

2주차엔 어땠는지 보고싶다면? 2주차: 자동차 게임 보러가기

<2주차 Plus>제출 직전의 스프린트

2주차 자동차 경주 과제에서 나는 제출 직전에 갑작스럽게 몰입이 되는 상황을 겪었다. 왜 였을까? 갑자기 끝나기 직전이 되니 집중이 잘된다니? 사건의 전말은 이러하였다.

나는 분명 내 코드를 보면서 "음음 이런 피드백이 나오겠지? 이렇게 고치면 되겠다 라는 피드백이 오겠지? 라고 생각하고 있었다. 이왕이면 내가 스스로 피드백 한 부분들을 주석으로 달아두면 더 좋을 것 같다고 생각하여 아래와 같이 주석을 달아두었다.

// self-feedback: 이거 뭔가 이렇게 하면 좋을 듯

갑자기 머릿속에서 들려온 한 마디, "한시간 정도 투자하면 지금 내가 한 피드백 바로 적용해볼만 하겠는데?"
이 이후로 즉시 그 어느 때보다 긴박한 순간에서 피드백 적용을 위한 시도가 이루어졌다.
시간이 빠르고도 느리게 흘러가며 온 집중을 코드 수정에 쏟은 결과, 신기하게도 제출 전에 모두 피드백을 반영하고, 모든 테스트에 통과하며, 제출 페이지에 까지 무사히 통과하는 것을 성공시켰다.

이는 한 클린코드 관련된 영상에서 반복해서 언급 했던 말 중 "코드 구조를 바꾸는 것에 두려워하지 말아요" 에 영향을 크게 받았다. 이전까지만 해도 코드를 짜다가 구조를 변경하는 것에 두려움이 있어 이를 변경하는 것을 기피하다시피 했는데, 생각해보니 깃으로 미리 커밋을 해두면 될 일이었고, 그렇게 해서 더 깔끔해지면 모두에게도 좋은 결과가 나오기에 두려울 필요가 없었다는 것을 깨달을 수 있었다.

어우 진짜 감기 너무 오래가네.. 이거 뭔가 잘못된 거 아냐?

분명 2주차 과제 진행 시작과 동시에 감기에 걸렸던걸로 알고있는데.. 왜 제출하는 이순간까지 감기에 걸려있는거지..? 비염 -> 두통 -> 잦은 기침 순으로 변화해오며 몸이 회복 되는 듯 아닌 듯 했다. 어쩌다보니 이번 과제는 가벼운 감기와 함께했던 과제인 것 같다. 2주차 시작 시점에 감기에 걸렸지만 3주차 제출 시점에 감기가 다 나아가는 뭔가 이상한 상태에 있던 나는 지금부터 배운 것도 많고, 성장도 많이 한 프리코스 3주차 후기를 시작하겠다.


2주차의 성공적인 코드리뷰, 무엇을 배웠을까?

이번 주에도 정말 많은 것들을 배워갈 수 있었다. 다른 사람들의 코드를 보며 배웠던 내용들, 그리고 코드 리뷰를 받으며 얻은 깨달음 등이 참 많았는데, 간단하게 정리해보자면 아래와 같았다.

  1. Object.freeze를 이용하면 선언한 상수가 외부에서 수정 불가능한 얼어붙은 상태가 된다.
  2. 테스트 코드의 경우 file.test.js와 같이 .test를 구분지어 작성하면 파일 구분하기가 편하다.
    • 나중에 확인한 결과 그렇게 이름을 지을 경우 아이콘이 플라스크 모양으로 변경된다.
  3. ++, --와 같은 연산자는 예기치 못한 오류를 발생할 수 있기에 for문에서 이를 사용하고 있다면 변경해주도록 한다.
  4. constlet을 구분지어 사용하도록 한다. 거의 대부분의 변수는 const에 할당된다.
  5. 같은 변수에 다시 값을 재 할당 하는 것은 후에 버그의 원인이 된다. const로 고정해주고 새로운 변수를 생성하여 할당하도록 하자.
  6. 출력 단위까지 분리해버리는 것이 좋다(Console.print 등 제공되는 입출력 시스템)
    • 이 부분은 바로 다음 주 요구사항에 들어있었다..!
  7. 추가로 무언가 기능이 요구될 때 변환하기 용이하도록 코드를 작성하라
  8. js convention에서는 if문 이후에 줄바꿈이 된다면 한줄만 작성되어도 중괄호{}를 쓰는 것을 추천한다.
  9. static을 메서드 앞에 붙이면 new Class()로 인스턴스를 생성하지 않고도 해당 메서드를 사용할 수 있다.
    • 이를 활용해보려 했으나 사용하려는 근거가 명확하지 않았기에 function()을 통해 함수로 대체해서 구현하였다.
  10. 커밋 컨벤션 또한 요구조건에 들어있었다. 다음번엔 꼭 적용해보자.
    • 잘 적용한 것 같다.
  • 이렇게 많은 피드백들을 얻으며 이런 점들을 모두 이번 프로젝트에 적용해야겠다 다짐했다.


정말 생각지도 못하고 있었는데.. 감사함을 표합니다.


이번엔 커밋 컨벤션도 잘 지킨 것 같다!


코수타(코치들과의 수다 타임)

이번 주 코수타에서는 신사옥을 구경했다. 코치님께서 진행하시는 v-log를 보며 "와 저기서 일하면 없던 힘도 날 것 같다..!" 와 같은 생각들을 하며 구경을 하고, 테코톡 촬영현장을 보고, 아래와 같은 조언을 얻었다.

  • 무언가 하나를 계속해서 깊게 파는 것을 높이 평가한다
  • 겉만 훑고 지나가는 사람들도 좋지는 않지만, 해결안되는데 시간 계속 써서 파는 그런 것은 지양하자. 시간은 한정적이다.

시작할 때 더욱 신중해야해

1주, 2주차 때 했던 실수를 하지 않기 위해, 나는 필수적으로 해야 할 일들을 이번에는 넘기지 말고 꼭 하고 시작하자라는 마음가짐으로 순서에 따라 리드미를 작성했다. 그리고 이번엔 성공적으로 요구사항들을 지켜가며 잘 구현한 것 같았고, 나름 만족하면서 구현을 진행했다.
시작할 때 브랜치 파고, 리드미 먼저 적어두고, 업데이트하면서, 컨벤션 지키면서, 하드코딩 다 대체하고, 동일한 기능 하는 것들 메서드화 시키고, 메서드 길이 준수 최대한 하면서, 1기능 원칙 최대한 지키면서 시간이 더 걸리더라도 신중하게 코드를 작성하고 변경했다.

그 결과 총 39개의 단위 테스트가 진행되었고, 모두 통과시키는 엄청난 결과를 내었다..!


와 !

스스로에게 박수 !

3주차까지 오면서 급격하게 늘어난 코드라인 수

이번 과제를 진행하면서 작성한 코드량이 전주차에 비해 급격하게 많아져서 모듈화를 잘 해두어서 그런가 생각했었다. 그러다 문득 궁금해져서 PR의 코드라인 수를 확인해 보았는데

  • 1주차: 약 200라인
  • 2주차: 약 400라인
  • 3주차: 약 1200라인

리드미가 약 300라인 정도 된다는 것을 감안해도 굉장한 증가폭을 보여준다. 주식도 이렇게는 안 오를텐데 뭔가 내 주가가 엄청 뛰어오르는 듯한 느낌이 들었다. 이제 가즈아를 외치면 되는걸까?

이번 로또를 구현하며 알게된 사실들

이번에 로또라는 다소 복잡한 요구조건을 지니고 있는 문제를 구현하면서 몇 가지 새로 안 사실들이 있다.

  1. 숫자 배열은 로그를 찍으면 배열형태로 나오지 않아요
    • [1,2,3,4,5] 의 숫자 배열은 로그를 찍었을 때 1,2,3,4,5처럼 그냥 숫자가 나열된 형태로만 나온다.
    • 따라서 아래와 같이 템플릿 리터럴을 사용하여 요구조건을 만족시켰다.
Console.print(`[${newLottoNumbers.join(", ")}]`);`
  1. 짧은 회로
    • 짧은 회로라고, 말 그대로 짧게 boolean 값을 이용하여 두개의 값 중 하나를 배정하는 로직이다.
    • 굉장히 특이했고, 사용할 수 있는 부분이 많을 것 같아서 기억해두려고 한다.
export function checkBonusBallIsMatching(hasBonus, rankCounts) {
  // 짧은 회로를 통해 hasBonus가 참일 경우 rankCounts[2], 거짓일 경우 rankCounts[3] 값 증가
  // 배열의 특성 상 return없이 직접 수정되는 효과 보유
  rankCounts[hasBonus ? 2 : 3] += 1;
}
  1. 충격적인 사실
    • JavaScript는 아래와 같이 연속으로 두개의 비교연산자를 사용하는 것이 불가능하다
    • 옆집 파이썬은 이거 되는데에에!
#isNumberInRange(string) {
    if (!(LOTTO_NUMBERS.minimum <= Number(string) <= LOTTO_NUMBERS.maximum)) {
      // 이러면 코드 안돌아갑니다
    }
  }
}
  1. 모델 생성
    • 모델을 생성할 때 #을 변수명, 메서드명 앞에 붙이면 외부에서 해당 메서드와 변수를 참조할 수 없게 된다.
    • constructor()this.method(string)를 넣어둔다면 클래스 호출 시 constructor에 들어가있는 모든 string이 들어간 클래스의 메서드들을 실행시킨다.

테스트코드에서도 알아낸 것이 있죠?

물론이다. 테스트코드를 작성하는 것에서도 어느 정도 상황에 따른 테스트 작성법을 알 수 있었다.
아래와 같이 여러 상황 별로 작성할 수 있는 방법들을 만들어 보았다.

  • 테스트는 describe를 통해 가장 밖에서 묶어주고, 각각의 케이스를 test를 통해 진행해주고, 그 테스트 내부에 expect().<methods> 를 통해 진행된다.
    • expect().toBe()
      • 주로 숫자, 문자, boolean 등의 단일 값에서 확인하는 케이스에서 사용
    • expect().toEqual()
      • 주로 배열, 객체 등의 Object 단위 값을 확인하는 케이스에서 사용
    • expect().toThrow()
      • 주로 에러가 발생하는 지 확인하는 케이스에서 사용
describe("테스트의 단위를 설명해두는 부분", () => {
  test("단위 내 상세 테스트 정보를 적어두는 부분", () => {
    // 이쯤 빈공간에 변수들 선언또는 생성해두기

    // expectedValue가 단일 값인 경우
    expect(expectedValue).toBe(singleValue); // 단일 값의 경우 .toBe()
    expect(expectedValue).toEqual(multpleValue); // 다중 값의 경우 .toEqual()
    // expectedValue라는 return값이 존재하는 함수에 대한 예외처리인경우
    expect(() => {
      new TestClass("Set Value Here");
    }).toThrow("여기의 문자열이 Throw된 메세지에 포함되는지 확인");
  });

    test("...다른 테스트", () => {});
});

그리고 가장 중요하게 깨달은 사실, class는 교실이 아닙니다.

깨알같은 다른 글 홍보
바로 class 모델을 생성할 때 하나의 값을 가진 클래스는 하나의 필드만 가지고 있어야 한다고 생각했다. 왜냐하면 클래스에 값이 형태 상관 없이 하나만 들어오게 되어있으니깐 그럴 것이라고 생각했다.

하지만 모든 구현이 끝나고 하나의 궁금증이 생겼다.

왜 굳이 하나의 형식만을 입력값으로 받는걸까? 여러 형식의 값을 입력받을 수는 없는걸까?

이런 궁금증이 생긴 이유는 내가 모델을 생성하고 유효성 검사를 하는 데 있었다.
기본적으로 입력받은 값들이 string값으로 들어오기에, 형 변환을 그냥 이 string 값을 받아서 변환해가면서 유효성 검사를 하도록 구현 해두었다.
하지만 나중에 코드량이 늘어난다면 헷갈려질 것 같으면서도 추후에 다른 곳에서 초기 형태의 값이 아닌 다른 형태(number, arr) 등에 해당하는 같은 모델에 다른 형태의 값이 들어올 때 테스트를 진행해야 한다면 어떡하지? 라는 고민이 생겼었다.

  • 이번 주차에서는 하나의 값에 하나의 클래스를 적용했고, 입력값의 경우 string 문자열을 받아서 처리하는 로직을 구현했다.
  • 더 나은 방법이 있을 것이라고 분명 생각하고 있고, 이를 다음 주에 적용해보려고 한다.
  • 확실히 아직 클래스를 능숙하게 다루는 단계는 아니다 보니 기초적인 형태로 여러 모델을 만들고 실험했던 것 같다. 다음번엔 더 발전된 클래스를 작성하기 위해 정보를 모아봐야겠다.

안심하세요, 이번에는 억까가 없었어요

이 사진을 보아 알 수 있듯이 이번엔 예기치 못한 오류 없이, 폴더 구조를 변경하지 않아도 정상적으로 테스트가 통과되었다는 것을 알 수 있다. 정말 다행이다. 휴


로또 자동으로 10억원어치 사면 당첨 되나요?

문득 이번 주에 올라온 로또 번호를 여기에 넣어보면 당첨이 될까 싶어 내가 만든 프로그램에서 돌려보기로 했다. 구매금액은 JavaScriptNumber범위 제한으로 인해 2억원씩 5번 총 10억원어치 구매해보았다.

  • 이때 아차 싶었다. BigInt처리를 할 생각을 이때는 왜 못했을까..! ㅠ
    • 라고 생각했지만 누가 한번에 10억원어치 구매를 하겠는가. 2억원이어도 20만장인데 ㅋㅋㅋㅋ


두근두근한 순간이다. 그래도 100만장을 사는 건데 하나는 당첨되지 않을까?


번호를 입력했다.

1회차 - 2억(20만장) 구매


수익: 2980,0000

2회차 - 2억(20만장) 구매


수익: 3440,0000

3회차 - 2억(20만장) 구매


수익: 3600,0000

4회차 - 2억(20만장) 구매


수익: 2800,0000

5회차 - 2억(20만장) 구매


수익: 3240,0000

총 수익: 약1,6060,0000
총 구매: 100만장(20만X5)
1억 6천만원 벌려고 10억을 태운거야..?
그리고 이와중에 1등은 커녕 2등 아무것도 안나온거...

결론


묻고.. 가!

묻어야지 그냥 뭘 자동 돌리려고 그래
이럴꺼면 9억을 기부하고 말지


End

728x90
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.