[architecture] 도메인 기반 디자인 : 도메인 서비스, 응용 프로그램 서비스

누군가가 몇 가지 예를 제공하여 도메인과 응용 프로그램 서비스의 차이점을 설명 할 수 있습니까? 또한 서비스가 도메인 서비스 인 경우이 서비스의 실제 구현을 도메인 어셈블리 내에 배치하고 해당하는 경우 리포지토리를 해당 도메인 서비스에 삽입 할 것입니까? 어떤 정보는 정말 도움이 될 것입니다.



답변

서비스는 도메인 서비스 , 응용 프로그램 서비스인프라 서비스의 세 가지 형태로 제공 됩니다.

  • Domain Services (도메인 서비스) : 도메인 객체에 맞지 않고 일반적인 CRUD 작업 이 아닌 비즈니스 로직 을 캡슐화
    합니다 . 이는 리포지토리에 속합니다 .
  • 응용 프로그램 서비스 : 외부 소비자가 시스템과 통신하기 위해 사용합니다 ( 웹 서비스 생각 ). 소비자가 CRUD 작업에 액세스해야하는 경우 여기에 노출됩니다.
  • 인프라 서비스 : 기술 문제 (예 : MSMQ, 전자 메일 공급자 등)를 추상화하는 데 사용됩니다.

도메인 서비스와 함께 도메인 서비스를 유지하는 것은 합리적입니다. 모두 도메인 논리에 중점을 둡니다. 예, 리포지토리를 서비스에 주입 할 수 있습니다.

응용 프로그램 서비스는 일반적으로 도메인 서비스 리포지토리를 모두 사용 하여 외부 요청을 처리합니다.

희망이 도움이됩니다!


답변

