6장 - 응용 서비스와 표현영역
- Created
- 2023년 1월 16일 AM 10:24
6.1 표현 영역과 응용 영역#
- 도메인 영역을 잘 구현하지 않으면 사용자의 요구를 충족하는 제대로 된 소프트웨어를 만들지 못한다.
- 하지만 도메인 영역만 잘 만든다고 끝나는 것은 아니다.
- 도메인이 제 기능을 하기 위해선 사용자와 도메인을 잘 연결해 주는 매개체가 필요하다.

- 표현 영역은 사용자의 요청을 해석
- URL, 요청 파라미터, 쿠키, 헤더 등을 이용해 사용자가 실행하고 싶은 기능을 판별하고 그 기능을 제공하는 응용 서비스를 실행
- 실제 사용자가 원하는 기능을 제공하는 것은 응용 영역에 위치한 서비스
- 사용자가 회원 가입을 요청했다면 실제 그 요청을 위한 기능을 제공해주는 주체는 응용 서비스에 위치함
- 표현 영역은 응용 서비스가 요구하는 형식으로 사용자 요청을 변환
- 응용 서비스의 메서드가 요구하는 파라미터와 표현 영역이 사용자로부터 전달받은 데이터는 형식이 일치하지 않기 때문
- 사용자와 상호작용은 표현 영역이 처리
- 응용 서비스는 표현 영역에 의존하지 않음
6.2 응용 서비스의 역할#
- 응용 서비스는 사용자가 요청한 기능을 실행한다.
- 응용 서비스는 사용자의 요청을 처리하기 위해 리포지터리에서 도메인 객체를 가져와 사용
- 응용 서비스의 주요 역할은 도메인 객체를 사용해 사용자의 요청을 처리하는 것
- 표현 영역입장에서 보았을 때 응용 서비스는 도메인 영역과 표현 영역을 연결해 주는 창구
- 응용 서비스는 주로 도메인 객체 간의 흐름을 제어하기 때문에 단순한 형태를 가짐
- 서비스가 복잡하다면 서비스에서 도메인 로직의 일부를 구현하고 있을 가능성이 높다.
- 서비스가 도메인 로직을 일부 구현하면 코드 중복, 로직 분산 등 코드 품질에 안좋은 영향을 줄 수 있다.
- 서비스는 트랜잭션 처리도 담당
- 도메인의 상태 변경을 트랜잭션으로 처리해야 함
6.2.1 도메인 로직 넣지 않기#
- 도메인 로직은 도메인 영역에 위치하고 응용 서비스는 도메인 로직을 구현하지 않는다.
- 도메인 로직을 도메인 영역과 응용 서비스에 분산해서 구현하면 코드 품질에 문제가 발생
- 코드의 응집성이 떨어짐
- 여러 응용 서비스에서 서로 다른 영역에 위치한다는 것은 도메인 로직을 파악하기 위해 여러 영역을 분석해야 한다는 것을 의미
- 코드 중복을 막기 위해 서브스 영역에 별도의 보조 클래스를 만들 수 있지만, 애초에 도메인 영역에 기능을 구현했으면 응용 서비스는 그 기능을 사용하기만 하면 됨
- 일부 도메인 로직이 응용 서비스에 출현하면서 발생하는 두 가지 문제(응집도 떨어짐, 코드 중복)는 결과적으로 코드 변경을 어렵게 만든다.
6.3 응용 서비스의 구현#
- 응용 서비스는 표현 영역과 도메인 영역을 연결하는 매개체 역할을 한다.
- 이는 디자인 패턴에서 파사드와 같은 역할을 한다.
- 응용 서비스 자체는 복잡한 로직을 수행하지 않기 때문에 응용 서비스의 구현은 어렵지 않다.
6.3.1 응용 서비스의 크기#
- 응용 서비스 자체의 구현은 어렵지 않지만 몇 가지 생각할 거리가 있다. 그중 하나가 응용 서비스의 크기다.
- 회원 도메인을 예시로 생각해보면 회원가입/탈퇴/암호 변경/비밀번호 초기화 등의 기능을 구현하기 위해 도메인 모델을 사용하게 됨
- 방법 1 - 한 응용 서비스 클래스에 회원 도메인의 모든 기능 구현하기
- 각 기능에서 동일한 로직을 위한 코드 중복을 제거하기 쉬운 장점
- 한 서비스 클래스의 크기가 커진다는 것이 단점
- 코드 크기가 커지면 연관성이 적은 코드가 한 클래스에 함게 위치할 가능성이 높아지고 결과적으로 관련없는 코드가 뒤섞여 코드를 이해하는데 방해가 됨
- 한 클래스에 코드가 모이기 시작하면 엄연히 분리하는 것이 좋은 상황임에도 습관적으로 기존에 존재하는 클래스에 억지로 끼워넣게 됨
- 결과적으로 점점 코드 품질을 낮추는 결과를 초래
- 방법 2 - 구분되는 기능별로 응용 서비스 클래스를 따로 구현
- 이 방식을 사용하면 클래스 개수는 많아지지만 한 클래스에 관련 기능을 모두 구현하는 것과 비교해 코드 품질을 일정 수준으로 유지하는 데 도움이 됨
- 각 기능마다 동일한 로직을 구현할 경우 여러 클래스에 중복해서 동일한 코드를 구현할 가능성이 있다.
- 별도 클래스에 로직을 구현해 코드 중복을 방지할 수 있음
6.3.2 응용 서비스의 인터페이스와 클래스#
- 응용 서비스 구현시 논쟁이 될 만한 것은 인터페이스가 필요한 지이다.
- 인터페이스가 필요한 몇 가지 상황이 있는데 그중 하나는 구현 클래스가 여러 개인 경우
- 응용 서비스는 런타임에 교체하는 경우가 거의 없고 한 응용 서비스의 구현 클래스가 두 개인 경우도 드물다.
- 때문에 인터페이스와 클래스를 따로 구현하면 소스 파일만 많아지고 구현 클래스에 대한 간점 참조가 증가해 저체 구조가 복잡해진다.
- 따라서 인터페이스가 명확하게 필요하기 전까지 응용 서비스에 대한 인터페이스를 작성하는 것이 좋은 선택이라 볼 수 없음
- TDD를 즐겨하고 표현 영역부터 개발을 시작한다면, 미리 응용 서비스를 구현할 수 없으므로 응용 서비스의 인터페이스부터 작성하게 될 것
- 이때 응용 서비스의 인터페이스를 이용해 컨트롤러 구현을 완성해 나갈 수 있음
- 표현 영역이 아닌 도메인 영역이나 응용 영역의 개발을 먼저 시작하면 응용 클래스가 먼저 만들어짐
- Mock 테스트 등의 도구를 이용해 테스트용 대역 객체를 만들 수 있기 때문에 인터페이스가 없어도 표현 영역을 테스트할 수 있음
- 결과적으로 응용 서비스에 대한 인터페이스 필요성을 약화시킴
6.3.3 메서트 파라미터와 값 리턴#
- 응용 서비스가 제공하는 메서드는 도메인을 이용해 사용자가 요구한 기능을 실행하는데 필요한 값을 파라미터로 전달받아야 함
- 응용 서비스는 파라미터로 전달받은 데이터를 사용해서 필요한 기능을 구현하면 된다.
- 스프링 MVC와 같은 프레임워크는 웹 요청 파라미터를 자바 객채로 변환하는 기능을 제공하므로 응용 서비스에 데이터로 전달할 요청 파라미터가 두 개 이상 존재하면 데이터 전달을위한 별도 클래스를 사용하는것이 편리함
- 응용 서비스의 결과를 표현 영역에서 사용해야 하면 응용 서비스 메서드의 결과로 필요한 데이터를 리턴한다.
- 응용 서비스에서 애그리거트 자체를 리턴하면 코딩은 편할 수 있지만 도메인의 로직 실행을 응용 서비스와 표현 영역 두 곳에서 할 수 있게된다.
- 이것은 코드를 분산시켜 응집도를 낮추게 하는 원인이 된다.
- 응용 서비스는 표현 영역에서 필요한 데이터만 리턴하는 것이 기능 실행 로직의 응집도를 높이는 확실한 방법이다.
6.3.4 표현 영역에 의존하지 않기#
응용 서비스의 파라미터 타입을 결정할 때 주의할 점은 표현 영역과 관련된 타입을 사용하면 안된다는 점이다.
- HttpSevelteRequest나 HttpSession을 응용 서비스의 파라미터로 전달하면 안된다.
- HttpSession이나 쿠키는 표현 영역의 상태에 해당하는데 이 상태를 응용 서비스에서 변경해 버리면 표현 영역의 코드만으로 표현 영역의 상태가 어떻게 변경되는지 추적이 어렵다.
- 즉 표현 영역의 응집도가 깨지는 것
- 결과적으로 코드의 유지 보수 비용을 증가시키는 원인
6.3.5 트랜잭션 처리#
회원 가입에 성공하더라도 DB 에 정보를 삽입하지 않으면 고객은 로그인을 할 수 없다.
이는 트랜잭션과 관련된 문제로 트랜잭션 관리 기능을 이용하면 쉽게 트랜잭션을 처리할 수 있다.
- 프레임워크에서 제공하는 트랜잭션 기능을 적극 사용하는 것이 좋다.
6.4 표현 영역#
표현 영역의 책임은 크게 다음과 같다.
- 사용자가 시스템을 사용할 수 있는 흐름(화면)을 제공하고 제어한다.

