2 분 소요

서론

저번 조영호 님의 “애플리케이션 아키텍처와 객체지향” 강의를 보고 우아한테크코스 2주차 과제 - 자동차 경주 게임에 적용한다고 말씀드렸습니다. 이번 글에서는 CRC Card를 통해서 객체의 책임과 협력 관계를 표현하고 적용하는 과정을 살펴보겠습니다. 그리고 MVC 패턴에서 InputView에 대해서 심각한 고민을 했는데 어떤 고민이였고 해결 방법은 무엇인지도 살펴보도록 하겠습니다.

CRC Card를 적용한 과정과 사소한 문제 해결

아래는 우아한 테크코스 2주차 과제의 기능 요구 사항입니다. 아래를 보고 명사를 추출해 CRC Card를 사용해 객체의 책임과 협력을 그려봤습니다.

초간단 자동차 경주 게임을 구현한다.

1. 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출  있다. -> 자동차
2.  자동차에 이름을 부여할  있다. 전진하는 자동차를 출력할  자동차 이름을 같이 출력한다. -> 자동차 이름
3. 자동차 이름은 쉼표(,) 기준으로 구분하며 이름은 5 이하만 가능하다. -> 자동차 이름 & 예외
4. 사용자는  번의 이동을  것인지를 입력할  있어야 한다. -> 사용자
5. 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한  무작위 값이 4 이상일 경우이다. -> 무작위 
6. 자동차 경주 게임을 완료한  누가 우승했는지를 알려준다. 우승자는   이상일  있다. -> 우승자
7. 우승자가 여러 명일 경우 쉼표(,) 이용하여 구분한다. -> 우승자
8. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨  애플리케이션은 종료되어야 한다. -> 사용자 & 예외

추출해본 명사는 자동차, 이름, 사용자, 우승자입니다. 객체 후보들은 자동차, 사용자, 우승자 정도가 될 수 있겠습니다. 하지만 우승자는 사실 자동차 이름이기 때문에 자동차 == 우승자가 되어버리고 사용자는 값을 입력하기만 합니다. 이는 나중에 Viewer 계층에서 해결했습니다.

따라서 저는 1차적으로 Car, GameManager 두 객체를 CRC Card에 그렸고 아래와 같이 협력, 책임을 설정했습니다.

절차지향이미지

1차 구현이 끝나고 코드를 뒤돌아 보는데 GameManager 객체에는 아무런 코드가 없었습니다. 순간 당황해서 randomNumber를 생성하는 곳을 봤더니 서비스 레이어에서 메서드로 추출해 사용하고 있었습니다. 이처럼 너무 작은 책임은 Service 레이어에서 해결할 수 있기 때문에 삭제 했습니다.

public class RacingGameManager {

    // 책임
    // 1. 무작위 값을 알아야 한다.

    // 협력
    // 1. Car

}

(텅텅 빈 객체)

MVC 패턴에서 InputView 위치에 대한 궁금증

제가 생각하기에 InputView의 위치는 Browser와 Controller 사이에 있어야 한다고 생각했습니다. KEEPER R2 프로젝트를 뒤돌아 봤을 때는 Browser(Front)에서 순수한 데이터의 모음인 Request DTO를 받고 Controller에서 Input값을 검증하고 있어 MVC 패턴의 흐름을 이해하는데에 있어 큰 어려움은 없었습니다.

절차지향이미지

하지만 프리코스에서는 Browser에서 DTO로 값을 넘겨주지 않고 Console 창을 이용해 값을 넘겨주게 됩니다. 그렇게 된다면 “InputView의 위치는 Browser와 Controller 사이에 있어야 하지 않나?”라는 생각이 1주일 동안 머릿속에 뱅뱅 돌았습니다. 그래서 1주차 프리코스에는 InputView -> InputUtil로 만들고 컨트롤러에서 사용자의 입력값을 받고록 했었습니다.

이 문제의 해결은 항상 큰 도움을 받고있는 의문의 코딩 장인 선배님께 여쭤봄으로써 해결했습니다! 단축해서 설명드리자면 InputView는 브라우저 그 자체라고 생각하면 된다고 말씀해주셨습니다. InputView, OutputView를 프론트라고 생각을 해본다면 위의 사진에서 나타내는 MVC 패턴의 흐름을 막힘없이 이해할 수 있습니다.

따라서 선배님의 말씀을 제 나름대로 적용한 Layer는 아래와 같습니다.

절차지향이미지

Layer를 나누는 이유

위의 InputView에 관한 답변을 해 주시면서 KEEPER R2 프로젝트에서 왜 3-tier Layer로 나눴는지 부가적으로 설명해 주셨습니다. 이유는 바로 “변경에 유연하기 위해서”입니다. repository 계층은 DB에서 데이터를 가져오는 역할을 하는데, 만약 mysql에서 oracle로 바꾼다고 가정해도 service 코드나 controller의 코드를 변경할 필요는 없습니다. 오직 repository 계층에서 mysql 문법을 oracle 문법으로 바꾸면 됩니다.

이는 controller와 service 계층에서도 동일하게 적용됩니다. 조영호님의 “아키텍처와 객체지향” 강의에서도 Layer를 나누는 이유에 대해서 설명해주셨습니다. 하지만 케이크 빵을 예시로 추상적으로 설명해주셔서 궁금증이 생겼지만 선배님꼐서 구체적인 예시를 들어주셔가지고 Layer를 이해하는데 정말 큰 도움이 됐습니다.

마치며

객체의 책임과 역할을 설정할 때 CRC Card를 사용하면 훨씬 쉽게 할 수 있습니다. 그리고 MVC 패턴에서 InputView와 OutputView를 프론트라고 생각한다면 흐름을 쉽게 이해할 수 있었습니다. 마지막으로 Layer를 나누는 이유에 대해서 알아봤습니다. 제 궁금증을 해결해주신 선배님께 정말 감사를 표하고 다음 글은 우아한객체지향 강의를 보고 정리한 내용을 작성해보도록 하겠습니다.

참조

[아키첵처와객체지향 영상] https://www.youtube.com/watch?v=26S4VFUWlJM&pp=ygUJ7KGw7JiB7Zi4

[MVC 패턴 사진] https://woo-chang.tistory.com/52