[DDD] 6장.응용 서비스와 표현 영역

매빈·2023년 3월 26일
0

1. 응용 서비스 구현


6.1 표현 영역과 응용 영역

  • 도메인이 제 기능을 하려면 사용자와 도메인을 연결해 주는 매개체가 필요함.

  • 사용자에게 기능을 제공하려면 도메인과 사용자를 연결해 줄 표현 영역
    응용 영역이 필요함
    - 표현 영역: 사용자의 요청을 해석
    - 응용 영역: 실제 사용자가 원하는 기능을 제공

  • 사용자와의 상호작용은 표현 영역이 처리하기 때문에 응용 서비스는
    표현 영역에 의존하지 않음.

6.2 응용 서비스의 역할

  • 응용 서비스: 사용자가 요청한 기능을 실행하고, 사용자의 요청을 처리하기 위해 리포지터리에서 도메인 객체를 가져와 사용함. (도메인 영역과 표현 영역을 연결해주는 창구 역할)

  • 특징

    • 주로 도메인 객체 간의 흐름을 제어하기 때문에 단순한 형태를 가짐.
      ➡️ 응용 서비스가 복잡하다면 응용 서비스에서 도메인 로직의 일부를 구현하고 있을 가능성 높음. 이 경우 코드 중복, 로직 분산 등 코드 품질에 안 좋은 영향을 미칠 수 있음.
    • 트랜잭션 처리도 담당함.
    • 접근 제어와 이벤트 처리도 담당.

6.2.1 도메인 로직 넣지 않기

  • 도메인 로직을 도메인 영역과 응용 서비스에 분산해서 구현하면 코드 품질에 문제가 발생 = 코드의 응집성이 떨어짐.
    ➡️ 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 높아지고,
    ➡️ 결과적으로 코드 변경을 어렵게 만듦 = 그만큼 소프트웨어의 가치가 떨어진 다는것을 의미

  • 따라서, 도메인 로직을 도메인 영역에 모아서 코드 중복을 줄이고 응집도를 높여야 함.

6.3 응용 서비스의 구현

응용 서비스는 표현 영역과 도메인 영역을 연결하는 매개체 역할을 하는데
이는 디자인 패턴에서 퍼사드와 같은 역할을 한다.

6.3.1 응용 서비스의 크기

보통 다음의 두 가지 방법 중 한 가지 방식으로 구현

  • 한 응용 서비스 클래스에 회원 도메인의 모든 기능 구현하기
    • 장점: 동일 로직에 대한 코드 중복을 제거할 수 있음.
    • 단점: 클래스의 크기가 커짐 ➡️ 연관성이 적은 코드가 한 클래스에 함께 위치할 가능성이 높아져, 코드를 이해하는 데 방해가 될 수 있음.
  • 구분되는 기능 별로 응용 서비스 클래스를 따로 구현하기 ➡️ 저자는 이 방법을 더 선호함
    • 장점: 클래스 개수는 많아지지만, 이전과 비교해서 코드 품질을 일정 수준으로 유지하는데 도움이 됨.
    • 단점: 클래스의 기능이 분산되어 중복해서 동일한 코드를 구현할 가능성이 있음 ➡️ 별도 클래스에 로직을 구현하여 코드 중복을 방지할 수 있음.

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

인터페이스가 필요한지 응용 서비스를 구현할 때 논쟁이 됨.

  • 구현 클래스가 다수 존재하거나 런타임에 구현 객체를 교체해야 할 경우 인터페이스를 유용하게 사용 가능. 하지만 응용 서비스는 런타임에 교체하는 경우가 거의 없고 구현체도 두개이상인 경우도 드뭄.
    ➡️ 이런 이유로 인터페이스와 클래스를 분리하면 구현 클래스만 많아지고 복잡해짐.
    ➡️ 따라서 인터페이스가 명확하게 필요해지기 전까지 인터페이스를 추가하는 것이 좋은 선택은 아님.

TDD(테스트 주도 개발)를 즐겨하고 표현 영역부터 개발을 시작하는 경우, 미리 응용서비스를 구현할 수 없으므로 인터페이스를 추가할 수도 있음.

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

  • 응용 서비스가 제공하는 메서드가 필요한 값을 파라미터로 전달 받는 방법

    • 각 값을 개별로 전달 받기
    • 별도 데이터 클래스를 만들어 전달 받기
    public class ChangePasswordRequest {
      private String memberId;
      private String currentPassword;
      private String newPassword;
    }

    ➡️ 스프링 MVC와 같은 프레임워크의 파라미터 객체 변환 기능을 이용하면 편리함.

  • 응용 서비스 결과를 표현 영역에서 사용해야 하는 경우, 필요한 데이터를 리턴 (ex. 식별자)

  • 애그리거트 객체를 그대로 리턴할 수도 있음. 이 경우, 코딩은 편하지만 도메인 로직이 표현 영역에서도 실행할 수 있게 되므로 응집도를 낮추는 원인이 됨.
    ➡️ 애그리거트를 리턴해도 애그리거트가 제공하는 기능을 컨트롤러나 뷰에서 실행하면 안된다는 규칙을 정할 수도 있지만, 그보단 필요한 데이터만 리턴하는것이
    실행 로직의 응집도를 높이는 확실한 방법

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

  • 응용 서비스의 파라미터 타입을 결정할 때 주의할 점은 표현 영역과 관련된 타입을 사용하면 안 된다는 점.

  • 문제점

    • 응용 서비스에서 표현 영역에 대한 의존이 발생하면 응용 서비스만 단독으로 테스트하기가 어려워짐.
    • 표현 영역의 구현이 변경되면 응용 서비스의 구현도 함께 변경해야 하는 문제도 발생.
    • 응용 서비스가 표현 영역의 역할까지 대신할 수도 있게 됨
  • HttpServletRequest, HttpSession을 응용 서비스에 파라미터로 전달하면 안됨.
    ➡️ 표현 영역 상태에 해당하는 대상(세션, 쿠키 등)들을 응용서비스에서 변경하면 표현 영역 코드만으로 표현 영역의 상태가 어떻게 변경되는지 추적이 어려워짐. 즉, 표현 영역의 응집도가 깨지게 됨.

  • 응용 서비스가 표현 영역 기술을 사용하지 않도록 하는 가장 쉬운 방법은 서비스 메서드의 파라미터와 리턴타입으로 표현 영역 기술을 사용하지 않는 것

