이번주 계획
이번주 목표
3주차에 학습했던 객체를 객체답게 사용하는 방법에 대해 학습을 진행하자!
구현을 함에 있어서 학습 목표는 다음과 같았다.
- 도메인과 UI로직을 분리해서 구조를 작성하기
- 단방향 흐름을 잘 지키기
- 의존성을 주입을 통해 테스트를 하기 쉬운 코드를 작성하기
이번주 내 활동
🔍 피어리뷰 스터디
디스커션을 보다가 정말 열심히 같이 성장하고 있는 스터디의 리뷰가 올라온 것을 포착했다. 공유해주신 스터디 요약을 보고 그 분들이 다른 동료들에게 남겨준 피어리뷰를 확인해보니 배울 것이 많은 스터디 같았다. 바로 해당 스터디원에게 슬랙으로 DM을 보냈다…! 스터디원분들이 전부 동의를 해주셨고 그렇게 스터디를 같이 진행하게 되었다.🤗
일주일동안 슬랙에서 같이 모각코를 진행하고 미션을 제출한 수요일 저녁에 피어리뷰를 진행헀다. 내가 보지 못했던 실수들이나 개념들에 대해 학습자료를 공유하면서 리뷰를 진행해주셔서 배울 점이 굉장히 많았고 좋은 학습자료들도 소개받았다.
미션은 끝났지만 앞으로 남은 기간동안 스터디를 꾸준히 계속 진행하기로 되어 있어 이번주는 새로운 것을 하는 게 아닌 여태까지 4주동안 배운 것을 다시 2주차 미션에 적용해보기로 했습니다!!
🔍 프론트엔드 아키텍쳐 학습
프론트엔드 아키텍처의 가장 최근 트렌드는? | 요즘IT
고민한 부분들
1️⃣ 전체 구조… 그리고 MVC 패턴?
📸 각 객체 및 클래스가 하는 역할
이번 미션에는 미리 View가 분리되어 제공이 되었다. 지난 주차 로또 미션을 진행할 때 미리 View를 분리하면서 비동기로 입력값을 받는 JS에 대한 충격을 미리 받아놔서 다행이라고 생각이 들었고 지난주와 같은 흐름으로 다음과 같이 전체적인 흐름을 짰습니다.
*View → Controller → Service → Domain *
- View : 사용자의 입력값을 받고 출력을 진행합니다.
- Controller: 뷰와 서비스 사이에서 뷰에서 데이터를 받아서 Service에게 요청사항에 따른 동작을 정의하는 역할을 합니다.
- Service: Controller가 행동을 선언했다면 실제로 동작, 즉 구현을 하는 부분은 Service에서 진행을 합니다.
- Domain: 실제 게임을 조작하는 동작을 하는 곳입니다.
미션 코드 자체가 View를 분리해 사용하고 domain과 UI를 분리하라는 요구사항이 있다보니 다른 동료분들은 MVC패턴으로 짜신 코드를 많이 봤습니다.
여기서 잠깐!!!!!!!!!
저는 이전에 MVC패턴에 대해 학습을 진행했었습니다. 모델, 뷰, 컨트롤러의 역할에 대해 알지만 이번 미션은 비동기인 입력값 받기를 컨트롤러에서 진행할 수 없기에 MVC패턴에서 가장 중요한 부분을 생각해봤습니다. 제가 생각했을 때 MVC패턴에서 가장 중요하고 지켜야 하는 부분이 구조의** 흐름이 단방향으로 흘러가야 한다**라는 것입니다.
제가 학습했던 MVC패턴의 흐름입니다.
하지만 이번 미션에서 **Controller가 입력값을 받아오라고 직접적으로 명령을 해도 되는가?**
에 대한 고민이 많았습니다.
제리의 테코톡 MVC를 확인하면 MVC패턴에서의 Controller는 View의 코드를 알고 있어도 된다입니다.
하지만 여기서 저는 Controller
는 View
의 코드를 알고 있어도 되지만 입력을 받으라고 하는 명령 자체를 Controller
가 해도되는 가에 대한 깊은 고민 끝에 View라는 곳을 만들어 진행했습니다.
*View → Controller → Service → Domain *
따라서 저의 코드 구조가 위와 같이 View가 스스로 입력값을 받고 흐름을 가지고 있게 작성했고 그 결과 View가 Controller를 알게되는 구조로 작성을 했습니다.
사실 이렇게 짜게 되면 MVC패턴을 기반으로 코드를 작성한게 아닙니다. 그렇다면 여기서 말한 제 코드 구조의 Controller는 MVC패턴의 Controller가 아닌 정말 게임의 동작들을 Controll하는 클래스가 됩니다.
하지만 다른 동료분들의 코드를 보니 MVC패턴을 사용하려면 Controller에서 입력을 받아오라고 명령을 하고 View를 정말 출력을 위한 용도로 사용한 것을 보고 또 다른 관점에서 저렇게 짤 수 있구나라는 생각과 오히려 저렇게 View를 출력의 용도로 사용할 수 있구나라는 다른 인사이트를 얻을 수 있었습니다.
2️⃣ 테스트 코드
1. 의존성 주입
테스트를 하기 좋은 코드를 위해 의존성을 주입시켜주는 방향으로 코드를 짜는 노력을 했다. 이번 미션에서 BridgeRandomNumberGenerator객체는 랜덤으로 다리 숫자를 만드는 객체이다. 이는 테스트를 하기 어려운 객체 이기 때문에 게임 동작을 구현하는 BridgeGame 안에서 직접적으로 랜덤 숫자를 만드는 것이 아닌 외부에서 한 단계를 거쳐 주입을 받아야 한다.
테스트를 하기 어려운 코드는 최대한 분리를 하는 연습을 할 수 있었습니다.
2. 중복된 테스트 코드 제거
지난 주 까지 작성했던 테스트 코드들은 중복이 너무 많았습니다. 같은 결과를 내는 하나의 test안에서 중복적으로 여러 객체를 만들어 테스트를 진행했었습니다.
test("당첨 번호가 숫자가 아닌 경우 예외가 발생한다.", () => {
expect(() => new WinNumber("1,가, ,as,")).toThrow(
"[ERROR] 당첨 번호는 숫자여야 합니다."
);
expect(() => new WinNumber("!,,1!,$#@ ,a")).toThrow(
"[ERROR] 당첨 번호는 숫자여야 합니다."
);
});
이런 중복을 막고자 test.each
를 사용해 여러 테스트 케이스들을 하나의 test에서 진행하도록 코드의 중복을 줄였습니다.
test.each([["u"], ["d"], [" "], [" U"], ["D "]])(
"입력한 이동 칸 수 가 U 또는 D가 아니면 에러가 발생한다.",
(testString) => {
const bridgeSpaceValidator = new BridgeSpaceValidator();
expect(() => bridgeSpaceValidator.validate(testString)).toThrow();
}
);
3. 두가지 경우를 다 테스트하자
입력값에 대한 유효성 검증을 진행할 때 이상한 입력값이 들어오면 에러를 던지고 있지?! 만 확인하는 것이 아닌 옳은 입력값을 던졌을 때 에러를 던지지 않는 상황 또한 테스트를 진행했고 이는 not
를 통해 구현을 했습니다.
test.each([["U"], ["D"]])(
"입력한 이동 칸 수 가 U 또는 D면 에러가 발생하지 않는다.",
(testString) => {
const bridgeSpaceValidator = new BridgeSpaceValidator();
expect(() => bridgeSpaceValidator.validate(testString))**.not**.toThrow();
}
);
4. 테스트 코드도 코드이다
지난 주 피드백에서 테스트 코드도 코드이다라는 피드백이 있었습니다. 그 피드백을 위해 위와 같이 중복을 제거하는 방법을 사용하기도 했지만 실제 src와 구조를 동일하게 변경했습니다. 기존에는 test내부에 모든 테스트 코드를 다 넣었지만 다음과 같이 동일한 구조로 작성했습니다.
3️⃣ Domain??
지난 로또 게임 미션을 진행하면서 도메인에 대한 이해가 높아졌고 이를 이번주차에 활용하고 자 했습니다. 그렇지만… 이번주 미션을 보니 다리 게임을 진행하는 메인 도메인 그리고 게임을 진행할 때 필요한 다리라는 도메인을 제외하고는 도메인이 없었고 오히려 도메인을 만들고자 클래스를 분리하는 것은 도메인이 아니라는 생각이 들었기에 BridgeGame 클래스 안에 게임과 관련된 동작들을 다 넣어 구현을 했습니다.
하지만 이번 미션이 종료되고 MVC패턴에 대해 한 번 더 생각해보고 다른 동료분들의 코드를 보니 다리 게임에 필요한 데이터들을 Model로 분리하고 BridgeGame은 Model의 데이터를 가지고 구현만 하는 코드를 짤 수 있겠구나 라는 인사이트를 또 얻게 되었습니다.
4️⃣ 세부적인 것도 챙기자
이 부분은 스터디를 진행하고 나서 깨닫게 된 점입니다.
저는 4주간 미션을 진행하면서 객체에 대한 이해를 높이고자 전체적인 구조에 대한 학습을 중점적으로 진행했습니다. MVC패턴을 사용을 하면 전체적으로 어떤 흐름으로 구조를 짜야하나에 대한 고민에 많은 시간을 쏟았습니다. 하지만 이번 피어리뷰 스터디를 진행하면서 제가 너무 전체적인 것에만 집착을 했다고 느꼈습니다. 세부적으로 고차함수를 사용해 성능을 높이고 어떤 고차함수를 사용해야지 효율성을 높일 수 있는 지, 데이터마다 배열로 전달하는 것이 옳은 지 객체가 옳은 지, 네이밍은 어떤식으로 지어야 하는 지 등에 대한 세부적은 요소들을 챙기지 못했습니다. 여태까지 전체적인 구조나 흐름에 대해 익히는 연습을 진행했다고 생각하고 이후에 리팩토링을 진행하면서 세부적인 부분을 더 챙기는 연습을 해보려고 합니다.
총 회고
최종 회고
이번 과제는 이전 주차까지 배운 것을 최대한 적용해보고자 모든 피드백들을 참고하면서 진행했습니다. 4주 동안 과제를 진행하면서 이번 미션 코드를 가장 오랫동안 쳐다봤던 것 같습니다. 하나의 고민이 들면 모든게 꼬리를 이어가듯이 고민을 할 수 있는 시간이 길어서 좋았고 고민을 하는 시간이 길어지다보니 예외 사항들을 코딩을 진행하는 프로그래머 관점, 실제로 게임을 진행할 사람의 관점을 생각해보며 추가를 했습니다. 에러를 처리하거나 단위테스트를 진행하는 방법이 익숙해지니 다른 고민들을 추가적으로 할 수 있었던 것 같습니다. 특히 테스트도 코드라는 피드백을 받고 나서 테스트 구조를 실제 소스와 동일하게 작성을 하도록 진행을 했습니다. 1주차와 2주차를 진행하면서 테스트를 하기 좋은 코드라는 것이 정확히 무엇인지에 대한 의문이 있었고 테스트를 위한 코드가 아닌지 라는 의문을 가졌습니다. 하지만 추가적으로 2주차를 더 진행을 해보고 테스트를 위한 코드가 아닌 테스트를 하기 어려운 코드라면 주입되고 있는 데이터, 들고 있지 않아야 할 데이터, 즉, 해당 객체가 해야하는 일 들만 최소한으로 정의하는 코드가 테스트를 하기 좋은 코드라는 인사이트를 얻었습니다.
지난 로또 미션과 이번 미션을 진행하면서 도메인에 대한 생각도 넓어진 것 같습니다. 맹목적으로 역할을 분리하는 것은 도메인이 아니라는 것도 깨닫게 되었습니다. 지난 주에는 a라는 시각을 얻었다면 이번 주에는 또 다른 b에 대한 시각을 스스로 얻을 수 있는 경험을 할 수 있었습니다.
프리코스를 진행하기 이전과 현재를 비교해보면 짧았던 4주이지만 많이 성장할 수 있었던 것 같습니다. 특히 디스커션에서 사람들과 소통을 할 수 있던 부분이 성장을 하는 데 큰 도움을 주었습니다. 내가 학습했던 컨텐츠에 부족한 부분이 있으면 다른 동료들이 채워주고 그 부분을 학습해가며 다양한 시각을 얻어가고 스스로 내 자신이 생각하기에 효율적이고 좋은 방향은 무엇일까 라는 고민을 할 수 있는 힘이 더 커진 것 같습니다. 다른 동료들이 아고라를 올리면 스스로 나 또한 자료를 찾아 학습해가고 좋은 자료가 있으면 공유해 토론을 하는 것이 실력향상에 많은 도움을 주었던 것 같습니다. 또한, 코드리뷰는 제가 놓쳤던 혹은 조금 더 효율적인 방법을 서로 제시하면서 제 코드에 대한 다른 시각을 얻을 수 있던 것이 좋았습니다. 특히 코드리뷰를 받고 조금 더 효율적인 방법을 제시해주었지만 그 방법을 보고 제게서 다른 시각이 떠올라 토론을 하는 것이 굉장히 신선했습니다. 다른 동료들의 코드를 읽으면서 가독성이 좋은 코드에 대한 인사이트도 얻을 수 있었고 다른 방법으로 접근한 코드가 있다면 새로운 것을 배우는 것에 재미를 많이 느꼈습니다. 모든 것을 진행하면서 스스로 문제를 해결하기 위해 효율적인 아키텍쳐를 짜는 방법을 배울 수 있었습니다.
이번주 계획
이번주에는 현재 4주를 달려오고 나서 얻은 인사이트를 가지고 2주차부터 다시 리팩토링을 진행할 계획입니다.
'우아한테크코스 5기' 카테고리의 다른 글
[우테코 5기 프리코스] 우테코 5기 3주차 회고 (1) | 2022.11.22 |
---|---|
[우테코 5기 프리코스] 우테코 5기 2주차 회고 (2) | 2022.11.10 |
[우테코 5기 프리코스] 우테코 5기 1주차 회고 (0) | 2022.11.04 |
nvm으로 node 버전 변경하기 (0) | 2022.11.04 |