본문 바로가기
Spring/study

MVC 패턴에서 Service Model의 역할

by avvin 2019. 5. 31.

MVC 패턴에서 Service Model 의 역할

MVC 패턴의 핵심은 View는 자신이 요청할 Controller만 알고있으면 되고, Controller는 화면에서 넘어오는 매개변수들을 이용해 Service 객체를 호출하는 역할을 한다. Service 는 불필요하게 Http 통신을 위한 HttpServlet을 상속 받을 필요도 없는 순수한 자바 객체로 구성된다(그렇기에 Service 에 request나 response와 같은 객체를 매개변수로 받아선 안된다. 그걸 사용해야하는 작업은 컨트롤러에서 해야한다.). 그렇기에 자신을 어떤 컨트롤러가 호출하든 상관없이 필요한 매개변수만 준다면 자신의 비즈니스로직을 처리하게된다. 즉 모듈화를 통해 어디서든 재사용이 가능한 클래스파일이라는 뜻이다. 단순 Web 기반이 아니라 추후 native app 으로 view단이 변경되더라도 Service는 view에 종속적인 코드가 없기때문에 그대로 재사용 할 수 있어야 한다. 그리고 추가적인 요청사항이 들어오면 기존 소스를 수정하는게 아니라 기존 service 인터페이스를 구현한 다른 클래스를 구현해 그 객체를 사용하게끔 하는것이다. OCP에 입각한 변화에는 닫혀있고 확장에는 열려있는 구조로 만들어야한다는 것이다.


결론

그렇기 때문에 Service를 인터페이스로 구성했던것이 아닐까 생각한다. 비즈니스 로직을 처리하는 모델은 요청사항에 따라 언제든 변할수있는 부분이었고 변화에 대응하기위해 확장을 염두하여 인터페이스로 구성했던것이다. 그런데 어디서부터 잘못된건지 Service를 인터페이스로 만들었던건 관례로 굳어지게 되었는데 개발은 transaction script 형식으로 진행하다보니 관례는 관례대로 남고 애초에 그렇게 하고자했던 이유는 사라져버리게 된것이다. 그래서 내가 내린 결론은 한 메서드에서 모든 역할을 다하는 이런 절차지향적 코딩에서는 사실 Service를 굳이 인터페이스로 할필요는 없다는 것이다. 물론 '그러니까 인터페이스 만들지말자' 보다는 애초에 인터페이스를 만들었던 이유를 잘 살리는게 바람직하지 않을까 생각하고, 나같은 궁금증을 가졌던 사람들에게 조금이나마 도움이 되는 글이었으면 좋겠다



출처: https://multifrontgarden.tistory.com/97 [우리집앞마당]



1. Service
Service의 역할은 Dao가 DB에서 받아온 데이터를 전달받아 가공하는 것이다.
다양한 예시가 있겠지만, 아주 간단한 예시를 통해서 느낌 정도만 알아보도록 하자.


출처 : https://jayviii.tistory.com/21



DAO는 단일 데이터 접근/갱신만 처리합니다.
Service는 여러 DAO를 호출하여 여러번의 데이터 접근/갱신을 하며 그렇게 읽은 데이터에 대한 비즈니스 로직을 수행하고, 그것을 하나의(혹은 여러개의) 트랜잭션으로 묶습니다.

즉, Service가 트랜잭션 단위입니다. 

위와 같이 DAO와 Service가 완전히 동일해지는 경우도 분명히 발생합니다. 하지만 그것은 해당 비즈니스 로직이 "단일 DB 접근"으로 끝나기 때문에 발생하는 것입니다.

만약 DAO의 메소드 하나에 다중 DB접근 로직이 들어갔고, 서비스는 단순히 그 DAO메소드를 호출하는 통로 역할만 한다면 DAO측 모듈화가 제대로 안된 접근 방식일 가능성이 높습니다(항상 그렇다는 뜻은 아닙니다)


 iBatis 관련부분을 DAO로 보시면 될 것입니다.


컨트롤러에서 서비스로 파라미터를 넘길때 request객체나 model을 그대로 던지는게 아니라 알맞는 POJO형태의 객체로 파라미터를 가공한 후 던지면 됩니다.

그럼 서비스는 그걸 받아서 비즈니스 로직을 처리하고 결과를 리턴하면 컨트롤러가 다시 그걸 받아서 모델에 담고 뷰로 전달하겠죠.

로직을 서비스에 담는 이유는, 비슷한 처리를 서로 다른 페이지에서 요청한다면 각각의 컨트롤러에 중복코드가 발생하지않을까요? 그걸 해결하기 위함입니다.

그리고 서비스에 request같은 파라미터를 넘기지 않는 이유는 서비스는 화면에 독립적이어야하기때문입니다. 지금이야 웹 서비스니 request 객체가 넘어오지만 만약 뷰가 웹 서비스가 아니라면? 뷰가 바뀌면 컨트롤러만 바뀌면 되는데 서비스가 request같은곳에 의존성을 갖게되면 뷰가 바꼈을때 서비스도 수정되어야 하겠죠.


기본적으로 '비즈니스'라는 것을 어떻게 바라볼 것인가에 대한 접근 방법의 문제입니다.

어떤 개발자들은 비즈니스를 ERD라고 생각할 수도 있고, 다른 개발자들은 웹 페이지의 묶음이라고 생각할 수도 있을 것입니다.

하지만 객체지향 언어를 사용한다면 적어도 정석이라고 할 수 있는 답은 '추상화, 계층화된 API의 모음'이라는 것이고, 그런 관점에서 볼 때는 비즈니스 계층에 '요청'이나 '응답' 같은 웹페이지 처리에 특화된 개념을 API에 노출시키는 것은 매우 잘못된 설계입니다. 쇼핑몰 사이트의 '비즈니스'는 상품 거래이지 서블릿 구동이 아니니까요.

따져보면, '컨트롤러 계층에 비즈니스 로직을 구현한다'는 이야기 자체가 '비즈니스'를 결국 데이터베이스 연동이나 페이지 처리와 동일한 것으로 전제를 하는 것입니다. 컨트롤러에서 마이바티스로 테이블을 조작할 수야 있겠지만 '상품 구매' 같은 API를 재활용 가능한 형태로 표현하기는 쉽지 않습니다.

실무에서 비즈니스 API를 제대로 설계하는 경우가 극히 드물고 사실상 서비스에서도 DAO의 역할을 중복적으로 정의하는 식이 관행이 되다보니 이럴 거면 왜 서비스 계층이 필요한지 모르겠다는 의문이 드는 경우가 생기는 것 같습니다.


위에서 다들 답변 잘해주셨는데 추가로 공통적인 키워드는 "재사용" 이겠죠. 

그리고 서비스에서 비즈니스로직을 작성하면 뷰에 종속되지않으므로 스펙의 변경 예를 들면 웹 -> 모바일앱으로 변경된다면 해당 비즈니스로직을 그대로 가지고 갈 수 있습니다. 

단위 테스트시에도 서비스레이어에 비즈니스로직을 작성하면 테스트도 유용합니다. 


출처 : https://okky.kr/article/179628