티스토리 뷰

개요


# 참고

IMPLEMENTING DOMAIN DRIVEN DESIGN (도메인 주도 설계 구현) - 반 버논 지음

 

# 개요

DDD에 대한 기술서적을 읽고 DDD가 무엇인지 이해하고 어떻게 코드에 적용시킬 수 있는지 고민해 보려고 한다.

 

# 7장의 로드맵

  • 도메인 모델의 정제가 어떻게 서비스의 필요성에 관한 인식으로 이어지는지
  • 도메인에서 서비스는 무엇이고 서비스가 아닌 것은 무엇인지
  • 서비스를 생성할지 결정할 떄 필요한 주의사항
  • 서비스를 모델링하는 방법

7장. 서비스

도메인 내에서 서비스란 도메인 고유의 작업을 수행하는 무상태의 오퍼레이션이다. 도메인 모델에서 서비스를 생성할 필요가 있음을 알리는 가장 정확한 지표는 애그리게잇이나 값 객체 상에서 수행해야 하는 오퍼레이션이 메소드로는 부적절하게 느껴질 때다.

 

7-1. 도메인 서비스란 무었인가?

소프트웨어 컨텍스트에서 서비스란 기본적으로 서비스 지향 아키텍처에서의 서비스를 의미한다. SOA 서비스를 개발하는 데에는 몇 가지 기술과 접근법이 있다. RPC나 메시지 지향 미들웨어를 강조하며 비즈니스 트랜잭션의 실행을 위해 서비스와 상호 교류한다. 하지만 지금까지 설명한 것은 어떤 것도 도메인 서비스가 아니다.

 

도메인 서비스를 애플리케이션 서비스와 혼동해서는 안된다. 비즈니스 로직을 애플리케이션 서비스 안에 넣으려고 하는게 아니라, 비즈니스 로직을 도메인 서비스 안에 넣고자 한다. 도메인 모델은 일반적으로 비즈니스의 특정 측면에 집중된 소단위 행동을 처리하기 때문에, 도메인 서비스는 도메인 모델과 비슷한 원칙을 고수하는 경향이 있다. 도메인 서비스는 다음의 경우에 사용할 수 있따.

  • 중요한 비즈니스 프로세스를 수행할 때
  • 어떤 컴포지션에서 다른 컴포지션으로 도메인 객체를 반영할 때
  • 하나 이상의 도메인 객체에서 필요로 하는 입력 값을 계산할 때

 

7-2. 서비스가 필요한지 확인하자

서비스로 도메인 개념을 모델링하는 데 너무 의존하지 말자. 서비스를 지나치게 사용하면 애너믹 도메인 모델이 만들어지는 부정적인 결과를 초래할 수 있는데, 대부분의 도메인 로직이 엔티티와 값 객체 전체로 흩어지지 못하고 서비스에만 몰리게 된다.

 

Q. 그렇다면 서비스는 왜 필요한 걸까?

클라이언트는 너무 복잡하다. 클라이언트에 쏟아 부은 책임은 모델 안으로 옮겨져야 한다. 순수하게 도메인 특화된 지식은 클라이언트로 절대 유출돼선 안 된다. 클라이언트가 애플리케이션 서비스라 해도, 해당 컴포넌트는 식별자와 액세스 관리 도메인의 책임을 져서는 안 된다. 실제론 클라이언트가 수행해야만 하는 비즈니스적 책임은 다른 모든 세부사항을 다룰 단일 도메인 특정 오퍼레이션의 사용을 조장하는 일 뿐이다.

 

 

7-3. 도메인에서 서비스를 모델링하기

도메인 서비스의 목적이 뭔지에 따라 도메인 내에서 서비스를 모델링하는 일은 아주 간단할 수 있따. 서비스에 분리된 인터페이스가 있어야만 하는지 판단해야 한다. 이 인터페이스는 해당 식별자의 애그리겟잇과 같은 모듈에 선언된다. 이제는 구현 클래스를 어디에 둘지만 결정하면 된다. 의존성 역행 원리나 헥사고날을 사용하고 있다면, 다소 기술적인 구현 클래스는 도메인 모델 외부에 두고 싶을 수도 있다. 한 예로, 기술적 사항의 구현을 인프라 계층의 모듈에 넣을 수 있다.

 

7-4. 분리된 인터페이스가 꼭 필요할까?

서비스에 기술적인 구현이 없는데도 분리된 인터페이스와 구현 클래스가 필요하고, 이를 분리된 계층과 모듈에 담아야 할까? 사실 반드시 필요하진 않는다. 이런 유형의 서비스를 해당 서비스의 이름에 따라 단일 구현 클래스로 만들 수도 있다. 이런 방식도 전혀 문제가 없다. 이런 유형의 서비스는 여러 구현이 필요하지 않으므로 이 접근법이 더 적합한 방법일 수 있다. 그러나 주어진 여러 테넌트가 특별한 보안 표준을 요구할 수 있다는 측변에서, 여러 개의 구현이 조재할 가능성도 있다. 

 

# 구현  클래스의 이름 짓기

일반적으로 자바 세계에서 구현 클래스는 접미사로 Impl을 붙이는 방식이 꽤 보편적인 상황이다. 뿐만 아니라 인터페이스와 구현 클래스는 보통 같은 패키지 안에 위치한다. 이는 좋은 이름일까? 이는 논란의 여지가 있는 주제며, 주로 Impl을 사용해 인터페이스를 명명하는 규모있는 조직이 있다는 사실도 잘 알고 있다. 다만 합리적인 이유로 Impl의 사용에 반대하는 집단도 있다.

ex) UserService(인터페이스) /  UserServiceImpl(구현클래스)

 

분리된 인터페이스의 사용은 스타일에 관한 문제가 된다. 분리도니 인터페이스는 결합 분리의 목표가 분명할 때 유요한다. 인터페이스로의 의존성이 필요한 클라이언트는 해당 구현에 관해선 전혀 몰라도 된다. 그러나 의존성 주입 또는 서비스의 팩토리를 사용하고 있거나 서비스 인터페이스와 클래스가 함께 뭉쳐 있는 상황을 마주했더라도 연전히 클라이언트가 구현을 알지 못하도록 막을 수 있다.

 

제어 역행 컨테이너(IoC/DI)는 서비스 인스턴스를 주입한다. 클라이언트는 서비스를 인스턴스화하지 않기 때문에 인터페이스와 구현의 통합이나 분리에 관해 알지 못한다. 서비스 팩토리와 의존성 주입을 모두 거부하고, 생성자나 메소드의 매개변수로 전달해 인바운드 의존성을 설정하는 편을 선호하는 사람도 있다. 이는 의존성을 연결하고 코드의 테스트를 가능케 하는 가장 명시적인 방법이고, 심지어 의존성 주입보다도 더 쉬울 수 있다. 전반적으로 생성자에 기반한 의존성 설정 방법을 적용하느 가운데, 상황에 맞춰서 세가지 방법 모두를 조합해 사용하는 편이 도움이 된다. 이 책에서는 생성자를 통해 의존성을 설정하거나 매개변수로 직접 전달하는 방식을 선호한다.

 

#Key Point

  • 애그리게잇 인스턴스에서 리파지토리로의 접근은 추천하지 않는 방식이다.
  • 서비스를 과용하지 않으려며, 서비스가 필요한 경우를 합리적으로 인식해야 한다.
  • 도메인 서비스를 과용하면 안티 패턴인 애너믹 도메인 모델로 이러질 수 있다.
  • 분리된 인터페이스를 사용하는 것의 장점과 단점을 생각해 봤다. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함