[Design Pattern] MVC에서 Controller의 규모와 책임을 이상적으로 가져갈 수 있는 방법

Kame·2024년 3월 4일

Design Pattern

목록 보기
2/2

MVC 구성요소 중 하나인 Controller에 대한 고민

프리코스 때부터 현재까지, 대다수(라고 하지만 사실상 100%) 지원자분들과 크루들은 MVC 패턴을 채택하여 우아한테크코스의 미션을 진행했고, 진행해오고 있습니다. 이 글을 읽고 계신 다음 기수에서 활동하게 되실 예비 크루분들도 그러실 것이라 생각합니다.

그런데, 현재 미션을 진행하면서 많은 크루들이 코드 리뷰를 받을 때, 공통적으로 리뷰어 분들로부터 받고 있는 피드백이 있습니다.

"정말 Controller에서 해야 할 일인가요?"
"Controller의 책임을 Model로 옮겨보세요."

실제로 받았던 피드백들 자동차 경주 피드백 중로또 피드백 중

저 역시 자동차 경주와 로또 미션을 제출했을 때, 두 번 모두 이러한 요지의 피드백을 받았습니다.

이 피드백들은 MVC 중 Controller가 어떤 역할을 해야 하는지에 대해 제대로 알지 못하고 미션을 구현해왔음을 깨닫는 계기가 되었습니다. 또한 MVC 패턴을 채택하여 프로그램을 작성할 때는 이상적인 Controller의 역할이 무엇인지, Controller의 로직을 최소화해야 할 이유와 그 방법은 무엇인지 고민하며 코드를 작성해야 한다는 사실을 알게 되었습니다.


이상적인 Controller의 규모와 역할

View와 Model을 연결해주는 역할 그 이상 이하도 아니다.

Controller는 역할은 View와 Model 간 연결 수단에 그쳐야 합니다.

  • 연결로 그친다라는 것은, Controller를 View와 Domain 측 객체의 함수를 트리거하는 코드로만 구성하는 것입니다.

  • 이는 곧, Domain 측에서 수행할 수 있는 작업들에 대해서는 최대한 Domain의 객체 측에 많은 책임을 부여해주어야 한다는 사실로도 이어질 수 있습니다.

  • Controller에서는 Controller로부터 요청을 받은 Model 측이 어떤 로직을 진행할지에 대한 관심을 가지면 안됩니다.


Domain과 View의 책임을 Controller에 할당한다면?

0. MVC를 사용하는 의미가 사라진다.

MVC를 사용하는 가장 큰 목적은 비즈니스 로직과 UI 로직의 분리이다.

비즈니스 로직Model 측에서 구현해야 하고, UI 로직View에서 구현해야 합니다. 이러한 분리를 통해, UI 로직 혹은 비즈니스 로직 상 변화가 일어나더라도 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있다는 효과를 볼 수 있게 됩니다. 이렇게 두 요소에 명확하게 역할을 나눠놓은 상태에서, Controller는 이 둘 사이를 연결하는 용도로만 활용하는 것이 MVC의 핵심 가치라고 할 수 있습니다.

1. Controller가 비대해진다.

그림과 같이, MVC 패턴에서는 Controller가 View와 Model에 의존하고 있습니다.

Controller가 두 가지 구성 요소에 의존을 하다 보니, 규모 증대 측면에서 위험이 크다고 볼 수 있습니다. 따라서 Model과 View로 역할을 제대로 분리하지 못한다면, Controller의 로직이 비대해지고 유지보수가 힘들어지는 상황을 마주하게 됩니다.

엄격하게 책임을 할당하지 않고 두 요소의 일부 로직이 Controller에 남아있게 된다면, 그에 따라 파생되는 로직들 역시 Controller에 추가될 수 있으며 이는 Controller의 지나친 비대화로 빠지게 되는 지름길이 될 것입니다.

2. 단위 테스트 가능성이 저해된다.

미션을 진행하면서, 단위 테스트가 힘들었던 대표적인 요인들로 다음과 같은 것들이 있었습니다.

  • 랜덤적인 요소가 들어간 객체에 대한 테스트
  • 사용자로부터의 입력이 포함된 로직에 대한 테스트 등