(읽고 싶지 않다면 하단에 요약이 있습니다 🙂

나도 응용 프로그램 서비스의 정확한 정의로 어려움을 겪었습니다. Vijay의 답변은 한 달 전에 내 사고 과정에 매우 도움이되었지만 그 일부에 동의하지 않았습니다.

기타 자료

응용 프로그램 서비스에 대한 정보는 거의 없습니다. 집계 루트, 저장소 및 도메인 서비스와 같은 주제는 광범위하게 논의되지만 애플리케이션 서비스는 간략하게 언급되거나 완전히 생략됩니다.

MSDN Magazine 기사 도메인 기반 디자인 소개 에서는 도메인 모델을 외부 클라이언트 (예 : WCF 서비스)로 변환 및 / 또는 노출하는 방법으로 응용 프로그램 서비스를 설명합니다. 이것이 Vijay가 애플리케이션 서비스를 설명하는 방식입니다. 이러한 관점에서 응용 프로그램 서비스는 도메인에 대한 인터페이스 입니다.

Onion Architecture에 관한 Jeffrey Palermo의 기사 ( 1 부 , 2 부3 부 )는 잘 읽습니다. 그는 응용 프로그램 서비스를 사용자 세션과 같은 응용 프로그램 레벨 개념 으로 취급합니다 . 이것은 응용 프로그램 서비스에 대한 이해에 더 가깝지만 여전히 주제에 대한 나의 생각과 일치하지 않습니다.

내 생각

응용 프로그램 서비스가 응용 프로그램에서 제공하는 종속성 으로 생각하게되었습니다 . 이 경우 응용 프로그램은 데스크톱 응용 프로그램 또는 WCF 서비스 일 수 있습니다.

도메인

예를 들어 시간입니다. 당신은 당신의 도메인으로 시작합니다. 외부 자원에 의존하지 않는 모든 엔티티 및 도메인 서비스가 여기에 구현됩니다. 외부 자원에 의존하는 모든 도메인 개념은 인터페이스에 의해 정의됩니다. 가능한 솔루션 레이아웃은 다음과 같습니다 (프로젝트 이름은 굵게 표시됨).

내 솔루션
- My.Product.Core (My.Product.dll)
  -도메인 서비스
      IExchangeRateService
    생성물
    제품 공장
    IProductRepository

ProductProductFactory클래스는 코어 어셈블리에 구현되었다. 는 IProductRepository아마 데이터베이스에 의해 백업됩니다 무언가이다. 이것의 구현은 도메인의 관심사가 아니므로 인터페이스에 의해 정의됩니다.

지금은에 초점을 맞출 것 IExchangeRateService입니다. 이 서비스의 비즈니스 로직은 외부 웹 서비스에 의해 구현됩니다. 그러나이 개념은 여전히 ​​도메인의 일부이며이 인터페이스로 표시됩니다.

하부 구조

외부 종속성의 구현은 응용 프로그램 인프라의 일부입니다.

내 솔루션
+ My.Product.Core (My.Product.dll)
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
  -도메인 서비스
      XEExchangeRateService
    SqlServerProductRepository

XEExchangeRateServicexe.comIExchangeRateService 과 통신 하여 도메인 서비스를 구현합니다 . 이 구현은 인프라 어셈블리를 포함하여 도메인 모델을 사용하는 응용 프로그램에서 사용할 수 있습니다.

신청

아직 애플리케이션 서비스에 대해서는 언급하지 않았습니다. 우리는 지금 그것들을 볼 것입니다. IExchangeRateService빠른 조회를 위해 캐시를 사용 하는 구현 을 제공한다고 가정 해 보겠습니다 . 이 데코레이터 클래스의 개요는 다음과 같습니다.

public class CachingExchangeRateService : IExchangeRateService
{
    private IExchangeRateService service;
    private ICache cache;

    public CachingExchangeRateService(IExchangeRateService service, ICache cache)
    {
        this.service = service;
        this.cache = cache;
    }

    // Implementation that utilizes the provided service and cache.
}

통지 ICache매개 변수를? 이 개념은 도메인의 일부가 아니므로 도메인 서비스가 아닙니다. 그것은이다 애플리케이션 서비스 . 애플리케이션에서 제공 할 수있는 인프라의 종속성입니다. 이것을 보여주는 응용 프로그램을 소개합시다 :

내 솔루션
- My.Product.Core (My.Product.dll)
  -도메인 서비스
      IExchangeRateService
    생성물
    제품 공장
    IProductRepository
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
  -응용 서비스
      ICache
  -도메인 서비스
      CachingExchangeRateService
      XEExchangeRateService
    SqlServerProductRepository
- My.Product.WcfService (My.Product.WcfService.dll)
  -응용 서비스
      MemcachedCache
    IMyWcfService.cs
  + MyWcfService.svc
  + Web.config

이것은 모두 다음과 같이 응용 프로그램에서 함께 제공됩니다.

// Set up all the dependencies and register them in the IoC container.
var service = new XEExchangeRateService();
var cache = new MemcachedCache();
var cachingService = new CachingExchangeRateService(service, cache);

ServiceLocator.For<IExchangeRateService>().Use(cachingService);

요약

완전한 응용 프로그램은 세 가지 주요 계층으로 구성됩니다.

  • 도메인
  • 하부 구조
  • 신청

도메인 계층에는 도메인 엔티티 및 독립형 도메인 서비스가 포함됩니다. 외부 리소스에 의존하는 모든 도메인 개념 (도메인 서비스 및 리포지토리 포함)은 인터페이스로 정의됩니다.

인프라 계층에는 도메인 계층의 인터페이스 구현이 포함됩니다. 이러한 구현은 애플리케이션에 제공되어야하는 새로운 비 도메인 종속성을 도입 할 수 있습니다. 이들은 응용 프로그램 서비스이며 인터페이스로 표시됩니다.

응용 프로그램 계층에는 응용 프로그램 서비스의 구현이 포함됩니다. 인프라 스트럭처 계층에서 제공하는 구현이 충분하지 않은 경우 응용 프로그램 계층에는 도메인 인터페이스의 추가 구현도 포함될 수 있습니다.

이 관점은 일반적인 DDD 서비스 정의와 일치하지 않을 수 있지만 도메인을 응용 프로그램과 분리하고 여러 응용 프로그램간에 도메인 (및 인프라) 어셈블리를 공유 할 수 있습니다.


답변

애플리케이션 서비스와 도메인 서비스의 차이점을 이해하는 데 도움이 된 최고의 리소스는 here 에있는 Eric Evans의화물 예제의 Java 구현이었습니다 . 로드하지 않으면 RoutingService (도메인 서비스)와 BookingService CargoInspectionService (응용 프로그램 서비스)의 내부를 확인할 수 있습니다.

내 ‘aha’순간은 두 가지로 인해 유발되었습니다.

  • 위의 링크에서 서비스에 대한 설명, 더 정확하게는이 문장을 읽으십시오.

    도메인 서비스는 유비쿼터스 언어와 도메인 유형으로 표현됩니다. 즉, 메소드 인수와 반환 값은 적절한 도메인 클래스입니다.

  • 블로그 게시물 , 특히이 부분을 읽으십시오 .

    사과를 오렌지에서 분리하는 데 큰 도움이되는 것은 응용 프로그램 워크 플로우 측면에서 생각하는 것입니다. 응용 프로그램 워크 플로와 관련된 모든 논리는 일반적으로 응용 프로그램 서비스 계층에 응용 프로그램 서비스를 고려한 반면 모델 개체에 맞지 않는 도메인의 개념은 결국 하나 이상의 도메인 서비스를 형성합니다.


답변

도메인 서비스도메인 의 확장입니다. 도메인 컨텍스트에서만 볼 수 있습니다. 예를 들어 계정 해지와 같은 사용자 작업이 아닙니다 . 도메인 서비스는 상태가없는 곳에 적합합니다. 그렇지 않으면 도메인 개체가됩니다. 도메인 서비스는 다른 공동 작업자 (도메인 개체 또는 다른 서비스)와 함께 작업 할 때만 의미가있는 작업을 수행합니다. 그리고 그 이해 는 다른 계층의 책임입니다.

응용 프로그램 서비스 는 도메인 개체와 서비스 간의 상호 작용을 초기화하고 감독하는 계층입니다. 플로우는 일반적으로 저장소에서 도메인 오브젝트를 가져 와서 조치를 실행 한 후 다시 배치합니다. 더 많은 작업을 수행 할 수 있습니다. 예를 들어 도메인 개체의 존재 여부를 확인하고 그에 따라 예외를 throw 할 수 있습니다. 따라서 사용자는 도메인 개체와 서비스를 조작하여 응용 프로그램과 상호 작용할 수 있습니다 (그리고 이름이 유래 한 곳일 수도 있음). 응용 프로그램 서비스는 일반적으로 가능한 모든 사용 사례를 나타내야합니다.. 아마도 도메인에 대해 생각하기 전에 할 수있는 최선의 방법은 응용 프로그램 서비스 인터페이스를 작성하여 실제로 수행하려는 작업에 대한 더 나은 통찰력을 제공하는 것입니다. 그러한 지식이 있으면 도메인에 집중할 수 있습니다.

리포지토리는 일반적으로 도메인 서비스에 주입 될 수 있지만 이는 드문 시나리오입니다. 그래도 대부분의 시간을하는 것은 응용 프로그램 계층입니다.


답변

레드 북 (Vaughn Vernon의 도메인 기반 디자인 구현)에서이 개념을 이해합니다.

도메인 객체 ( 엔티티값 객체 )는 (하위) 도메인에 필요한 동작을 캡슐화하여 자연스럽고 표현 가능하며 이해하기 쉽게 만듭니다.

도메인 서비스단일 도메인 개체에 맞지 않는 이러한 동작을 캡슐화 합니다. 예를 들어, a에 a Book를 대출하는 서적 라이브러리 Client(해당 Inventory변경 사항 포함)는 도메인 서비스에서 수행 할 수 있습니다.

응용 프로그램 서비스 는 도메인 필요한 추가 문제를 비롯하여 사용 사례 흐름을 처리합니다 . 종종 외부 클라이언트가 사용할 수 있도록 API를 통해 이러한 메소드를 노출합니다. 이전 예제를 바탕으로 애플리케이션 서비스는 다음과 같은 메소드 LendBookToClient(Guid bookGuid, Guid clientGuid)를 노출 할 수 있습니다 .

  • 을 검색합니다 Client.
  • 권한을 확인합니다. ( 도메인 모델에 보안 / 사용자 관리 문제가 없는지 확인했습니다. 이러한 오염으로 인해 많은 문제가 발생할 수 있습니다. 대신 애플리케이션 서비스에서이 기술 요구 사항을 충족합니다. )
  • 을 검색합니다 Book.
  • 도메인 서비스를 호출 ( Client및 전달 Book) 하여 클라이언트에게 책을 대출하는 실제 도메인 논리 를 처리합니다 . 예를 들어 책의 가용성을 확인하는 것이 도메인 논리의 일부라고 생각합니다.

응용 프로그램 서비스는 일반적으로 매우 간단한 흐름을 가져야합니다. 복잡한 응용 프로그램 서비스 흐름은 종종 도메인 논리가 도메인에서 유출되었음을 나타냅니다.

잘 아시다시피, 도메인 모델 은 이러한 방식으로 매우 깨끗하게 유지 되며 도메인 전문가에게는 실제 비즈니스 관련 문제 만 포함되므로 도메인 전문가와 이해하고 토론하기 쉽습니다. 응용 프로그램의 흐름은 , 다른 한편으로는,이다 또한 이 도메인 우려 완화되기 때문에 관리가 훨씬 쉽게, 그리고 간결하고 간단하게된다.


답변

도메인 서비스 : 단일 엔티티에 실제로 맞지 않거나 저장소에 액세스해야하는 메소드는 도메인 서비스 내에 포함됩니다. 도메인 서비스 계층은 자체 도메인 로직을 포함 할 수 있으며 엔터티 및 값 개체만큼 도메인 모델의 일부입니다.

응용 프로그램 서비스 : 응용 프로그램 서비스는 도메인 모델 위에 있으며 응용 프로그램 활동을 조정하는 얇은 계층입니다. 비즈니스 로직을 포함하지 않으며 엔티티의 상태를 보유하지 않습니다. 그러나 비즈니스 워크 플로 트랜잭션의 상태를 저장할 수 있습니다. 응용 프로그램 서비스를 사용하여 요청-응답 메시징 패턴을 사용하여 도메인 모델에 API를 제공합니다.

Millett, C (2010). 전문 ASP.NET 디자인 패턴. 와일리 출판. 92.


답변

도메인 서비스 : Aggregate Root의 일부가 아닌 비즈니스 로직 을 표현하는 서비스입니다 .

  • 2 개의 집계가 있습니다.

    • Product 이름과 가격이 포함되어 있습니다.
    • Purchase 여기에는 구매 날짜, 당시 수량 및 제품 가격으로 주문한 제품 목록 및 결제 방법이 포함됩니다.
  • Checkout 이 두 모델 중 하나의 일부가 아니며 비즈니스에서 개념입니다.

  • Checkout는 모든 제품을 가져와 총 가격을 계산하고 PaymentService인프라의 구현 부분으로 다른 도메인 서비스 를 호출하여 총액을 지불 한 다음로 변환하는 도메인 서비스로 생성 될 수 있습니다 Purchase.

응용 프로그램 서비스 : 도메인 방법 을 “오케스트레이션” 하거나 연습 하는 서비스입니다 . 이것은 컨트롤러처럼 간단 할 수 있습니다.

이곳은 일반적으로 수행하는 곳입니다.

public String createProduct(...some attributes) {
  if (productRepo.getByName(name) != null) {
    throw new Exception();
  }

  productId = productRepository.nextIdentity();

  product = new Product(productId, ...some attributes);

  productRepository.save(product);

  return productId.value();
  // or Product itself
  // or just void if you dont care about result
}

public void renameProduct(productId, newName) {
  product = productRepo.getById(productId);

  product.rename(newName);

  productRepo.save(product);
}

여기서 Product고유한지 확인하는 등의 유효성 검사를 수행 할 수 있습니다 . 하지 않으면 Product되는 독특한이 불변 인 그 호출 할 수있는 도메인 서비스의 일부가되어야 UniqueProductChecker그것의 일부가 될 수 없기 때문에 Product클래스와는 여러 집계와 상호 작용합니다.

다음은 DDD 프로젝트의 완전한 예입니다. https://github.com/VaughnVernon/IDDD_Samples

많은 응용 프로그램 서비스 예제와 몇 가지 도메인 서비스를 찾을 수 있습니다