Skip to content
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단계 미션 제출합니다. #10

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Conversation

opehn
Copy link

@opehn opehn commented Oct 1, 2024

src
├── const
│   └── num-range.ts
├── domain
│   ├── command.model.ts
│   └── game-number.model.ts
├── main.ts
├── service
|    ├── result.service.ts
│   └── game.service.ts
└── ui
    └── Game
        ├── game.controller.ts
        └── game.presenter.ts

test
├── game.service.test.ts
└── target-number.model.test.ts

const: 숫자 범위 제약사항을 nu-range.ts에 상수화 해서 사용하였습니다

domain: 사용자 명령을 나타내는 value object인 Command와 숫자 야구 대상이 되는 숫자 세 개를 나타내는 일급 컬렉션 TargetNumber 클래스가 있습니다

service:
ResultService

  • 결과 판정 담당
  • GameService의 playGame에서 루프를 돌 때마다 이 서비스의 인스턴스를 새로 생성하는게 맞나 싶었는데 그렇게 하지 않으려면 ResultService 정답과 사용자의 추측, 결과를 ResultService의 멤버 변수로 만들어 루프 돌 때 마다 setter로 할당해야 하는데 이 방법이 더 복잡하고 상태를 가지게 되어 취약한 것 같아 이대로 두었습니다

ui : 사용자와 상호작용하는 입출력을 담당하고 있습니다.

  • presenter는 사용자에게 출력될 메세지를 모아둔 클래스입니다
  • 컨트롤러는 입/출력과 서비스를 연결합니다

test: domain 객체와 서비스 로직에 대한 테스트를 구현했습니다.

  • 입출력이 개입되는 부분은 테스트 방법을 고민중에 있어 비즈니스 로직에 해당하는 부분만 테스트가 작성되어있습니다.

- gitignore
- prettierrc
- jest.config.ts, tsconfig
- pacakage.json에 명령어 세팅
- node readline의 프로미스 인터페이스인 rl.question을 사용했다
- 숫자 야구의 대상이 되는 세 개의 숫자를 나타내는 BaseNumber 클래스를 구현했다
- 처음 랜덤으로 숫자를 생성할 때, 이후 사용자가 입력할 때 지속적으로
  1. 입력된 숫자가 세 개인지 2. 입력이 모두 숫자로 이루어져 있는지 등등
  제약사항을 검사해야 하기에 이를 중앙화 할 수 있는 Value Object 역할을 하는 클래스를 구현했다.
- 입출력 로직에서 command를 실행하는 부분을 함수로 분리했다
- 입력 옵션을 상수화해 의미를 명확히 알 수 있도록 변경했다
- 입력 옵션을 나타내는 Command 클래스를 구현해 예외 처리를 안으로 숨겼다
- validate 항목마다 메소드로 분리해 명확히 볼 수 있도록 변경했다
- TargetNumber 생성시 복잡한 로직이 필요함 :
중복되지 않는 1 ~ 9 사이의 숫자 세 개를 뽑아야 함
팩토리 클래스를 따로 구현해 캡슐화했다
- 제약사항 검증하는 부분 함수로 분리
- Command를 상수 하나하나로 관리하지 않고 CommandType으로 합쳐서 관리
- 사용자에게 지침을출력하는 부분을 Presenter로 분리
- 수정 이유 : 지침 내용을 수정해야 할 때 비즈니스 로직과 분리되어 있어 Presenter 클래스만 수정해도 된다
- Controller 클래스는 유저 인풋을 받고 서비스 로직에 전달하는 역할을 담당
- GameService 클래스에 서비스 로직 구현

- 게임 진행하면서 지속적으로 유저 인풋을 받고 결과를 출력해야 하는 부분 때문에 컨트롤러와 서비스 로직의 분리가 어려웠음
  -> 인풋 받고 /출력하는 메소드를 서비스에 인자로 넘겨서 책임을 최대한 분리

- 테스트는 비즈니스 로직에 해당하는 compareNumbers에 대해서만 구현,
    playGame 메서드는 어떻게 테스트해야할지 고민
  모든 경우의 수를 검증하려면 테스트 코드가 너무 커져서 기본적인 경우만
  테스트

- 서비스와 컨트롤러는 싱글톤 패턴을 적용
- TargetNumber -> GameNumber로 네이밍 변경
- 팩토리 클래스를 없애고 정적 팩토리 메소드를 만들어 인풋을 통한 생성 /
  랜덤 문자열로 생성 두 가지 경우 모두 하나의 클래스에서 생성할 수
  있도록 변경함
- 랜덤 문자열 생성하는 함수들은 도메인 의존성을 없애고 유틸로 분리
- 결과 판정 로직을 ResultService로 분리했다
- 책임을 분리해 GameService에서는 결과 판정 로직을 알 수 없게 되었고 로직 변경이 GameService로 전파되지 않아 유지보수성이 높아졌다
- 결과 자체를 다루는 서비스가 생겨 comapareNumber에 대한 테스트 문제도 해결되었다
- 하지만 루프를 돌 때마다 ResultService를 생성해야 해 성능에 약간 안좋을 수 있다
- 매번 생성하지 않으려면 targetNumber, guessNumber, result를 멤버 변수로 갖고 매번 setter로 할당해줄 수 있는데 그렇게 하면 상태를 가지게 되어
  취약점이 생길것같아 이대로 두기로 했다
- ResultService를 분리하고 나니까 GameService의 존재 의미가 사라져서 삭제했다
- 컨트롤러에서 게임 진행을 도맡도록 해서 콜백 메서드를 넘기지 않아도 되게 되었다. 이게 나은 것 같다
- ResultService도 매번 생성하지 않고 GameController 생성시에 인스턴스를받고 재사용하게 바꾸었다.
- runGame에서 상수를 그대로 사용하기보다 인자로 받도록 바꾸어 테스트에용이한 구조로 바꾸었다
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