# Chapter 6: 응용 서비스와 표현 영역

<br>

## 💡 책에서 기억하고 싶은 내용

<br>

### 응용 서비스의 역할

* 응용 서비스는 사용자(client)가 요청한 기능을 실행한다
  * 사용자의 요청을 처리하기 위해 리포지터리에서 `도메인 객체` 를 가져와 사용한다
* 응용 서비스의 주요 역할은 `도메인 객체` 를 사용해서 사용자이 요청을 처리하는 것이므로 `표현(사용자) 영역` 입장에서 보았을 때 응용 서비스는 도메인 영역 ↔ 표현 영역을 연결해 주는 창구 역할을 한다
* 응용 서비스는 주로 `도메인 객체 간 흐름을 제어` 하기 때문에 아래와 같이 단순한 형태를 갖는다
  1. 리포지터리에서 애그리거트를 구한다
  2. 애그리거트의 도메인 기능을 실행한다
  3. 결과를 리턴한다
* 새로운 애그리거트를 생성하는 응용 서비스 역시 간단하다
  1. 데이터 중복 등 데이터가 유효한지 검사한다
  2. 애그리거트를 생성한다
  3. 리포지터리에 애그리거트를 저장한다
  4. 결과를 리턴한다
* 응용 서비스는 `트랜잭션 처리` 도 담당한다
  * 응용 서비스는 도메인의 상태 변경을 트랜잭션으로 처리해야 한다

### 도메인 로직 넣지 않기

* 도메인 로직은 도메인 영역에 위치하고, 응용 서비스는 도메인 로직을 구현하지 않는다
* ex) 암호 변경 기능
  * 암호 변경 기능을 위한 응용 서비스는 Member 애그리거트와 관련 리포지터리를 이용해서 도메인 객체 간의 `실행 흐름을 제어` 한다
* 도메인 로직을 도메인 영역과 응용 서비스에 분산해서 구현하면 `코드 품질` 에 문제가 발생한다
  1. 코드의 `응집성` 이 떨어진다
     * 도메인 데이터와 그 데이터를 조작하는 도메인 로직이 한 영역에 위치하지 않고, `서로 다른 영역에 위치`한다는 것은 도메인 로직을 파악하기 위해 `여러 영역을 분석`해야 한다는 것을 의미한다
  2. 여러 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 높아진다
* 일부 도메인 로직이 응용 서비스에 출현하면서 발생하는 위의 두 가지 문제는 결과적으로 코드 변경을 어렵게 만든다
  * 그러므로, 도메인 로직을 도메인 영역에 모아서 `코드 중복`을 줄이고 `응집도` 를 높여야 한다

### 응용 서비스의 크기

1. 한 응용 서비스 클래스에 해당 도메인의 모든 기능 구현하기
   * 장점
     * 각 기능에서 동일한 로직을 위한 코드 중복을 제거하기 쉬움
   * 단점
     * 한 서비스 클래스의 크기 (LoC)가 커짐
     * 코드 크기가 커지면 연관성이 적은 코드가 한 클래스에 함께 위치할 가능성이 높아짐
     * 결국 관련 없는 코드가 뒤섞여 코드를 이해하는 데 방해가 됨
2. 구분되는 기능별로 응용 서비스 클래스를 따로 구현하기
   * 장점
     * 코드 품질을 일정 수준으로 유지하는 데 도움이 됨
     * 각 클래스별로 필요한 의존 객체만 포함하므로, 다른 기능을 구현한 코드에 영향을 받지 않음
   * 단점
     * 클래스의 개수가 많아짐
     * 각 기능마다 동일한 로직을 구현할 경우, 여러 클래스에서 중복해서 동일한 로직을 구현할 가능성이 있다
       * 하지만 이 경우 `별도 클래스에 로직을 구현`해서 코드가 `중복`되는 것을 `방지`할 수 있다!

### 응용 서비스의 인터페이스와 클래스

* 응용 서비스를 구현할 때 논쟁이 될 만한 것이 `인터페이스` 가 필요한 지이다
* `인터페이스` 가 필요한 상황: 구현 클래스가 여러 개인 경우
* but, 인터페이스와 클래스를 따로 구현하면
  * 소스 파일만 많아지고,
  * 구현 클래스에 대한 간접 참조가 증가해서 전체 구조가 복잡해진다
* 따라서 인터페이스가 명확하게 필요하기 전까지는 응용 서비스에 대한 인터페이스를 작성하는 것이 좋은 선택이라고 볼 수는 없다

### 메서드 파라미터와 값 리턴

* 응용 서비스가 제공하는 메서드는 도메인을 이용해서 사용자가 `요구한 기능을 실행`하는 데 필요한 값을 `파라미터`로 전달받아야 한다
* 스프링 MVC와 같은 웹 프레임워크는 웹 요청 파라미터를 `자바 객체` 로 `변환` 하는 기능을 제공 하므로, 응용 서비스에 데이터로 전달할 `요청 파라미터`가 `두 개 이상 존재`하면 데이터 전달을 위한 `별도 클래스` 를 사용하는 것이 편리하다
* 응용 서비스의 결과를 표현 영역에서 사용해야 하면, 응용 서비스 메서드의 결과로 필요한 데이터를 리턴한다
  * 대표적으로 `식별자` 가 있다
