-
Notifications
You must be signed in to change notification settings - Fork 168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1단계 - 행운의 로또 미션] 지그(송지은) 미션 제출합니다. #23
Conversation
- update input price form's id
- create dom selector converter - add line spacing - update isValidPrice method for early return
src/js/Lotto.js
Outdated
constructor() { | ||
this._numbers = new Set(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constructor
에서 바로 new Set()
과 같이 생성자 호출하는 것이 살짝 불안정해 보이는 느낌인데, 코드를 간결하게 하기 위해서 사용하였습니다. 괜찮은 방식일까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네 전혀 문제 없고 좋습니다.
[] 로 할당하는것보다 숫자가 겹치지 않는다는 의도를 전달 하기 위해 Set을 사용한 것도 좋고, constructor 에서 초기화하는 것도 적절한곳에 적절한 코드가 적절하게 위치하고 있습니다.
src/js/LottoController.js
Outdated
this.lottos = Array.from({ length: lottoCount }, () => { | ||
const lotto = new Lotto(); | ||
lotto.initNumbers(); | ||
return lotto; | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Array.from({ length: ... }), () = {})
방식의 코드를 이번에 처음 접해 보았는데,
언젠가 new Array()
와 같은 생성자 호출 방식은 좋은 방법이 아니며(😬 이 이유를 알고자 다시 검색해 보았으나 잘 나오지 않아서, 이 부분도 궁금합니다. ), 위 코드 역시 내부적으로 생성자를 호출하는 것이라서 좋은 코드가 아닐 수도 있다고 생각했습니다.
사용해도 좋은 방식인지 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new 로 생성하면 객체의 생성 방법을 사용자측 코드에서 너무 자세히 알아야 하는 문제가 있습니다.(필수 파라미터가 무엇인지, 순서는 어떤지 등등 그래서 생성 방법이 바뀌면 해당 객체를 생성하는 모든 코드를 다 바꿔야 하는 문제가 있습니다.)
그래서 객체를 직접 생성하지 말고 요청하게 하는 것입니다.
객체를 생성하는 정적 메서드를 제공해주고 이 메서드를 사용하게 함으로써 앞서 있던 문제를 해결 할 수 있는것입니다.
'정적 팩토리 메서드 패턴'으로 검색하시면 자세한 내용을 접하실 수 있을것입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정적 팩토리 메서드 패턴에 대해 간단하게 검색해 보았습니다. 처음 알게 되었습니다. 감사합니다 😊
번외로 제가 며칠 전에 Object.create()
라는 문법을 알게 되었는데, 이것도 new Object
가 아닌, .create()
라는 메소드를 사용하여 새 객체를 생성하였으므로 정적 팩토리 메서드 패턴이라고 볼 수 있는지 궁금합니다! 😮
- remove unnecessary label 'for' attribute - create utils file for helper function - rename 'priceValidator' to 'validatePrice' - create getter for show lotto numbers - update logic for getting input price value - separate alert out of isValidPrice method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요. 역할 분리에도 신경을 쓰신거 같고 코드가 깔끔한편이어서 읽기 좋았습니다. :)
궁금한점 답변
-
class 명으로 셀렉팅하여 js에서 기능을 하게 하는것은 프로그램이 깨지기 쉬운, 굉장히 취약하게 만드는 방법중 하나 입니다. 기능의 변화없이 화면이 바뀌어 스타일을 새로 만들고 클래스를 바꿔주면 화면에 변화가 일어나고 기능은 똑같이 동작해야 합니다. (변한것은 화면의 디자인뿐이기 때문) 그러나 js에서 클래스에 의존하도록 구현 해놨었다면 이 기능은 망가지게 됩니다. 그래서 화면이 바뀌었는데 매번 js 에서 이걸 쓰는지 검색해가면서 조심스럽게 작업을 진행할 수 밖에 없어 시간도 더디게 됩니다. 따라서 단일 엘리먼트면 id 로 하도록 하고 여러개면(하나여도 상관없음) data-* 프로퍼티를 이용하면 좋습니다. data-section=lotto, data-section=result 이런식으로 하면 구성하는 섹션 전체를 가져올수도 그 안에서 세부적인 하나를 가져오기도 좋습니다.
-
현재의 $는 단순히 코드 타이핑을 줄이는 정도와 단일한 사용 포인트를 나의 코드레벨에서 관리 할 수 있다는 정도의 이점 밖에 없습니다.
따라서 $를 좀 더 개선하셔서 제이쿼리 처럼 show, hide 메서드를 제공하게 하면 좀 더 쓸만한 커스텀 라이브러리가 될 것입니다. 그리하면 LottoView의 show, hide는 제거 할 수도 있고 더 유연하게 쓸 수도 있습니다.
방법은 $ 함수가 엘리먼트를 바로 반환하지 말고 함수 내부에 지역변수로 두고, show,hide 메서드를 가진 객체를 반환하고 이 객체를 통해 element를 접근하게 하면 됩니다.
이것이 클로저를 이용한 모듈 패턴입니다.
$(셀렉터).show()
$(셀렉터).hide()
같은식으로 할 수 있게 됩니다.
필요에 따라 addEventListener, addClass, removeClass 같은것을 추가해보셔도 좋습니다.
src/js/Lotto.js
Outdated
|
||
export default class Lotto { | ||
constructor() { | ||
this._numbers = new Set(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private을 의도하셔서 _numbers 를 하신것이라면 좋습니다.
다만 이것은 자바스크립트에 private이 없을 때 관례적인 명명규칙일뿐 여전히 외부에서 직접 접근하여 조작 할 수 있습니다.
그러나 이제는 자바스크립트에도 공식적으로 private 의 의도를 표현 할 수 있는 #이 들어왔기 때문에
this.#numbers = ....
로 하시면 됩니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private을 의도한 것은 맞습니다!
다만 #을 쓰는 방식을 아직 지원하지 않는 브라우저들이 있다고 해서 사용을 고려했었고, 현재 safari 브라우저에서도 syntax 오류를 발생시켜 사용하지 않는 쪽으로 결정했습니다. 또한 크롬으로 실행하더라도 현재 eslint와 충돌이 나고, babel을 따로 설정해 줘야 해서 이번 단계에서는 사용하지 않기로 했습니다.
우선 현재는 numbers
에 직접 접근할 일이 없어서, private 접근자(언더바)를 사용하지 않고 진행하기로 해보았습니다!
src/js/Lotto.js
Outdated
} | ||
|
||
initNumbers() { | ||
while (this._numbers.size < NUMBERS.LOTT0_LENGTH) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOTT0_LENGTH 가 NUMBERS에 있는것보다 이 Lotto 에 스태틱 프로퍼티로 존재하는게 더 좋을것 같습니다.
Lotto는 몰라야하고 LOTT0_LENGTH 만 알아야 하는 객체가 있는 경우가 있는게 아니라면 LOTT0_LENGTH를 굳이 분리하는건 관리상 이점이 없을 것 같습니다.
그리고 LOTT0_LENGTH 보다는 LOTT0_MAX_LENGTH 가 더 의미적으로 명확할 것 같습니다.
근데 사용 할 땐 Lotto.LOTT0_LENGTH 가 될 테니 정보가 중복되므로 Lotto.MAX_NUMBER_LENGTH 정도의 의미 전달이 더 좋지 않을까 싶습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
각 로또별로 번호의 개수가 '최대' 6개가 아니라 '반드시' 6개여야 하기 때문에 MAX는 문맥에 맞지 않다고 생각했습니다!
말씀주신대로 해당 값은 Lotto
객체 안에 있는 게 좋을 것 같아서 그 부분은 수정해보도록 하겠습니다.
src/js/LottoController.js
Outdated
createLottos(lottoCount) { | ||
this.lottos = Array.from({ length: lottoCount }, () => { | ||
const lotto = new Lotto(); | ||
lotto.initNumbers(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로또 객체를 생성하면 번호까지 완성된 로또가 튀어나오면 더 좋지 않을까 싶습니다.(자동)
외부에서 로또 객체를 만들고 번호까지 직접 init 해줘야 할 필요까지는 없을것으로 생각됩니다.
혹은 아예 생성할 때 번호를 직접 줘도 되고...(수동)
(이 부분은 지금 그냥 넘어가시고 다음 단계에서 고민하셔도 될 것 같습니다.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리뷰 반영하도록 하겠습니다!
번호 수동 입력은 다음 단계 미션에 있기 때문에 그 때 참고하도록 하겠습니다 🤓
const isSwitchOn = $lottoIconsDiv.checked; | ||
|
||
if (isSwitchOn) { | ||
$lottoIconsDiv.classList.add('flex-col'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컨트롤러에서 뷰의 세부적인 클래스(flex-col)까지 알고 있는것은 컨트롤러의 책임이 과합니다.
숨겨야 하고 보여야 할 게 있다면 단지 뷰에 요청만 하면 되고 flex-col 같은 것은 뷰에서 알아야 할 정보라고 보여집니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 View와 Controller의 역할을 다시 고민해 보고 각각의 역할에 맞게 분리하는 작업을 하고 있어서, 2단계 미션에 전반적인 리팩토링을 추가할 예정입니다. 말씀 주신 부분도 해당 리팩토링 단계에서 참고하여 포함하도록 하겠습니다. 좋은 조언 감사합니다 😊
src/js/utils/constants.js
Outdated
@@ -0,0 +1,13 @@ | |||
export const NUMBERS = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NUMBERS 라는 이름의 constants를 만들게 되면 실제로 그 내부의 있는것들은 전혀 연관관계가 없지만 숫자라는 이유만으로 같이 뭉쳐있게 됩니다. (이내 쓰레기통과 같은 객체가 됩니다.)
예를 들면 키, 몸무게, 나이, 생년월일, 핸드폰번호 같은것은 개인정보라는 카테고리로 묶여있어야 하고 100미터 달리기 기록, 2분동안 푸시업 개수, 풀업 개수 같은것은 운동 관련 카테고리로 묶여 있어야 합니다.
따라서 NUMBERS라는 상수 객체가 생겨버리면
const NUMBERS = {
키: xx,
몸무게: xx,
푸시업개수: xx
로또최대숫자: xx,
}
처럼 되길 의도한 이름이라고 봐도 무리가 없기 때문에(물론 그런 의도는 아니었겠지만...) 그래서 이름을 좀 더 구체적으로 잘 지어주셔야 겠습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나중에 바꾸려고 했는데 실수로 바꾸지 않은 채로 올렸네요 😅 좋은 지적 감사합니다! 반영하여 수정하였습니다.
|
- change unused private property to public property - redefine Lotto Length property to Lotto class static property - move initNumbers method to constructor - rename constant name in specific way - install eslint-babel to fix eslint syntax
학습 로그정적 팩토리 메서드 패턴 ref
DOM 선택자로 class명 대신 id(단일 엘리먼트), dataset(여러 개) 사용하기 ref
class private field, hash
|
안녕하세요! 페어 티케와 로또 미션 진행한 지그입니다.
잘 부탁드립니다 😊
데모 - 지그의 로또 미션
✅ 1단계 미션 TODO
🎰 로또 🎰
1번부터 45번까지의 공 중에서 6개를 추첨하고, 이어서 보너스 번호로 공 1개를 추가로 추첨한다. 즉 1번부터 45번까지 중에서 6개를 추첨한 후 또 다시 1개를 추첨하는 것이다. 물론 이 번호들은 중복된 번호가 없다.
기능 구현 목록
사용자가 라벨을 선택해도 입력칸에 autofocus를 해준다.Cypress 테스트
정상 로직
예외상황
🚧 앱 구조
📺 디렉토리 구조
🤔 궁금한 점
dom.js
에서와 같이 선택자를 만들어주는 방식을 처음 적용해 보았는데, 괜찮은 방식인지 궁금합니다.기타 질문은 코멘트로 달도록 하겠습니다!
리뷰 감사드립니다. 🙃