표현 영역과 응용 영역

지금까지의 내용은 주로 도메인과 그 구현에 대한 내용이었다. 하지만, 도메인 영역만 잘 만든다고 끝나는 것은 아니다. 도메인이 제 기능을 하려면 사용자와 도메인을 연결해 주는 매게체가 필요하다. 응용 영역과 표현 영역이 사용자와 도메인을 연결해 주는 매개체 역할을 한다.

사용자에게 기능을 제공하려면 도메인과 사용자를 연결해 줄 표현 영역과 응용 영역이 필요하다

사용자에게 기능을 제공하려면 도메인과 사용자를 연결해 줄 표현 영역과 응용 영역이 필요하다

표현 영역은 사용자의 요청을 해석한다. 사용자가 웹 브라우저에서 폼에 아이디와 암호를 입력한 뒤에 전송 버튼을 클릭하면 요청 파라미터를 포함한 HTTP 요청을 표현 영역에 전달한다. 요청을 받은 표현 영역은 URL, 요청 파라미터, 쿠키, 헤더 등을 이용해서 사용자가 어떤 기능을 실행하고 싶어 하는지 판별하고 그 기능을 제공하는 응용 서비스를 실행한다.

실제 사용자가 원하는 기능을 제공하는 것은 응용 영역에 위치한 서비스이다. 응용 서비스는 기능을 실행하는 데 필요한 입력값을 메서드 파라미터로 전달받고 실행 결과를 리턴한다.

응용 서비스의 메서드가 요구하는 파라미터와 표현 영역이 사용자로부터 전달받은 데이터는 형식이 일치하지 않기 때문에 표현 영역은 응용 서비스가 요구하는 형식으로 사용자 요청을 변환한다.

@RequestMapping(value = "/member/join")
public ModelAndView join(HttpServletRequest request) {
    String email = request.getParameter("email");
    String password = request.getParameter("password");
    // 사용자 요청을 응용 서비스에 맞게 변환
    JoinRequest joinReq = new JoinRequest(email, password);
    // 변환한 객체(데이터)를 이용해서 응용 서비스 실행
    joinService.join(joinReq);
    ...
}

응용 영역을 실행한 뒤에 표현 영역은 실행 결과를 사용자에 알맞은 형식으로 응답한다. 웹 브라우저인 경우 실행 결과를 HTML 형식으로 전송할 수 있다. REST 클라이언트라면 JSON이나 XML과 같은 형식으로 ㅇ

사용자와의 상호작용은 표현 영역이 처리하기 때문에 응용 서비스는 표현 영역에 의존하지 않는다. 응용 영역은 사용자가 웹 브라우저를 사용하는지, REST API를 호출하는지, TCP 소켓을 사용하는지 여부를 알 필요가 없다. 단지, 응용 영역은 기능 실행에 필요한 입력값을 전달받고 실행 결과만 리턴하면 된다.

응용 서비스의 역할

응용 서비스는 사용자(클라이언트)가 요청한 기능을 실행한다. 응용 서비스는 사용자의 요청을 처리하기 위해 리포지터리로부터 도메인 객체를 구하고, 도메인 객체를 사용한다.

응용 서비스의 주요 역할은 도메인 객체를 사용해서 사용자의 요청을 처리하는 것이므로 표현(사용자) 영역 입장에서 보았을 때 응용 서비스는 도메인 영역과 표현 영역을 연결해 주는 창구 역할을 한다.

응용 서비스는 주로 도메인 객체 간의 흐름을 제어하기 때문에 다음과 같이 단순한 형태를 갖는다.

public Result doSomeFunc(SomeReq req) {
    // 1. 리포지터리에서 애그리거트를 구한다.
    SomeAgg agg = someAggRepository.findBy(req.getId());
    checkNull(agg);
    
    // 2. 애그리거트의 도메인 기능을 실행한다. 
    agg.doFunc(req.getValue());

    // 3. 결과를 리턴한다.
    return createSuccessResult(agg);
}

새로운 애그리거트를 생성하는 응용 서비스 역시 간단하다.

public Result doSomeCreation(CreateSomeReq req) {
    // 1. 데이터 중복 등 데이터가 유효한지 검사한다.
    checkValid(req);
    
    // 2. 애그리거트를 생성한다. 
    SomeAgg newAgg = createSome(req);
    
    // 3. 리포지터리에 애그리거트를 저장한다. 
    someAggRepository.save(newAgg);

    // 4. 결과를 리턴한다.
    return createSuccessResult(newAgg);
}

응용 서비스가 이것보다 복잡하다면 응용 서비스에서 도메인 로직의 일부를 구현하고 있을 가능성이 높다. 응용 서비스가 도메인 로직을 일부 구현하면 코드 품질에 안 좋은 영향을 준다.

도메인 객체 간의 실행 흐름을 제어하는 것과 더불어 응용 서비스의 주된 역할 중 하나트랜잭션 처리이다. 응용 서비스는 도메인의 상태 변경을 트랜잭션으로 처리해야 한다.

트랜 잭션 외에 응용 서비스의 주요 역할로 접근 제어이벤트 처리가 있는데 이는 뒤에서 다룬다.