Skip to content

[1주차] 홍의민 미션 제출합니다.#42

Open
EM-H20 wants to merge 20 commits intogreedy-team:EM-H20from
EM-H20:EM-H20
Open

[1주차] 홍의민 미션 제출합니다.#42
EM-H20 wants to merge 20 commits intogreedy-team:EM-H20from
EM-H20:EM-H20

Conversation

@EM-H20
Copy link

@EM-H20 EM-H20 commented Mar 17, 2026

안녕하세요, 송혜정 리뷰어님.
프론트엔드 4기 홍의민입니다.
1단계 숫자야구게임 미션 제출합니다.

스크린샷 2026-03-17 오전 11 42 06

기능 구현 목록

BaseballGame.js (src/index.js)

BaseballGame 클래스 — 랜덤한 숫자와 유저 입력 숫자를 비교하는 클래스

[입력값 검증 기능]

  • validateInput — 유저 입력값을 4가지 기준으로 검증
    • 숫자가 아닌 경우
    • 3자리가 아닌 경우
    • 중복된 숫자가 있는 경우
    • 0이 포함된 경우 (1~9 범위 외)
  • 검증 실패 시 throw Error → submitButton 에서 try-catch로 alert으로 에러 메시지 출력
    • play() 실행 전에 먼저 validateInput()을 호출해서, 유효하지 않은 입력이 게임 로직까지 넘어가지 않도록 했습니다. throw Error 방식을 사용한 이유는, 검증 실패 시 즉시 흐름을 끊고 submitButton의 try-catch에서 한 곳에서 에러를 처리할 수 있기 때문입니다.

[결과 계산 기능]

  • play(computerInputNumbers, userInputNumbers) — 컴퓨터 숫자와 유저 숫자를 비교
    • 같은 위치에 같은 숫자 → 스트라이크
    • 다른 위치에 같은 숫자 → 볼
    • {strikes, balls} 카운트 후 getResult()로 결과 문자열 반환
    • for문으로 인덱스 0~2를 순회하면서, 먼저 같은 위치(===)를 확인하고, 아니면 includes()로 다른 위치에 포함되는지 확인하는 순서로 판정했습니다. else if를 사용해서 하나의 숫자가 스트라이크와 볼에 동시에 카운트되지 않도록 했습니다.

[결과 출력 기능]

  • getResult(strikes, balls) — 결과 문자열 반환
    • 스트라이크, 볼 모두 0 → "낫싱"
    • 볼만 있을 때 → "X볼"
    • 스트라이크만 있을 때 → "X스트라이크"
    • 둘 다 있을 때 → "X볼 Y스트라이크" (볼 먼저)
    • 요구사항에서 볼을 먼저, 스트라이크를 나중에 출력하라고 되어있어서 if-else 분기로 4가지 경우를 나누어 처리했습니다. play()에서 카운트한 strikes, balls 값을 그대로 받아서 문자열로 변환하는 역할만 담당합니다.

index.js (DOM 연결 및 게임 흐름)

[랜덤 숫자 생성]

  • randomNumbers() — MissionUtils.Random.pickNumberInRange(1, 9)를 활용하여 중복 없는 3자리 숫자 배열 생성
    • while문으로 배열 길이가 3이 될 때까지 반복하고, includes()로 이미 뽑힌 숫자인지 확인하여 중복을 방지했습니다. Set 대신 배열 + includes를 사용한 이유는 3개라는 작은 크기에서는 배열이 더 직관적이라고 판단했기 때문입니다.

[이벤트 처리]

  • submitButton 클릭 → userInput 값 가져옴 → text 형태니 숫자 배열로 변경후 입력 검증 validateInput
    → 결과 계산 play → 화면 출력 resultDiv
    • e.preventDefault()로 폼 제출 시 페이지 새로고침을 방지하고, validateInput → play → resultDiv 순서로 한 흐름 안에서 처리했습니다. 결과가 "3스트라이크"인 경우에만 재시작 버튼을 노출하도록 문자열 비교로 분기했습니다.
  • 3스트라이크 시 재시작 버튼 노출 (restartButton.style.display = "block");
  • restartButton 클릭 → 새 랜덤 숫자 생성 + 화면 초기화 (userInput, resultDiv, restartButton)
    • 재시작 시 새로운 랜덤 숫자를 생성하고, 입력창·결과창·재시작 버튼을 모두 초기 상태로 되돌려서 처음부터 다시 게임을 시작할 수 있게 했습니다.

MVC 패턴 리팩토링

기능 구현 이후, MVC 패턴으로 리팩토링을 진행했습니다.

Model (src/models/BaseballGameModel.js)

  • computerNumbers를 this로 자체 관리 (constructor에서 초기화)
    • 모두에게 같게 보여지는 값인가? 에 대한 생각을 해봤을 때, 컴퓨터 랜덤값은 사용자가 입력하는 상태에 관계없이 같은 값을 입력받기에 Model에 정의했습니다. 그리고 index.js : 98에서 첫 시작(생성할 때) 때 랜덤 숫자가 생성되니까, BaseballGameModel 에 constructor에서 this.computerNumbers = this.randomNumbers(); 같은 로직으로 진행했습니다.
  • play()는 userInput만 파라미터로 받고, computerNumbers는 내부에서 사용
    • 기존 index.js에서는 play(computerInputNumbers, userInputNumbers)로 두 파라미터를 받았는데, Model로 옮기면서 computerNumbers가 this에 있으니 외부에서 넘겨줄 필요가 없어졌습니다. Controller에서는 play(userInput)만 호출하면 되어 인터페이스가 단순해졌습니다.
  • validateInput(), getResult(), randomNumbers() 등 데이터 처리 로직 담당
  • Controller, View에 의존하지 않음

