1. 프리코스 1주차가 끝나고 나서의 상황 ( 배운점 )
1주차 미션을 완료한후 아침에 눈을 떠보니 디스코드 알람이 여기저기 울렸습니다. 바로 서로 리뷰하기 채널의 활동이 시작된 것 이였습니다.
저는 이번 2주차 미션에서 단순히 코드를 작성하는 것 이상의 무언가를 필요로 했습니다. 그것이 바로 '코드 리뷰' 인 것 같았습니다.
코드 리뷰는 제가 성장하는데 있어 가장 중요한 요소 중 하나라고 생각했기 때문입니다. 이에 저는 다양한 사람들과 코드 리뷰를 하면서 제가 그동안 놓쳐왔던 부분이 있는지 어떤식으로 개선하면 사람들에게 좀더 읽기 쉬운 코드가 될 수 있는지를 좀더 다양한 사람들과 토론을 하고 싶어했고 마침내 처음으로 코드리뷰하는 시간이 열린 것 입니다.
다양한 사람들과 함께 코드 리뷰를 해주고, 받는식으로 리뷰를 진행 하였습니다. 각자의 다른 관점과 접근 방식을 경험하면서, 저 스스로도 많은 것을 배울 수 있는 계기가 되었던것 같습니다. 이러한 경험을 기반으로 2주차 미션을 어떻게 접근하고 완료할지에 대한 중요한 배경이지 않을까 싶습니다.
메서드 명은 처음 보는 사람들이 알아볼수 있게 작성하자!
메서드 명이 아무리 길어지더라도 내가 원했던 의도가 드러나게 작성할 필요가 있었습니다.
각 클래스 별로 역할과 책임을 준수하자!
각 클래스가 어떤 역할을 하고 있는지 확실하게 알아야 할 필요가 있었습니다. 1주차 미션에서 유효성 검증을 처리하는 로직을 별도의 클래스나 함수로 분리하여 BaseballGame클래스에 게임 진행에만 집중할 수 있도록 했어야하는데 유효성 검증을 BaseballGame 클래스에서 진행 했었습니다. 이는 게임진행도하면서 플레이어의 입력값또한 검증까지 하고 있어서 역할이 모호해진다는 리뷰가 있었습니다.
private 필드를 사용해서 캡슐화를 하자!
Javascript에서는 '#' 심볼을 사용하여 private 필드를 설정할 수 있습니다. 이는 클래스의 내부 상태를 외부로부터 잘 숨기는 캡슐화를 실현할 수 있습니다.
그렇다면 왜 private 필드를 사용해야 할까요?
1. 불변성 유지 : 객체의 상태가 외부에서 변경되지 않도록 보호합니다.
2. 안전성 보장 : 중요한 정보들을 외부로 부터 보호합니다.
3. 코드 유지보수성 향상 : 내부 상태를 숨기므로 내부 구현을 자유롭게 변경할 수 있습니다.
제 생각을 담아보자면 그렇습니다. 숫자야구게임에서 랜덤 숫자 3개를 뽑고 그 숫자를 리턴하는 경우가 있었는데 생각해보면 '랜덤 숫자를 뽑는것을 외부에서 굳이 알아야할까?' 라는 생각이 들었습니다. 그 숫자3개를 만드는 과정까지 알 필요는 없다는 것 입니다! 단순히 검증된 3개의 숫자만 알면 외부로부터 중요한 로직같은 정보들을 보호하면서 필요한 3개의 숫자만 노출할 수 있었습니다.
2. 프리코스 2주차 미션
우아한테크코스 6기 프리코스의 2주차 과제는 '초간단 자동차 경주 게임' 구현이였습니다.
여기에 대해 간략히 설명해보자면
- 기본 게임 규칙
- 게임에는 여러 대의 자동차가 참여하면서 각차량은 주어진 횟수 동안 전진하거나 멈출 수 있다.
- 참가하는 각 자동차에는 이름을 부여할 수 있으며, 이 이름은 게임 진행 중 화면에 표시된다.
- 자동차의 이름은 쉼표(,)로 구분하며, 각 이름은 5자 이하여야 한다.
- 사용자 입력
- 사용자는 자동차의 이름을 입력하고, 게임에서 몇번의 이동을 할 것인지입력해야한다.
- 게임 로직
- 자동차는 0에서 9사이의 무작위 값들을 생성하여 이 값이 4이상일 경우에만 전진한다.
- 레이싱 결과
- 게임을 시작하고 결과를 알려주어야하는데 결과를 출력함과 동시에 누가 우승했는지를 알려주어야 하며, 우승자가 여러 명일 경우 이를 쉼표(,)로 구분하여 출력한다.
또한 여기서 기존에 없었던 요구사항중에서 들여쓰기는 최대 2단계까지만 허용된다는 문구가 있었습니다.
이를통해 '아 이제부턴 정말로 객체지향 프로그래밍을 요구하는구나' 라고 생각하였습니다.
지난 1주차에서의 개선 방향과 나의 방향성을 잡으려고 시도 했습니다.
처음으로 위의 미션을 통해 구조를 먼저 생각해 보았습니다. 이번에는 디자인패턴중 MVC 패턴을 적용해 코드를 작성할 계획이였습니다.
간략한 MVC 패턴 설명
MVC 패턴 정리
Model : 애플리케이션의 데이터와 비즈니스 로직 관리
View : 사용자에게 보여지는 UI
Controller : 모델과 뷰를 연결하며, 사용자의 입력에 따라 모델을 업데이트하면서 뷰를 갱신 ( 게임의 전체 흐름을 관리 )
1. Model은 Controller와 View에 의존하지 않아야 한다. (Model 내부에 Controller와 View에 관련된 코드가 있으면 안된다.)
2. View는 Model에만 의존해야 하고, Controller에는 의존하면 안된다. (View 내부에 Model의 코드만 있을 수 있고, Controller의 코드가 있으면 안된다.)
3. View가 Model로부터 데이터를 받을 때는, 사용자마다 다르게 보여주어야 하는 데이터에 대해서만 받아야한다.
4. Controller는 Model과 View에 의존해도 된다. (Controller 내부에는 Model과 View의 코드가 있을 수 있다.) View가 Model로부터 데이터를 받을 때, 반드시 Controller에서 받아야한다.
폴더 구조
+ src
+ constants
└ ErrorMessages.js ------ 에러 메시지에 사용되는 상수를 저장
└ GameSettings.js ------ 게임 설정에 관련된 상수를 저장
└ Messages.js ------ 사용자에게 출력되는 메시지의 상수를 저장
└ ValidationRules.js ------ 입력 검증에 사용되는 규칙을 상수로 저장
+ controller
└ RacingGameController.js ---- 게임의 전체 흐름을 제어하는 컨트롤
+ model
└ Car.js ----- 자동차의 정보와 움직임을 관리하는 모델
└ movementStrategies.js --- 자동차의 움직임 전략을 담은 함수
└ Race.js ----- 경주 게임을 처리하는 모델
+ utils
└ InputValidator.js ------ 사용자 입력을 검증하는 클래스
└ CarNameProcessor.js ----- 사용자로부터 받은 자동차 이름을 처리하는 유틸 함수
+ view
└ InputView.js ------ 사용자로부터 입력을 처리하는 뷰
└ OutputView.js ------ 게임의 결과를 출력하는 뷰
export default class Car {
#name;
#position;
#carMovementStrategy;
constructor(name, carMovementStrategy) {
this.#name = name;
this.#position = 0;
this.#carMovementStrategy = carMovementStrategy;
}
getCarInformation() {
return {
name: this.#name,
position: this.#position,
};
}
move() {
if (this.#shouldMoveBasedOnStrategy()) {
this.#position += 1;
}
}
#shouldMoveBasedOnStrategy() {
return this.#carMovementStrategy.shouldMove();
}
}
import { Random } from '@woowacourse/mission-utils';
import { GameSettings } from '../constants/GameSettings';
export const randomMovementStrategy = {
shouldMove() {
const randomNumber = Random.pickNumberInRange(
GameSettings.MIN_RANDOM_NUMBER,
GameSettings.MAX_RANDOM_NUMBER
);
return randomNumber >= GameSettings.MOVE_THRESHOLD;
}
};
이부분에서 특이한 점은 바로 움직임 전략 분리(Strategy pattern) 입니다.
왜 이러한 움직임 전략 객체를 사용하였냐면 Car클래스 즉 자동차가 어떤 기준으로 움직이는지는 알 필요가 없으며, 그저 나는 움직이는 자동차다. 라는 것을 생각해보면 움직임 전략 객체를 알 필요가 없고 '나 움직여도 될까?' 라고 물어보면 전략 객체에서는 'TRUE' 혹은 'FALSE' 를 반환할 것 입니다. 이에 따라 자동차는 TRUE 이면 움직이고 FALSE이면 움직일 필요가 없습니다. 이는 의존성 역전 원칙(Dependency Inversion Principle)을 따르고 있습니다.
Jest 테스트 폴더 구조
+ __tests__
+ model
└ Car.test.js
└ Race.test.js
+ utils
└ CarNameProcessor.test.js
└ InputValidator.test.js
+ view
└ InputView.js
└ OutputView.js
이번 추가된 요구 사항중 2번째인 Jest를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인하는 부분이 있었습니다.
그래서전 각 클래스별로 메서드가 정상적으로 작동하는지를 테스트하였고 jest-html-reporters 라이브러리를 통해 테스트 결과를 HTML로 보기 쉽게 나타내었습니다.
2주차 미션을 통해 배운점
2주차 미션에는 기존 1주차 미션을 통해 아쉬웠던 점들을 개선하고자 몇 가지 목표를 세웠습니다. 여기에서는 그 목표들을 얼마나 달성했는지, 그리고 그 과정에서 느낀 점들에 대해 이야기 하려고 합니다.
목표 달성도
MVC 패턴 적용 - RacingGameController,Race,Car 클래스 등을 통해 각자의 클래스들이 분명한 역할을 가지고 있습니다. 이는 MVC 패턴을 어느정도 적용했다고 볼 수 있을 것 같습니다.
OOP - 마찬가지로 자동차와 레이스등의 클래스를 통해 책임과 역할을 분리하려고 노력해왔습니다.
Jest 단위 테스트 - 예외 상황이나 세부적인 케이스에 대한 테스트를 추가했습니다.
jest-html-reporters 활용 - 코드의 정확성을 검증하면서 또한 테스트 결과를 HTML 형태로 쉽게 확인할 수 있게 했습니다. 또한 다른 사람들에게 공유하기도 편리합니다.
마무리
전반적으로 1주차 미션 때 세운 목표들을 어느 정도는 달성했다고 생각합니다. 특히 MVC 패턴을 적용하면서 프로그램의 구조가 얼마나 중요한지 느꼈습니다. 그러나 아직 저는 부족하다고 느낍니다. 도메인 주도설계나 DTO 그안에 리포지토리 등 어떠한 구조를 가지고 있는지도 궁금해졌습니다.
1주차의 마음가짐과 현재의 마음가짐은 항상 같습니다. 항상 학습에 중점을 두어 내가 1주차 부터 4주차 사이에 얼마나 학습하고 성장했는지 나의 모습을 4주차가 끝나고 '마지막에 나는 어떤 모습일까?' 가 가장 중요한 것 같습니다.
한번 여러분들도 1주차의 나의모습과 2주차의 나의모습을 돌이켜 보면서 나의 코드가 얼마나 더 성장하였는지 보았으면 좋겠습니다.
'우아한테크코스' 카테고리의 다른 글
우아한테크코스 6기 프리코스 4주차 마지막 회고 (1) | 2023.11.16 |
---|---|
우아한테크코스 6기 프리코스 3주차 회고 (3) | 2023.11.09 |
JEST 테스트결과를 HTML로 보여주자! (0) | 2023.11.02 |
우아한테크코스 6기 프리코스 1주차 회고 (0) | 2023.10.23 |