6.3.5 트랜잭션 처리

  • 트랜잭션을 관리하는 것은 응용 서비스의 중요한 역할
  • 스프링과 같은 프레임워크가 제공하는 트랜잭션 관리 기능을 이용하여 쉽게 트랜잭션 처리 가능
  • 스프링의 경우 @Transactional 사용.

2. 표현 영역의 역할


6.4 표현 영역

  • 표현 영역의 책임
    • 사용자가 시스템을 사용할 수 있는 (화면)흐름을 제공하고 제어
    • 사용자의 요청을 알맞은 응용 서비스에 전달하고 결과를 사용자에게 제공
    • 사용자의 세션을 관리

3. 값 검증과 권한 검사


6.5 값 검증

  • 값 검증은 표현 영역과 응용 서비스 두 곳에서 모두 수행할 수 있음.

  • 원칙적으로 모든 값에 대한 검증은 응용 서비스에서 처리

  • 응용 서비스에서 각 값이 존재하는지 형식이 올바른지 확인할 목적으로 Exception을 사용할 때의 문제점은 사용자에게 좋지 않은 경험을 제공한다는 것이다.
    ➡️ 사용자가 폼을 입력하고 전송하면 첫번째에 예외를 발생시킬 경우 나머지 항목은 검사하지 않기 때문
    ➡️ 이러한 불편을 해소하기 위한 방법

    • 에러 코드를 모아 하나의 익셉션으로 발생 시키기.
    • 스프링의 Validator 인터페이스를 사용하기.
  • 응용 서비스를 사용하는 표현 영역 코드가 한 곳이면 구현의 편리함을 위해 다음과 같이 역할을 나누어 검증을 수행할 수도 있음.

    • 표현 영역: 필수 값, 값의 형식, 범위 등을 검증
    • 응용 서비스: 데이터의 존재 유무와 같은 논리적 오류를 검증
      ➡️ 저자의 경우, 가능하면 응용 서비스에서 모두 검증하는 편. 프레임워크의 검증 기능을 사용할 때보다 코드가 늘어나지만, 반대로 응용 서비스의 완성도가 높아지는 이점이 있기 때문에.

6.6 권한 검사

  • 개발할 시스템마다 권한의 복잡도가 달라짐.
  • 보안 프레임워크에 대한 이해가 부족하면 프레임워크를 무턱대고 도입하는 것보다 개발할 시스템에 맞는 권한 검사 기능을 구현하는 것이 시스템 유지보수에 유리할 수 있음.
  • 권한 검사를 수행하는 영역
    • 표현 영역: 인증된 사용자 여부 검사
    • 응용 서비스 영역: URL 만으로 접근 제어를 할 수 없는 경우 응용 서비스의 메서드 단위로 권한 검사를 수행
    • 도메인 영역: 도메인 단위로 권한 검사를 해야 하는 경우는 다소 구현이 복잡해짐.
      • ex. 게시글 삭제 - 본인 또는 관리자 역할을 가진 사용자만 가능.
        ➡️ 게시글 작성자가 본인인지 확인하기 위해 게시글 애그리거트를 먼저 로딩해야 함. 즉, 응용 서비스 메서드 수준에서 권한 검사를 할 수 없으므로 직접 권한 검사 로직을 구현해야 함.
        • Spring Security와 같은 보안 프레임워크를 확장해서 개별 도메인 객체 수준의 권한 검사 기능을 프레임워크에 통합할 수도 있지미나, 프레임워크에 대한 높은 이해가 필요함.
          ➡️ 따라서, 이해도가 높지않아 원하는 수준으로 확장되지 않는다면 도메인에 맞는 권한 검사 기능을 직접 구현하는것이 코드 유지 보수에 유리함.

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

  • 5장에서는 조회 화면을 위해 별도로 조회 전용 모델과 DAO를 만드는 내용을
    다루었음.
    ➡️ 서비스에서 조회 전용 기능을 사용하게 되면 서비스 코드가 다음과 같이 단순히 조회 전용 기능을 호출하는 것으로 끝날 수 있다.

    public class OrderListService {
      public List<OrderView> getOrderList(String ordererId) {
        return orderViewDao.selectByOrderer(ordererId);
      }
    }
  • 서비스에서 수행하는 추가적인 로직이 없고 조회 전용이라 트랜잭션이 필요하지 않을 경우에는 표현 영역에서 바로 조회 전용 기능을 사용해도 문제 없음.

0개의 댓글