6. 응용 서비스와 표현 영역
표현 영역과 응용 영역
도메인이 제 기능을 하려면 사용자와 도메인을 연결해 주는 매개체가 필요하다. 응용 영역과 표현 영역이 그 매개체 역할을 한다.
표현 영역
은 사용자의 요청을 해석한다. 전달받은 HTTP 요청의 URL, 요청 파라미터, 쿠키, 헤더 등을 이용해서 사용자가 어떤 기능을 실행하고 싶어하는지 판별하고 그 기능을 제공하는 응용 서비스를 실행한다.
응용 서비스의 메서드가 요구하는 파라미터와 표현 영역이 전달받은 데이터 형식이 일치하지 않기 때문에 표현 영역은 응용 서비스가 요구하는 형식으로 사용자 요청을 변환한다.
응용 서비스를 실행한 뒤에 표현 영역은 실행 결과를 사용자에 알맞는 형식으로 응답한다.
응용 영역
의 서비스는 사용자가 원하는 기능을 제공한다. 응용 서비스는 기능을 실행하는 데 필요한 입력값을 메서드 파라미터로 전달받고 실행 결과를 리턴한다. 사용자와의 상호작용은 표현영역이 처리하기 때문에 응용 서비스는 표현 영역에 의존하지 않는다.
응용 서비스의 역할
응용 서비스는 사용자(클라이언트)가 요청한 기능을 실행한다. 응용 서비스는 사용자의 요청을 처리하기 위해 리포지터리로부터 도메인 객체를 구하고, 도메인 객체를 사용한다.
응용 서비스는 주로 도메인 객체 간의
흐름을 제어
한다.응용 서비스는 도메인의 상태 변경을
트랜잭션
으로 처리해야 한다.또한
접근 제어
와이벤트 처리
역할을 맡는다.
도메인 로직 넣지 않기
도메인 로직은 도메인 영역에 위치하고 응용 서비스는 도메인 로직을 구현하면 안된다. 응용 서비스가 도메인 로직을 구현할 경우 두 가지 문제가 발생한다.
코드의 응집성이 떨어진다.
여러 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 생김(코드 중복)
이런 문제점들은 소프트웨어의 변경 용이성을 저하시킨다.
응용 서비스 구현
응용 서비스는 표현 영역과 도메인 영역을 연결하는 매개체 역할을 하는데 이는 디자인 패턴에서 파사드(facade)
와 같은 역할을 한다.
응용 서비스의 크기
응용 서비스는 보통 다음의 두 가지 방법 중 한가지 방식으로 구현한다.
헌 응용 서비스 클래스에서 도메인이 모든 기능 구현하기
장점 : 한 도메인과 관련된 기능을 구현한 코드가 한 클래스에 위치하므로 각 기능에서 동일한 로직에 대한 코드 중복을 제거할 수 있음.
단점 : 한 서비스의 크기가 커짐(코드 줄 수) ⇒ 연관성 적은 코드가 함께 위치할 가능성이 생김 ⇒ 코드 이해의 어려움.
구분되는 기능별로 응용 서비스 클래스를 따로 구현하기
장점 : 코드 품질 유지, 필요한 의존 객체만 포함함.
단점 : 클래스가 많아짐, 동일한 로직은 따로 함수나 별도 클래스로 만듬.
응용 서비스의 인터페이스와 클래스
다음과 같이 인터페이스를 만들고 이를 상속한 클래스를 만드는 것이 필요할까?
public interface UserService {
}
public class UserServiceImpl implements UserService {
}
구현 클래스가 다수 존재하거나 런타임에 구현 객체를 교체해야 할 경우 인터페이스를 유용하게 사용할 수 있다. 그러나 응용 서비스는 런타임에 이를 교체할 경우가 거의 없고 구현 클래스가 두 개인 경우도 매우 드물다.
이런 이유로 인터페이스와 클래스를 따로 구현하면 소스 파일만 많아지고 구현 클래스에 대한 간접 참조가 증가해서 전체 구조만 복잡해지는 문제가 발생한다.
메서드 파라미터와 값 리턴
응용 서비스가 제공하는 메서드는 도메인을 이용해서 사용자가 요구한 기능을 실행하는 데 필요한 값을 파라미터를 통해 전달받는다.
각 값을 개별 파라미터로 전달받을 수 있고, 값 전달을 위한 별도 데이터 클래스를 만들어 전달받을 수도 있다. 후자의 경우 응용 서비스는 데이터 클래스를 파라미터로 전달받고 필요한 데이터를 추출해서 필요한 기능을 구현하면 된다.
응용 서비스에 데이터로 전달할 요청 파라미터가 두 개 이상 존재하면 데이터 전달을 위한 별도 클래스를 사용하는 것이 편리하다.
표현 영역에 의존하지 않기
응용 서비스의 파라미터 타입을 결정할 때 표형 영역과 관련된 타입을 사용하면 안 된다. 예를 들어, 표현 영역에 해당하는 HttpServletRequest나 HttpSession을 응용 서비스의 파라미터로 전달하면 안 된다.
응용 서비스가 표현 영역에 의존하면 응용 서비스만 테스트하기 어렵고 함께 변경해야 한다.
응용 서비스가 표현 영역의 역할을 하여 표현 영역의 응집도가 깨진다.
트랜잭션 처리
트랜잭션을 관리하는 것은 응용 서비스의 중요한 역할이다. 스프링 프레임워크에서 제공하는 트랜잭션 관리 기능을 이용해서 손쉽게 트랜잭션을 처리할 수 있다.
public class ChangePasswordService {
@Transactional
public void changePassword(ChangePasswordRequest request) {
Member member = findExistingMember(request.getMemberId());
member.changePassword(request.getCurPassword(), request.getNewPassword());
}
}
스프링의 기본 동작은 @Transactional
이 적용된 메서드에서 RuntimeException이 발생하면 트랜잭션을 롤백하고 그렇지 않으면 커밋하는 것이다.
도메인 이벤트 처리
응용 서비스의 역할 중 하나는 도메인 영역에서 발생시킨 이벤트를 처리
하는 것이다. 여기서 이벤트는 도메인의 상태 변경을 의미하며 '암호 변경', '주문 취소'와 같은 이벤트가 있다.
도메인 영역은 상태가 변경되면 이를 외부에 알리기 위해 이번트를 발생(Events.raise())시킬 수 있다. 도메인에서 이벤트를 발생시키면 응용 서비스는 이벤트를 받아서 이벤트에 알맞는 후처리(Events.handle())를 할 수 있다.
표현 영역
표현 영역의 책임은 크게 다음과 같다.
사용자가 시스템을 사용할 수 있는 (화면) 흐름을 제공한다.
사용자의 요청을 알맞는 응용 서비스에 전달하고 결과를 사용자에게 제공한다.
사용자의 요청 데이터를 응용 서비스가 요구하는 형식으로 변환하고 응용 서비스의 결과를 사용자에게 응답할 수 있는 형식으로 변환한다.
사용자의 세션을 관리한다.
값 검증
값 검증은 표현 영역과 응용 서비스 두 곳에서 모두 수행할 수 있다.
표현 영역 : 필수 값, 값의 형식, 범위 등을 검증한다.
응용 서비스 : 데이터의 존재 유무, 중복 같은 논리적 오류를 검증한다.
값 검증 방법
Validator 인터페이스 이용하기
@Valid
이용하기
권한 검사
보통 다음 세 곳에서 권한 검사를 수행할 수 있다.
표현 영역
표현 영역에서는 서블릿 필터를 사용해서 인증 여부와 URL별 권한 검사를 할 수 있다.
응용 서비스
스프링 시큐리티는 AOP를 활용해서
@PreAuthroize("hasRole('Admin')")
과 같이 어노테이션으로 서비스 메서드에 대한 권한 검사를 할 수 있다.도메인
개별 도메인 단위로 권한 검사를 해야 하는 경우는 직접 권한 검사 로직을 구현해야 한다.
조회 전용 기능과 응용 서비스
서비스가 조회 전용 기능을 사용하면 단순히 조회 전용 기능을 호출하는 것으로 끝나는 경우가 많다.
public class OrderLIstService{
public List<OrderView> getOrderList(String ordererId) {
return orderViewDao.selectByOrderer(ordererId);
}
}
서비스에서 수행하는 추가적인 로직도 없고 트랜잭션도 필요없다. 이런 경우는 굳이 서비스를 만들지 않고 표현 영역에서 바로 조회 전용 기능을 사용해도 된다.
Last updated
Was this helpful?