이러한 요소들로 인하여, 아래 두 가지 요소로는 단위 테스트를 진행하기가 불가능에 가깝다는 제약사항을 안고 가야 하는 상황이었습니다.

  • View

    • 사용자로부터 입력을 받는 InputView는 단위 테스트를 수행하기 부적합하다.
  • Controller

    • 랜덤 숫자를 만들어내는 클래스View에 직접적으로 의존하고 있다.
    • 애초에 컨트롤러의 역할은 프로그램의 전체적인 흐름을 주도하는 데 의의가 있는 만큼, 단위 테스트를 적용하기에는 부적합한 구성요소이다. 대신 통합 테스트를 수행하는 것이 적합하다.

이것들을 제외하면 남은 것은 랜덤적인 요소를 포함하고 있지 않는 Domain 객체들입니다. 그렇다면, 최소한 이 객체들에 대해서는 단위 테스트를 꼼꼼하게 작성해야 테스팅의 이점을 최대한으로 얻을 수 있을 것입니다. 그런데 만약 이러한 로직들이 Controller에 들어가게 된다면, 테스트를 충분히 할 수 있는 요소임에도 하지 못하게 되는 상황이 발생하게 됩니다.

따라서 Controller의 책임에 대해서 정확히 이해하고 개발을 하는 것이 테스팅 가능성을 높이는 데 중요한 것이라고 볼 수 있습니다.


최소한의 책임을 보유하도록 하기 위해서는?

작성한 Controller의 코드가 정말 나머지 두 요소를 연결하는데 그치는지는 여러 기준을 통해 판단할 수 있을 것입니다. 저 같은 경우, 미션 중 받았던 피드백을 통해서 다음과 같은 판단 기준이자 행동 요령을 가져갈 수 있었습니다.

1. 컨트롤러의 메서드에서 조건문과 반복문이 존재하지 않도록 한다.

데이터를 연산 혹은 변경하고, 다른 Domain Model 혹은 View 측에서 사용하기 좋게 정제하는 로직은 Model 측에서 해야 할 일입니다. Controller에서 조건문이나 반복문을 작성했다면, 이러한 역할을 수행하는 코드를 Controller에서 작성했을 가능성도 높다고 볼 수 있습니다.

예를 들어, 리스트의 요소를 하나하나 순회해가며 특정 조건을 만족했을 때 값을 변경하는 일은 정말 컨트롤러에서 해도 되는 것인가?

컨트롤러는 도메인 측에서 정제해준 객체를 그대로 가져다가 사용하는 것이 좋지 않을까 하는 의문을 가져볼 수 있을 것이고, 도메인 측으로 옮겨보는 시도를 할 수 있을 것입니다.

2. 메서드의 역할을 충분히 작고 직관적으로 가져간다.

우아한테크코스의 미션에는 항상 아래의 요구사항들이 등장합니다.

함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.
한 메서드에 오직 한 단계의 들여쓰기만 한다.
함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.

제가 느낀 Controller에서 메소드를 잘게 분리하는 것의 가장 큰 이점은, 생각지 못한 부분에서 공통된 로직을 발견할 수 있다는 것입니다. 공통된 로직이 있다는 것은 곧 인터페이스 혹은 독립된 Domain 객체로 분리할 수 있다는 것과 같습니다.

이것으로 Domain 측에 객체를 추가함으로써 더욱 고도화된 객체지향 프로그래밍을 달성할 수 있고, Controller에 존재하던 로직의 양을 획기적으로 줄일 수 있습니다. 또한 테스트 가능한 로직이 추가됨으로써 테스팅으로 인한 이점을 얻을 수 있게 됩니다.


로또 미션을 마치며

우아한테크코스에서 교육을 받은지 벌써 3주가 되어가고 있습니다. 자동차 경주 미션을 마치고, 레벨 1의 두 번째 미션으로 프리코스 3주차에서 구현하였던 로또를 재구현해보게 되었습니다. 이번 미션을 하면서 새로 만나게 된 페어는 제가 만나본 안드로이드 개발을 하는 사람들 중에서 Kotlin의 API와 객체지향에 대한 이해가 가장 높았던 크루였고, 그 덕에 미션 과정에서 정말 많은 것들을 배울 수 있었습니다. 함께 미션을 진행하는 과정에서, 객체 지향에 대한 잘못된 생각을 바로잡을 수 있었을 뿐만 아니라, value class, static factory method, Map 관련 함수들을 처음으로 접하고 학습해볼 수 있었습니다. 이번 미션을 통해 많은 것들을 배우고 도움을 받았던 것처럼, 나중에 개발에 어려움을 겪는 사람들에게 도움을 주는 사람이 되고 싶다는 생각을 하게 되었습니다.

자동차 경주 미션 수행 코드
로또 미션 수행코드


참고자료

https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC

profile
Software Engineer

0개의 댓글