* 응용 서비스에서 애그리거트 자체를 리턴하면, 코딩은 편할 수 있지만 도메인의 로직 실행을 응용 서비스와 표현 영역 두 곳에서 할 수 있게 된다
  * 이것은 기능 실행 로직을 응용 서비스와 표현 영역에 `분산` 시켜 코드의 `응집도` 를 낮추는 원인이 된다
* 응용 서비스는 표현 영역에서 필요한 데이터만 리턴하는 것이 기능 실행 로직의 응집도를 높이는 확실한 방법이다

### 표현 영역에 의존하지 않기

* 응용 서비스의 파라미터 타입을 결정할 때 주의할 점은 `표현 영역과 관련된 타입`을 사용하면 안 된다는 점이다
  * ex) 표현 영역에 해당하는 `HttpServletRequest` 나 `HttpSession` 을 응용 서비스에 파라미터로 전달하면 안 된다
* 응용 서비스에서 표현 영역에 대한 의존이 발생하면,
  * 응용 서비스만 단독으로 테스트 하기가 어려워진다
  * 게다가 표현 영역의 `구현이 변경` 되면, 응용 서비스의 구현도 함께 변경해야 하는 문제도 발생한다
  * 가장 심각한 것은 응용 서비스가 `표현 영역의 역할까지 대신하는 상황` 이 벌어질 수도 있다는 것이다
* 위와 같은 문제가 발생하지 않도록 철저하게 응용 서비스가 표현 영역의 기술을 사용하지 않도록 해야한다
  * 이를 위한 방법으로 서비스 메서드의 파라미터와 리턴 타입으로 `표현 영역의 구현 기술` 을 사용하지 않는 방법이 있다

### 표현 영역

* `표현 영역의 책임`은 크게 다음과 같다
  1. 사용자가 시스템을 사용할 수 있는 `흐름(화면)`을 제공하고, 제어한다
  2. 사용자의 `요청`을 알맞은 응용 서비스에 전달하고, `결과`를 사용자에게 제공한다
     * 사용자의 요청 데이터를 응용 서비스가 요구하는 형식으로 변환하고,
     * 응용 서비스의 결과를 사용자에게 응답할 수 있는 형식으로 변환한다
  3. 사용자의 `세션` 을 관리한다

### 값 검증

* 값 검증은 표현 영역과 응용 서비스 두 곳 모두 수행할 수 있다
  * 원칙적으로 모든 값에 대한 검증은 응용 서비스에서 처리한다
* 표현 영역에서 필수 값과 값의 형식을 검사하면, 실질적으로 응용 서비스는 ID 중복 여부와 같은 `논리적 오류` 만 검사하면 된다
  * 즉, 표현 영영과 응용 서비스가 값 검사를 나눠서 수행하는 것이다
* 응용 서비스를 사용하는 표현 영역의 코드가 한 곳이면 구현의 편리함을 위해 아래와 같이 역할을 나누어 검증을 수행할 수도 있다
  * `표현 영역`: 필수 값, 값의 형식, 범위 등을 검증
  * `응용 서비스 영역` : 데이터의 존재 유무와 같은 논리적 오류를 검증

### 권한 검사

* 아래의 세 곳에서 권한 검사를 수행할 수 있다
  1. 표현 영역
     * 인증된 사용자인지 아닌지 검사
     * ex)
       * 회원 정보 변경 기능
         * 인증된 사용자만 접근 가능하도록 `URL 접근 제어`
         * 인증된 사용자가 아닐 경우 로그인 화면으로 redirect
     * `서블릿 필터 (Servlet Filter)` 에서 접근제어 하기 좋다
     * 스프링 시큐리티도 `필터` 를 이용해서 인증 정보를 생성하고, 웹 접근을 제어한다
  2. 응용 서비스
     * URL 만으로 접근 제어를 할 수 없는 경우 응용 서비스의 `메서드 단위` 로 권한 검사 수행
     * 꼭 응용 서비스에서 직접 권한 검사 해야하는 것은 아님
       * ex) `스프링 시큐리티` - AOP 를 활용해서 annotation으로 `서비스 메서드` 에 대한 권한 검사 수행
  3. 도메인
     * 개별 도메인 객체 단위로 권한 검사를 해야 하는 경우, 직접 권한 검사 로직 구현
       * `스프링 시큐리티` 와 같은 보안 프레임워크를 확장해서 개별 도메인 객체 수준의 권한 검사 기능을 프레임워크에 통합할 수도 있음
         * but, 높은 이해가 필요
         * 이해도가 높지 않아 프레임워크 확장을 원하는 수준으로 할 수 없다면, 해당 도메인에 맞는 권한 검사 기능을 직접 구현하는 것이 유지 보수에 유리함

### 조회 전용 기능과 응용 서비스

* 서비스에서 추가적으로 수행하는 로직이 없고 단일 쿼리만 실행하는 조회 전용 기능이면, 서비스를 만들 필요 없이 `표현 영역` 에서 바로 조회 전용 기능을 사용해도 문제 없다
