[DDDStart] 6장. 응용 서비스와 표현 영역
6장. 응용 서비스와 표현 영역
USER -> 표현 영역 -> 응용 영역 -> 도메인 영역
응용 서비스 : 실제 사용자가 원하는 기능을 제공
응용 영역은 사용자가 웹브라우저를 사용하는지 REST API를 호출하는지 TCP 소켓을 사용하는지를 알 필요가 없다. 단지 기능 실행에 필요한 입력값을 받아 결과만 리턴하면 된다
표현 영역 : 사용자의 요청을 해석함
- URL, 요청 파라미터, 쿠키, 헤더 등을 이용하여 사용자가 어떤 기능을 실행하고 싶어 하는지 판별하고 그 기능을 제공하는 응용 서비스를 실행
사용자로부터 전달받은 데이터 형식
과응용 영역에서 필요한 데이터 형식
이 서로 일치하지 않기 때문에 표현 영역에서 변환- 응용 서비스에서 리턴받은 값을 사용자가 요구하는 형식에 맞게 변환
응용 서비스
응용 서비스 역할
- 주요 역할
- 도메인 객체를 사용해서 사용자의 요청을 처리하는 것
- 표현 영역 입장에서는 응용 서비스는 도메인 영역과 표현 영역을 연결해줌
- => 파사드(Facade) 역할을 함
- 파사드 : 각 인터페이스 들에 대해서 하나의 통합된 상위 수준의 인터페이스를 제공하는 패턴
- 퍼사드를 사용하는 사용자는 서브시스템을 구성하는 객체로 직접 접근하지 않아도 된다
- 표현 영역은 도메인 객체로 직접 접근하지 않고 응용 서비스를 사용하면 된다
- 파사드 : 각 인터페이스 들에 대해서 하나의 통합된 상위 수준의 인터페이스를 제공하는 패턴
- => 파사드(Facade) 역할을 함
- 단순한 형태를 갖음
- 도메인 객체 간의 흐름을 제어
- 응용 서비스는 도메인 객체 간의 실행 흐름을 제어함
- 도메인 로직을 직접 구현하면 안됨
- 1.코드의 응집성이 떨어짐
- 도메인 데이터와 도메인 로직이 한 영역에 위치해야 함
- 도메인 로직을 파악하려면 여러 영역(도메인 영역 + 응용 영역)을 분석해야 함
- 2.여러 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 높아진다
- 도메인에서 구현했다면 메시지를 보내면 됨
- 서비스에서 구현했다면 각 서비스마다 같은 로직을 중복 구현해야 함
- 결국 코드 변경을 어렵게 한다
- 1.코드의 응집성이 떨어짐
- 도메인의 상태 변경을 트랜잭션으로 처리해야 한다
@Transactional
- 도메인 로직을 직접 구현하면 안됨
응용 서비스 구현
하나의 서비스 클래스 vs 여러개의 서비스 클래스
- 1.하나의 서비스에 기능 모두 때려넣기
- 코드 중복을 제거하기 쉽다
- 가독성 떨어진다
- 코드 길이가 길다
- 연관성이 적은 코드가 한 클래스에 함께 위치할 가능성이 크다
- 코드를 점점 얽히게 만들어 코드 품질을 낮춘다
- 2.기능별로 따로 서비스 구현하기
- 코드 중복이 발생한다
- 코드 길이가 짧다
- 서비스를 인터페이스로 따로 빼야할까?
- 서비스를 런타임에 교체하는 경우는 거의 없음
- 구현 클래스가 두개인 경우도 매우 드물다
- 테스트의 경우는 어떨까. 가짜 객체로 대체하기 위해 인터페이스를 추가할 수는 있지 않나
- 하지만 Mokito가 클래스를 가짜 객체로 대체할 수 있게 해줌
- 결국 인터페이스 불필요
- 이벤트
- 상태가 변경되면 이를 외부에 알리기 위해 이벤트 발생시킬 수 있음
- 계정의 암호를 변경했을 때 이벤트 발생시킴
- 등록된 이벤트 핸들러에 따라서 처리 됨
- ex) 이메일로 새로운 비밀번호 발송
- ex) 문자로 새로운 비밀번호 발송
- 10장에서 자세히 다루니까 패스
- 상태가 변경되면 이를 외부에 알리기 위해 이벤트 발생시킬 수 있음
표현 영역
- 표현 영역 책임
- 사용자가 시스템을 사용할 수 있는 (화면) 흐름을 제공하고 제어
- 웹서비스의 경우 링크, 폼 등이 포함
- 사용자의 요청을 알맞은 응용 서비스에 전달하고, 결과를 가공하여 사용자에게 제공
- 사용자의 세션 관리
- 사용자가 시스템을 사용할 수 있는 (화면) 흐름을 제공하고 제어
값 검증
- 표현 영역
- 필수 값, 값의 형식, 범위 등을 검증
- 응용 서비스
- 데이터의 존재 유무와 같은 논리적 오류를 검증
- 도메인 영역
- 비즈니스 정책에 맞는 데이터인지 검증
Spring Validation 는 Java 와 Spring 의 Validation - Junghoon Song 보면 금방 쓸 수 있음
권한 검사
- 표현 영역
- 인증된 사용자인가?
- 서블릿 필터 이용해서 검사
- 401 UNAUTHORIZED
- 응용 서비스
- 권한이 있는 사용자인가?
- AOP 활용해서 검사
- 403 FORBIDDEN
- 도메인
- 권한이 있는 사용자인가?
- 직접 구현해서 검사
시큐리티 공부하자 ~
조회 전용 기능과 응용 서비스
조회전용 기능은 단순하다. 트랜잭션 필요 없다
따라서 서비스 계층을 생략해도 무방
컨트롤러 -> DAO/리포지터리
@RequiredArgsConstructor
public class OrderController {
private final OrderViewDao orverViewDao;
@GetMapping("/myorders")
public String list(ModelMap model) {
String ordererId = SecurityContext.getAuthentication().getId();
List<OrderView> orders = orderViewDao.selectByOrderer(ordererId);
model.addAttribute("orders", orders);
return "order/list";
}
}
자세한건 11장 CQRS에서..
Q1. 표현 계층에서 파라미터로 RequestDto 받는 클래스들 어느 패키지에 둬야할까
서비스아닐까. 범균님 예제에서도 Service 패키지 안에 있음
A클래스의 메서드 a, B클래스의 메서드b는 모두 @Transactional 걸려있다고 하자. a와 b를 순차적으로 호출해야 하는 로직이 있다. a가 완벽하게 수행되고 b에서 런타임에러 뜨면 a는 롤백이 안될 것 같은데?
집가서 직접 해보자
- 범위 : DDD START! 6~7 장
- 일시 : 190901 (15:30 ~ 18:00)
- 장소 : 역삼 할리스
- 인원 : 2