DDD 도메인주도설계

도메인주도설계 6장

MIN우 2024. 1. 26. 16:38
728x90

# 표현 영역과 응용 영역

- 응용 영역과 표현 영역이 사용자와 도메인을 연결해주는 매개체 역할을 함

- 표현 영역은 응용 서비스가 요구하는 형식으로 사용자 요청을 변환.

- 응용 서비스를 실행한 뒤에 표현 영역은 실행 결과를 사용자에게 알맞은 형식(HTML/JSON)으로 응답

 

# 응용 서비스의 역할 & 주의점

  • 응용 서비스는 사용자가 요청한 기능을 실행하는 영역을 담당한다.
  • 이 때 리포지터리로부터 도메인 객첼르 구하고, 도메인 객체를 사용한다.
  • 주의 사항은 응용 서비스에서 도메인 로직을 넣어서는 안된다.
  • 응용 서비스에서 도메인 로직을 넣으면 두 가지 단점이 존재한다.
    • 코드의 응집도가 떨어진다.
    • 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 높아진다. (이는 실제로 몇 번 경험한 이슈)

 

도메인 로직을 응용서비스로 분산시 문제점

1. 코드 응집성이 떨어짐

2. 여러 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 높아짐

 

# 응용 서비스의 구현

 

## 응용 서비스 구현 방식

1. 한 응용 서비스 클래스에 회원 도메인의 모든 기능 구현

- 장 : 동일 로직에 대한 코드 중복 제거 가능

- 단 : 한 서비스 클래스 크기가 커짐

 

2. 구분되는 기능별로 응용 서비스 클래스를 따로 구현하기

- 기능 별로 2~3개의 기능 구현

- 장 : 코드 품질을 일정 수준으로 유지 가능. 각 클래스 별 필요한 의존 객체만 포함

- 단 : 클래스 개수가 많아짐

Helper 클래스를 통해 중복 로직 관리 

 

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

구현 클래스가 여러개인 경우 인터페이스가 필요함.

허나, 응용 서비스는 런타임에 교체하는 경우가 거의 없고, 응용 서비스의 구현 클래스가 두 개인 경우도 드물다.

 

# 표현 영역

- 사용자가 시스템을 사용할 수 있는 흐름(화면)을 제공/제어

- 사용자의 요청을 알맞은 응용 서비스에 전달하고 결과를 사용자에게 제공

- 사용자 세션 관리

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

  • 응용 서비스의 파라미터 값은 표현 영역과 관련된 파라미터 값이면 안된다.
  • 응용 서비스에서 표현 영역에 대한 의존이 발생하는 순간 응용 서비스만 단독으로 테스트하기가 어려워진다.
  • 심지어 표현 영역이 바뀌면 응용 서비스도 바뀌어야함 (OMG)

트랜잭션 처리

  • 회원가입에 성공했따고 하면서 회원 정보를 DB에 저장하지 않으면 고객은 로그인을 할 수 없다.
  • 이 때 프레임워크가 제공하는 트랜잭션 기능을 적극 사용하는 것이 좋다.
  • 스프링으 경우 @Transactional이 그 대표적인 예이다. (동시에 AOP이기도 하다.)

# 도메인 이벤트 처리

public class Member {
 private Password password;
 public void initializePassword() {
  String newPassword = generateRandomPassword();
  this.password = new Password(newPassword);
  Events.raise(new PasswordChangedEvent(this.id, password);
 }
}
  • 위 코드는 암호 초기화 기능을 수행한 이후 암호 변경 이벤트를 발생시키는 코드이다.
  • 응용 서비스는 이벤트를 받아 처리할 수 있는데 이러한 이벤트 기반의 개발은 코드의 복잡도가 올라가지만 도메인 간의 의존성이나 외부 시스템에 대한 의존도를 낮추는 장점을 얻을 수 있다. (이것이 이벤트 주도 개발?) 기대된다 ㅎㅎ ... 재밌겠다

 

# 값 검증

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

원칙적으로는 응용 서비스에서 처리 : 파라미퍼로 전달받은 값에 대한 검사

표현 영역 : 필수 값, 값 형식, 범위 등 검증

응용 서비스 : 데이터 존재 유무 등 논리적 오류 검증

 

# 권한 검사

표현 영역에서 권한 검사 수행 : 서블릿 필터 등을 통해 인증된 사용자인지 아닌지 검사

응용 서비스에서 권한 검사 수행 : AOP등을 활용

개별 도메인 객체 단위 검사 수행 : 내부에서 직접 권한 검사 로직 수행

# 응용 서비스 영역

  • 스프링 시큐리티는 AOP를 활용해서 다음과 같이 애노테이션으로 서비스 메서드에 대한 권한 검사를 할 수 있는 기능을 제공한다.
public class BlockMemberService {
    private MemberRepository memberRepository;

    @PreAuthorize("hasRole('ADMIN')")
    public void block(String memberName) {
      Member member = memberRepository.findByName(memberName);
      if(member == null) throw new NoMemberException();
      member.block();
    }
    ...
}

 

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

단순 조회 호출은 직접 Repository를 호출할 수 있음.

이 경우는 굳이 서비스를 만들 필요가 없을 수도

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

public class OrderListService {
 public List<OrderView> getOrderList(String ordererId) {
  return orderViewDao.selectByOrderer(ordererId);
 }
}
  • 때때로 서비스 조회만 하는 경우가 종종 있다.
public class OrderController {
 private OrderViewDao orderViewDao;

 @RequestMapping("/myorders")
 public String list(ModelMap model) {
  String ordererId = SecurityContext.getAuthentication().getId();
  List<OrderView> orders = orderViewDao.selectByOrderer(ordererId);
  model.addAttribute("orders", orders);
  return "order/list";
 }
...
  • 만약 서비스에서 수행하는 추가적인 로직이 없고 조회 전용이라 트랜잭션이 필요 없을 경우 표현 영역에서 바로 조회 전용 기능을 사용해도 된다.
  • 즉, 저자는 응용 서비스가 사용자 요청 기능을 실행하는데 별 기여를 하지 못한다면 굳이 서비스를 만들지 않아도 된다고 말한다.
  • 이는 논쟁의 여부가 있을 것 같은데, 개인적으로는 그래도 서비스를 만드는게 낫다고 생각한다.
  • 왜냐하면 추후에 해당 응용 서비스에 조회 외에 다른 비즈니스 로직들이 추가될 여지가 분명히 있을 것이므로…
728x90