- 웹 서비스의 표현 영역은 사용자가 요청한 내용을 응답으로 제공한다.
- 응답에는 다음 화면으로 이동할 수 있는 링크나 데이터를 입력하는 폼 등이 포함된다.
- 사용자는 표현 영역이 제공한 폼에 알맞은 값을 입력하고 다시 폼을 표현 영역에 전송한다.
- 사용자의 요청을 알맞은 응용 서비스에 전달하고 결과를 사용자에게 제공한다.
- 화면을 보여주는데 필요한 데이터를 읽거나 도메인의 상태를 변경해야 할 때 응용 서비스를 사용한다.
- 이 과정에서 표현 영역은 사용자의 요청 데이터를 응용 서비스가 요구하는 형식으로 변환
- 응용 서비스의 결과를 사용자에게 응답할 수 있는 형식으로 변환한다.
- 사용자의 세션을 관리한다.
- 웹은 쿠키나 서버 세션을 이용해 사용자의 연결 상태를 관리한다.
6.5 값 검증#
값 검증은 표현 영역과 응용 서비스 두 곳에서 모두 수행할 수 있다.
- 원칙적으로 모든 값에 대한 검증은 응용 서비스에서 처리한다.
- 표현 영역은 잘못된 값이 존재하면 이를 사용자에게 알려주고 값을 다시 입력받아야 한다.
- 응용 서비스에서 각 값이 유요한지 확인할 목적으로 인셉션을 사용할 때의 문제점은 사용자에게 좋지 않은 경험을 제공한다는 것
- 매번 폼을 다시 입력하고 보내며 검사해야만 하기 때문
- 한번에 잘못된 값을 검증받고 싶음
- Error 목록을 생성해 값 검증이 끝난 후 하나의 익셉션으로 모아서 발생시켜 해결
- 표현 영역에서는 필수 값과 값의 형식을 검사하면 실질적으로 응용 서비스는 ID 중복 여부와 같은 논리적 오류만 검사하면 된다.
- 즉 표현 영영과 응용 서비스가 값 검사를 나눠서 수행하는 것!
- 표현 영역 : 필수 값, 값의 형식 범위 등을 검증
- 응용 서비스 : 데이터의 존재 유무와 같은 논리적 오류를 검증
6.6 권한 검사#
개발하는 시스템마다 권한의 복잡도가 다르다.
단순한 시스템은 인증 여부만 검사하면 되는데 반해, 어떤 시스템은 관리자인지에 따라 사용 할 수 있는 기능이 달라지기도 한다.
또 실행할 수 있는 기능이 역할마다 달라지는 경우도 있다.
보안 프레임워크의 복잡도를 떠나 보통 세 곳에서 권한 검사를 수행할 수 있다.
- 표현 영역

서블릿 필터를 이용한 인증URL 에 대한 권한 검사 과정 - 표현영역에서 할 수 있는 기본적인 검사는 인증된 사용지인이 아닌지 검사하는 것
- URL을 처리하는 컨트롤어에 웹 요청을 전달하기 전에 인증 여부를 검사해 인증된 사용자의 웹 요청만 컨트롤러에 전달한다.
- 응용 서비스
- URL 만으로 접근 제어를 할 수 없는 경우 응용 서비스의 메서드 단위로 검사를 수행해야 한다.
- 이것이 꼭 응용 서비스의 코드에서 직접 권한 검사를 해야 한다는 것을 의미하는 것은 아니다.
- AOP를 활용해 서비스 메서드에 대한 권한을 검사할 수 있는 기능을 제공
- 도메인
- 개별 도메인 객체 단위로 검사를 해야 하는 경우 구현이 복잡해짐
- 응용 서비스의 메서드 수준에서 권한 검사를 할 수 없기 때문에 다음과 같이 직접 권한 검사 로직을 구현해야 한다.