왜 MVC 패턴을 사용하고 어떻게 설계해야 할까? Service와 Model이 차이가 뭘까?

목적

왜 MVC 패턴을 사용할까?

  1. 재사용성을 높인다.
  2. 잘 알려진 패턴을 따른다면 다른 사람이 코드를 봤을 때 어떤 기능을 할 것이라는 것을 쉽게 예측할 수 있다.
  3. 리팩토링 비용이 낮아진다.
  4. 위의 모든 장점으로 인해 생산성(output/input)이 향상된다.

방법

그렇다면 MVC 패턴을 어떻게 구현할 수 있을까?

그 전에 먼저 알아야 할 것이 있다. 바로 Layered Approach(계층화 전략)이다.

Layered Approach

Layered Architecture는 소프트웨어가 여러 개의 논리적인 계층으로 이루어진 것이다. 계층이란 유사한 기능을 수행하는 모듈들의 집합이다.

layered-architecture

Layered Architecture에서 가장 중요한 것은 모든 계층은 오직 한 단계 아래의 계층의 API를 호출한다는 것이다. Layer1은 Layer2에만, Layer2는 Layer3에만 접근할 수 있다. 그렇게 함으로써 한 계층의 수정이 다른 계층으로까지 확산되는 것을 막아준다. 즉, 수정해야 할 코드의 양이 줄어든다.

Model View Controller

이제 다시 본론으로 돌아와서 MVC 패턴을 구현해보자. 먼저 MVC 패턴은 Model, View, Controller로 구성된다.

  • 모델 - 비즈니스 로직에 필요한 과 그에 대한 연산을 제공한다.
  • - 애플리케이션 사용자에게 어떻게 보여질 것인지를 정의한다.
  • Controller - 사용자의 입력에 대한 결과(뷰)를 만들기 위해 모델에게 명령을 내린다.

Service 계층의 도입

모델 객체를 컨트롤러에서 접근할 수도 있지만 컨트롤러와 모델 계층 사이에 serivce layer를 추가했다. 그 이유는 아래와 같다.

  1. 여러 컨트롤러에서 동일한 모델에 접근할 경우 해당 모델의 인터페이스 수정이 여러 컨트롤러에 영향을 미치기 때문이다.

service가 없을 때 문제점

  1. Service 객체가 어떤 서비스를 제공하는 것인지 메서드 이름을 보고 예측할 수 있다.

3주차 미션에서 다음과 같이 Controller와 Service 클래스를 작성했다.

Service와 Model의 차이

서비스는 모델을 사용하여 한 층 더 추상적인 서비스 로직을 수행한다.
비유하자면 서비스는 밀키트Model은 그 안의 식재료들이다.
주문이 들어오면 서비스는 식재료들을 레시피(비즈니스 로직)에 맞게 식재료를 요리(모델에 명령을 전달)한다. 그렇게 완성된 음식은 사용자에게 전달된다.
현실과 다른 점은 요리사가 없어도 밀키트가 스스로 만들어지고 식재료가 스스로 손질된다는 점이다. 서비스와 모델은 능동적인 객체이기 때문이다.

🚨 비즈니스 로직과 서비스 로직을 같다고 생각하여 혼용했다.🚨

웹으로 이식

계층적 구조의 장점중 하나는 코드의 재사용성을 높이는 것이다. 이는 서비스를 다른 채널(플랫폼)로 이식할 때 체감할 수 있다.

지금까지의 미션은 모두 표준 입출력을 통해 사용자에게 서비스를 제공했다.
하지만 이 서비스를 웹 애플리케이션으로 제공해야 한다면 어떻게 해야 할까?
코드는 얼마나 수정해야 할까?

서버 애플리케이션으로 구현

Spring Boot를 사용하여 REST API를 제공하는 서버 애플리케이션으로 이식했다.

전체 코드

이식하는데 걸린 시간 분석

아래와 같이 REST API 애플리케이션으로 이식하는데 총 1시간 13분정도 걸렸다. 그 중 기존 코드를 수정하고 새로운 클래스를 작성하는 데 걸린 시간은 30분이고 나머지는 앱의 로직과는 상관없는 작업(JSON 매핑, 어노테이션 선언, 패키지 이름 수정, import문 수정 등)이였다.

postman 결과

postman 예외 결과

필요가 없어진 IOTest를 제외한 모든 테스트를 재사용 할 수 있었다.

test

컨트롤러를 수정하고 요청, 응답 객체를 새로 생성하였다. 하지만 그 이외의 코드(서비스, 모델)는 전혀 수정할 필요가 없었다. 제공하는 서비스가 그대로이기 때문에 입출력, 컨트롤러와 완전히 분리된 서비스 계층은 수정할 필요가 없었다.

수정된 컨트롤러

사용자 입력에 대한 결과를 반환한다.

controller

새로 알게된 점

HTTP POST 메서드의 JSON body가 인스턴스로 매핑될 때에는 기본생성자가 생성되고, setter를 통해 필드에 값이 대입된다. 이걸 몰라서 20분동안 해맸다.

reference

Comments