View (src/views/BaseballGameView.js)

  • DOM 요소 선택 및 화면 조작만 담당
  • displayResult(), showRestartButton(), resetView() 등 표시 로직
  • submitButtonListener(), restartButtonListener()로 콜백 등록 방식 사용
    • 기존 index.js에서는 모듈 레벨에서 직접 addEventListener를 등록했는데, View로 분리하면서 콜백을 파라미터로 받는 방식으로 변경했습니다. 이렇게 하면 View는 "버튼이 클릭되면 이 콜백을 실행해줘"라는 역할만 하고, 실제 로직은 Controller가 결정하게 됩니다.
  • Model 데이터는 Controller를 통해서만 전달받음

Controller (src/controllers/BaseballGameController.js)

  • Model과 View를 연결하는 역할
  • constructor에서 이벤트 리스너 자동 등록
    • new BaseballGameController(model, view)를 호출하면 constructor 안에서 submitButtonListener()와 restartButtonListener()가 바로 등록됩니다. 별도의 init() 메서드 없이 생성과 동시에 게임이 준비되도록 했습니다.
  • 입력 검증 → 게임 실행 → 결과 표시 흐름 제어
    • submitButtonListener 안에서 model.validateInput() → model.play() → view.displayResult() 순서로 호출하여, Controller가 Model과 View 사이의 데이터 흐름을 중재합니다.
  • try-catch로 에러 핸들링 후 alert() 출력

App.js (src/App.js)

  • new BaseballGameController(model, view) 한 줄로 MVC 조립
    • index.html에서 App.js를 모듈로 로드하면, Model → View → Controller 순서로 생성됩니다. Controller 생성 시 Model과 View를 주입받는 구조라서, 나중에 Model이나 View를 교체하더라도 App.js에서 생성 부분만 바꾸면 됩니다.

❓ 질문사항

1. 처음부터 MVC로 나눠서 만드는 게 더 좋을까요?

이번 미션에서는 index.js에 모든 기능을 먼저 구현한 뒤, MVC 패턴으로 리팩토링하는 순서로 진행했습니다.
처음부터 model, view, controller로 나누고 개발을 시작하는 것이 더 좋은 방법인지 궁금합니다.
저는 우선 동작하는 코드를 만들고 나서 구조를 잡는 게 이해하기 쉬울 것 같아서 이 순서로 진행했는데, 실무에서는 어떤 순서를 선호하시는지 듣고 싶습니다.

2. 폴더 이름은 단수(model)와 복수(models) 중 어떤 것이 좋을까요?

저는 models, views, controllers로 복수형 폴더명을 사용했는데, 프로젝트에 따라 model, view, controller처럼 단수형을 쓰는 경우도 본 것 같습니다.
어떤 네이밍 컨벤션이 더 일반적인지, 혹은 팀마다 다른 것인지 궁금합니다.

💭 고민사항

스터디 진행 방식과 AI 활용에 대한 고민

사실 저는 이런 개발 스터디가 처음입니다.
그래서 미션을 진행할 때 AI를 최대한 활용하지 않으려고 했고, 가능한 한 제가 아는 선에서 직접 코드를 짜려고 노력했습니다.

모르는 메서드나 해결되지 않는 오류가 있을 때에만 구글링과 AI의 도움을 받았고, MVC 패턴에 대해서는 방향성을 물어보면서 공부하는 방식으로 진행했습니다.

그런데 미션을 끝내고 보니, 이 방법이 맞는 건지 고민이 됩니다.

  • AI에게 코드를 대신 짜달라고 하지 않더라도, 방향성이나 설계를 물어보며 공부하는 것은 괜찮은 방법일까요?
  • 아니면 처음부터 끝까지 혼자 고민하고, 리뷰어님께 피드백을 받는 것이 더 나을까요?
  • 앞으로 미션을 진행할 때, 어떤 방식으로 학습하면 가장 효과적일지 조언을 듣고 싶습니다.

마치며

혹시 앞으로 더 주의해야 할 점이 있다면 말씀해 주시면 감사하겠습니다.

EM-H20 added 20 commits March 16, 2026 00:46
- toNumberArray 함수를 만들어서 반복 패턴 줄임
- id(#). class(.) 등 유연하게 선택자 사용할 수 있게 getElementById 말고 querySelector DOM 요소 선택
https://github.com/woowacourse-projects/javascript-mission-utils#mission-utils

README 에 적힌   const randomNumber = Random.pickNumberInRange(1, 9);

이게 아니라. 문서 안에 있는 사용법 참고결과 앞에 MissionUtils 붙여야함.
HTML form의 기본 동작은 버튼 클릭 시 서버로 데이터를 전송하고 페이지를 새로고침함.
서버 없이 JS로만 처리하므로 e.preventDefault()로 새로고침 막음.
submitButton 클릭 시 랜덤 함수가 호출되어, 확인할 때마다 정답이 바뀌는 문제 수정.
랜덤 함수 호출 시점을 게임 시작 시(첫 게임 및 재시작 버튼 클릭 시)로 변경.
컴퓨터 랜덤 숫자는 이미 숫자 배열로 생성되므로 toNumberArray 적용시 split으로 인해 [1, NaN, 2, NaN, 3] 같은 잘못된 값이 도출되는 문제 수정
@EM-H20 EM-H20 changed the title [1단계 미션] 홍의민 미션 제출합니다. [1주차] 홍의민 미션 제출합니다. Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant