6.1 표현 영역과 응용 영역
-
정리
- 1 ~ 5장 : 도메인의 구성요소와 JPA를 이용한 리포지터리 구현 방법
- 도메인이 제 기능 하려면 사용자와 도메인 연결하는 매개체 역할을 하는 표현 영역과 응용 영역 필요

-
표현 영역
- 사용자 요청 해석
- 요청을 받으면 URL, 요청 파라미터, 쿠키, 헤더 등 이용해서 사용자가 실행하고자 하는 기능 판별 및 기능 제공하는 응용 서비스 실행
- 사용자로부터 전달받은 데이터가 응용 서비스가 요구하는 파라미터와 형식이 다르기 때문에 이를 변환해야 함
-
응용 영역
- 실제 사용자가 원하는 기능 위치함
- 기능을 실행하느데 필요한 입력 값을 메서드 인자로 받고 실행 결과 리턴
- 표현 영역에 의존하지 않음
6.2 응용 서비스의 역할
- 도메인 서비스의 주요 역할
- 도메인 객체를 사용해서 사용자의 요청 처리
- 트랜잭션 처리
- 접근 제어
- 이벤트 처리
6.2.1 도메인 로직 넣지 않기
6.3 응용 서비스의 구현
6.3.1 응용 서비스의 크기
- 응용 서비스 구현 방법
- 한 응용 서비스 클래스에 회원 도메인의 모든 기능 구현하기
- 장점 : 각 기능에서 동일 호직에 대한 코드 중복 제거 가능
- 단점 : 한 클래스의 크기가 커짐 -> 코드 품질 낮추게 됨
- 구분되는 기능별로 응용 서비스 클래스를 따로 구현하기
- 한 응용 서비스 클래스에 1 ~ 3개의 기능 구현
- 장점 : 코드 품질 유지, 코드가 서로 의존적이지 않음
- 각 기능마다 동일한 로직이 필요한 경우 별도 클래스에 로직 구현해서 코드 중복 방지
6.3.2 응용 서비스의 인터페이스와 클래스
- 응용 서비스를 구현할 때 인터페이스가 필요한가?
-> 필요 없음, 전체 구조가 복잡해지므로 인터페이스가 명확하게 필요하기 전까지는 작성하지 않는 것이 좋음
- 인터페이스 필요한 경우
- 구현 클래스가 여러 개인 경우
- 런타임에 구현 객체를 교체해야 하는 경우
- -> 응용 서비스는 둘 다 해당 안 됨
6.3.3 메서드 파라미터와 값 리턴
- 응용 서비스가 메서드를 실행하는 데 필요한 값을 파라미터로 받는 방법
- 필요한 각 값을 개별 파라미터로 전달받음
- 값 전달을 위해 별도 클래스를 만들어 전달받음
- 스프링 MVC같은 웹 프레임워크는 웹 요청 파라미터를 자바 객체로 변환하는 기능 제공하므로, 요청 파라미터가 두 개 이상이면 별도 클래스 사용하는 것이 편리
- 응용 서비스의 결과 리턴하기
- 주문번호와 같이 필요한 데이터만 리턴 -> 기능 실행 로직 응집도 높임
- 애그리거트 객체 그대로 리턴 -> 코드 응집도 낮춤
6.3.4 표현 영역에 의존하지 않기
- 응용 서비스가 표현 영역에 의존하면 생기는 문제점
- 응용 서비스 단독으로 테스트하기 어려움
- 표현 영역의 구현 변경되면 응용 서비스의 구현도 변경해야 함
- 응용 서비스가 표현 영역의 역할까지 대신하는 상황 발생 -> 표현 영역의 응집도 꺠짐, 코드 유지 보수 비용 증가
서비스 메서드의 파라미터와 리턴 타입으로 표현 영역의 구현 기술 사용하지 않기
6.3.5 트랜잭션 처리
@Transactional
- 스프링은
@Transactional
이 적용된 메서드가 RuntimeException
을 발생시키면 트랜잭션 롤백
- 그렇지 않으면 커밋
6.4 표현 영역
[표현 영역의 책임]
- 사용자가 시스템을 사용할 수 있는 흐름(화면)을 제공하고 제어한다
- 사용자의 요청을 알맞은 응용 서비스에 전달하고 결과를 사용자에게 제공한다
- 화면을 보여주는데 필요한 데이터를 읽거나 도메인의 상태를 변경해야 할 때 응용 서비스 사용
- 아 과정에서 사용자의 요청 데이터를 응용 서비스가 요구하는 형식으로 변환하고, 응용 서비스의 결과를 사용자에게 응답할 수 있는 형식으로 변환
- MVC 프레임워크는 HTTP 요청 파라미터로부터 자바 객체를 생성하는 기능 지원
- 사용자의 세션을 관리한다
- 사용자의 연결 상태인 세션을 관리
- 웹은 쿠키나 서버 세션 이용해서 사용자의 연결 상태 관리
- 세션 관리는 권한 검사와 연결
6.5 값 검증
- 값 검증은 표현 영역과 응용 서비스 두 곳에서 모두 수행 가능
- 원칙적으로 모든 값에 대한 검증은 응용 서비스에서 처리 (값의 형식 검사, 로직 검사 등)
- 표현 영역은 잘못된 값이 존재하면 이를 사용자에게 알리고 다시 값 입력받음 -> 코드가 다소 번잡
- 응용 서비스에서 각 값이 유효하지 확인할 목적으로 익셉션 사용할 때의 문제점 : 사용자에게 좋지 않은 경험 제공
ex) 전체 값에 대해 검사하지 않기 때문에 사용자는 같은 폼에 값을 여러 번 입력해야 함
-> 응용 서비스에서 에러 코드를 모아 하나의 익셉션으로 발생시키는 방법 사용 (ValidationError
, ValidationErrorException
사용)
- 응용 서비스를 사용하는 표현 영역 코드가 한 곳이면 구현의 편리를 위해 표현 영역과 응용 서비스가 값 검사를 나눠서 수행 할 수도 있음
- 표현 영역 : 필수 값, 값의 형식, 범위 등을 검증
- 응용 서비스 : 데이터의 존재 유무와 같은 논리적 오류를 검증
- 필자의 의견: 가능하면 응용 서비스에서 필수 값 검증과 논리적인 검증 모두 하는 편
- 코드가 늘어날 수 있지만 응용 서비스의 완성도 높아짐
6.6 권한 검사
- 개발하는 시스템마다 권한의 복잡도가 다르기 때문에 항상 고민해야 함
- 다양한 상황을 충족시키기 위해 스프링 시큐리티와 같은 프레임워크는 유연하고 확장 가능한 구조 갖고 있음. 그러나 그만큼 복잡
- 보안 프레인워크에 대한 이해ㅏ 부족하면 프레임워크를 무턱대고 도입하는 것보다 개발할 시스템에 맞는 권한 검사 기능 구현하는 것이 시스템 유지 보수에 유리
[권한 검사를 수행할 수 있는 곳]
- 표현 영역
- 인증된 사용자인지 아닌지 검사
- 서블릿 필터에서 사용자의 인증 정보 생성하고 인증 여부 검사
- 응용 서비스
- URL만으로 접근 제어를 할 수 없는 경우 응용 서비스의 메서드 단위로 권한 검사 수행
- 꼭 응용 서비스의 코드에서 직접 권한 검사 해야하는 것은 아님
ex) 스프링 시큐리티 - @PreAuthorize("hasRole('ADMIN')
- 도메인
- 개별 도메인 객체 단위로 권한 검사 해야 하는 경우는 구현 복잡
- 보안 프레임워크 확장해서 사용
- 프레임워크에 대한 이해가 부족하다면 직접 권한 검사 기능 구현하는 것이 코드 유지 보수에 유리
6.7 조회 전용 기능과 응용 서비스
- 5장에서 만든 조회 전용 모델과 DAO를 서비스에 사용하면 서비스 코드가 단순히 조회 전용 기능 호출하는 형태로 끝남
- 서비스에서 추가적인 로직이 없고 단일 쿼리만 실행하는 기능이기 때문에 트랜잭션도 필요 없음
-> 굳이 서비스 만들지 않고 표현 영역에서 바로 조회 기능 사용해도 문제 없음
public class OrderController {
private OrderViewDao orderViewDao;
@RequestMapping("/myorders")
public String list(ModelMap model) {
String ordererId = SecurityContext.getAuthentication().getId();
List<OrderView> orders = orderViewDao.selectByOrderer(ordererId);
medel.addAttribute("orders", orders);
return "order/list";
}
...
표현 영역에서 응용 서비스 없이 조회 전용 기능에 접근하는 것이 아상하게 느껴질 수 있지만 전혀 이상하지 않은 것!!