리치 vs 빈혈 도메인 모델 [닫힘]


97

나는 빈혈 도메인 모델보다 리치 도메인 모델을 사용해야하는지 결정하고 있으며 두 가지의 좋은 예를 찾고 있습니다.

저는 서비스-> 리포지토리-> 스토리지 계층 시스템에서 지원하는 Anemic 도메인 모델을 사용하여 웹 애플리케이션을 구축하고 있으며 , BL 유효성 검사를 위해 FluentValidation 을 사용 하고 모든 BL을 서비스 계층에 배치했습니다.

나는 Eric Evan의 DDD 책을 읽었고, 그는 (Fowler와 다른 사람들과 함께) Anemic Domain Models가 반 패턴이라고 생각하는 것 같습니다.

그래서 저는이 문제에 대한 통찰력을 얻고 싶었습니다.

또한 저는 Rich Domain 모델의 좋은 (기본) 예제와 그것이 제공하는 Anemic Domain Model에 비해 이점을 찾고 있습니다.



14
DDD> ADM , ADM> DDD , DDD> ADM , ADM> DDD , ADM + DDD ... DDD / ADM 또는 소프트웨어 설계에 대해 동의하지 않는 방법 !
sp00m

빈혈 도메인 모델을 피하는 방법의 예는 다음과 같습니다. medium.com/@wrong.about/…
Vadim Samokhin 2017

11
이 질문에 실제 조직이 자금을 지원하는 실제 프로젝트에 대한 단일 링크로 대답 할 수 있다는 것은 재밌습니다. 5 년 후, IMO. 토크는 싸다. 코드를 보여주세요.
Mateusz Stefek

답변:


57

차이점은 빈약 한 모델은 논리와 데이터를 분리한다는 것입니다. 논리는 종종라는 이름의 클래스에 배치됩니다 **Service, **Util, **Manager, **Helper과에 있도록. 이러한 클래스는 데이터 해석 논리를 구현하므로 데이터 모델을 인수로 사용합니다. 예

public BigDecimal calculateTotal(Order order){
...
}

리치 도메인 접근 방식은 데이터 해석 로직을 리치 도메인 모델에 배치하여이를 역전시킵니다. 따라서 논리와 데이터를 결합하고 풍부한 도메인 모델은 다음과 같습니다.

order.getTotal();

이것은 객체 일관성에 큰 영향을 미칩니다. 데이터 해석 로직이 데이터를 래핑하기 때문에 (데이터는 객체 메서드를 통해서만 액세스 할 수 있음) 메서드는 다른 데이터의 상태 변경에 반응 할 수 있습니다.-> 이것이 우리가 행동이라고 부르는 것입니다.

빈약 한 모델에서 데이터 모델은 그들이 할 수있는 풍부한 도메인 모델에있는 동안 합법적 인 상태에 있다는 것을 보장 할 수 없습니다. 풍부한 도메인 모델은 캡슐화, 정보 숨기기 및 데이터와 논리를 함께 가져 오는 것과 같은 OO 원칙을 적용하므로 빈혈 모델은 OO 관점에서 반 패턴입니다.

더 깊은 통찰력을 얻으려면 내 블로그 https://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/를 살펴보십시오.


15
주문의 총 가격을 계산하는 데 다음이 포함된다고 가정 해 보겠습니다. 1) 가능한 많은 로열티 프로그램 중 하나의 회원 인 고객에 따라 할인 적용. 2) 현재 매장에서 운영하는 마케팅 캠페인에 따라 특정 품목 그룹을 함께 포함하는 주문에 대해 할인 적용. 3) 세액이 주문의 각 특정 항목에 따라 달라지는 세금 계산. 이 모든 논리가 어디에 속한다고 생각하십니까? 간단한 의사 코드 예를 들어 주시겠습니까? 감사합니다!
Nik

4
@Nik 리치 모델에서 주문에는 고객 개체에 대한 참조가 있고 고객 개체에는 로열티 프로그램에 대한 참조가 있습니다. 따라서 Order는 해당 정보를 가져올 서비스 및 저장소와 같은 항목에 대한 명시 적 참조없이 필요한 모든 정보에 액세스 할 수 있습니다. 그러나 순환 참조가 발생하는 경우에는 쉽게 부딪 힐 수 있습니다. 즉, 주문은 고객을 참조하고 고객은 모든 주문의 목록을 가지고 있습니다. 이것이 사람들이 지금 Anemic을 선호하는 부분적인 이유라고 생각합니다.
분쇄

3
@crush 당신이 설명하는 접근 방식은 정말 잘 작동합니다. 하나의 캐치가 있습니다. 아마도 우리는 DB에 엔티티를 저장합니다. 따라서 주문 총액을 계산하려면 DB에서 Order, Customer, Loyalty Program, Marketing Campaign, Taxes Table을 가져와야합니다. 또한 고객에게는 주문 컬렉션이 있고 로열티 프로그램에는 고객 컬렉션 등이 있습니다. 이 모든 것을 순진하게 가져 오면 전체 DB를 RAM에로드하게됩니다. 물론 실행 가능하지 않으므로 DB에서 관련 데이터 만로드합니다. 1/2
Nik

3
@Nik "기본적으로이 모든 것을 가져 오면 전체 DB를 RAM에로드하게됩니다." 그것은 내 마음 속에있는 풍부한 모델의 주요 단점 중 하나이기도합니다. 풍부한 모델은 도메인이 크고 복잡해지면 인프라 제한에 도달 할 때까지 유용합니다. 하지만 지연로드 ORM이 도움이 될 수있는 곳입니다. 좋은 모델을 찾으면 데이터베이스의 1/20 만 필요할 때 전체 DB를 메모리에로드하지 않고 풍부한 모델을 유지할 수 있습니다. 즉, 나는 빈혈과 부자 사이를 오가는 수년 후에 CQRS와 함께 빈혈 모델을 사용하는 경향이 있습니다.
crush

2
고려해야 할 또 다른 사항은 비즈니스 도메인 논리가있는 위치입니다. 점점 더 많은 개발자들이 그것을 데이터베이스에서 내 의견으로는 그것이 속한 애플리케이션으로 옮기고 있습니다. 그러나 회사에서 비즈니스 로직이 데이터베이스 계층 (저장 프로 시저)에 유지되도록 요구하는 상황에 갇혀 있다면 리치 도메인 모델에 해당 로직을 추가해도 거의 혜택을받지 못할 것입니다. 실제로 저장 프로 시저가 응용 프로그램의 도메인 계층과 다른 규칙을 갖는 충돌
crush

53

Bozhidar Bozhanov는 블로그 게시물 에서 빈혈 모델을 찬성하는 것으로 보입니다 .

그가 제시하는 요약은 다음과 같습니다.

  • 도메인 객체는 스프링 (IoC)으로 관리되어서는 안되며, DAO 또는 인프라와 관련된 어떤 것도 주입되어서는 안됩니다.

  • 도메인 개체는 최대 절전 모드 (또는 지속성 메커니즘)에 의해 설정된 도메인 개체를 가지고 있습니다.

  • 도메인 개체는 DDD의 핵심 아이디어처럼 비즈니스 로직을 수행하지만 여기에는 데이터베이스 쿼리 또는 CRUD가 포함되지 않고 개체의 내부 상태에 대한 작업 만 포함됩니다.

  • DTO가 거의 필요하지 않습니다. 도메인 개체는 대부분의 경우 DTO 자체입니다 (일부 상용구 코드 절약).

  • 서비스는 CRUD 작업을 수행하고, 이메일을 보내고, 도메인 개체를 조정하고, 여러 도메인 개체를 기반으로 보고서를 생성하고, 쿼리를 실행합니다.

  • 서비스 (애플리케이션) 계층은 그다지 얇지는 않지만 도메인 개체에 내재 된 비즈니스 규칙은 포함하지 않습니다.

  • 코드 생성은 피해야합니다. 추상화, 디자인 패턴 및 DI는 코드 생성의 필요성을 극복하고 궁극적으로 코드 중복을 제거하는 데 사용되어야합니다.

최신 정보

필자는 최근 저자가 일종의 하이브리드 접근 방식을 옹호하는 기사를 읽었습니다. 도메인 개체는 상태에 따라 다양한 질문에 답할 수 있습니다 (완전히 빈약 한 모델의 경우 서비스 계층에서 수행 될 수 있음).


11
나는 Bozho가 빈혈 도메인 모델을 찬성하는 것으로 보이는 기사에서 추출 할 수 없습니다. 서비스 (애플리케이션) 계층은 그다지 얇지는 않지만 도메인 객체에 내재 된 비즈니스 규칙을 포함하지 않습니다 . 내가 이해하는 것은 도메인 개체는 고유 한 비즈니스 논리를 포함해야하지만 다른 인프라 논리를 포함해서는 안된다는 것 입니다. 이 접근 방식은 나에게 빈혈 도메인 모델처럼 보이지 않습니다.
Utku

8
또한 이것은 도메인 개체가 DDD의 핵심 아이디어처럼 비즈니스 논리를 수행하지만 데이터베이스 쿼리 나 CRUD는 포함하지 않고 개체의 내부 상태에 대한 작업 만 포함합니다 . 이러한 진술은 빈혈 도메인 모델을 전혀 선호하지 않는 것 같습니다. 인프라 논리 가 도메인 개체에 연결되어서는 안된다고 만 명시 합니다. 적어도 그것이 내가 이해하는 것입니다.
Utku

@Utku 내 견해로는 Bozho가 두 모델 사이의 일종의 하이브리드를 옹호한다는 것이 상당히 분명해 보입니다. 하이브리드는 풍부한 모델보다 빈혈 모델에 더 가깝다고 말하고 싶습니다.
geoand

41

내 관점은 다음과 같습니다.

빈약 한 도메인 모델 = 개체에 매핑 된 데이터베이스 테이블 (필드 값만, 실제 동작 없음)

풍부한 도메인 모델 = 동작을 노출하는 개체 모음

간단한 CRUD 애플리케이션을 만들고 싶다면 클래식 MVC 프레임 워크가있는 빈약 한 모델이면 충분합니다. 그러나 어떤 종류의 논리를 구현하려는 경우 빈혈 모델은 객체 지향 프로그래밍을 수행하지 않음을 의미합니다.

* 객체 동작은 지속성과 관련이 없습니다. 다른 계층 (데이터 매퍼, 리포지토리 등)은 도메인 개체를 유지하는 역할을합니다.


5
내 무지에 대해 미안하지만 모든 엔티티 관련 논리를 클래스에 넣으면 풍부한 도메인 모델이 어떻게 SOLID 프린시 페를 따를 수 있습니까? 이것은 SOLID principe, The 'S'를 위반합니다. 즉, 단일 책임을 의미합니다. 즉, 클래스는 한 가지만 수행하고 올바르게 수행해야합니다.
redigaffi

6
@redigaffi "한 가지"를 정의하는 방법에 따라 다릅니다. 두 가지 속성과 두 가지 방법으로 클래스를 고려 : x, y, sumdifference. 네 가지입니다. 또는 덧셈과 뺄셈 (두 가지)이라고 주장 할 수 있습니다. 또는 그것이 수학이라고 주장 할 수 있습니다 (한 가지). SRP 적용에서 균형을 찾는 방법에 대한 많은 블로그 게시물이 있습니다. 여기에 하나 있습니다 : hackernoon.com/…
Rainbolt

2
DDD에서 단일 책임은 클래스 / 모델이 시스템 전체에 부작용을 일으키지 않고 자체 상태를 관리 할 수 ​​있음을 의미합니다. 다른 정의는 내 경험에서 지루한 철학적 논쟁을 초래할뿐입니다.
ZombieTfk

12

우선, http://msdn.microsoft.com/en-gb/magazine/dn385704.aspx 의 답변을 복사하여 붙여 넣었습니다 .

그림 1은 기본적으로 게터와 세터가있는 스키마 인 Anemic Domain Model을 보여줍니다.

Figure 1 Typical Anemic Domain Model Classes Look Like Database Tables

public class Customer : Person
{
  public Customer()
  {
    Orders = new List<Order>();
  }
  public ICollection<Order> Orders { get; set; }
  public string SalesPersonId { get; set; }
  public ShippingAddress ShippingAddress { get; set; }
}
public abstract class Person
{
  public int Id { get; set; }
  public string Title { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string CompanyName { get; set; }
  public string EmailAddress { get; set; }
  public string Phone { get; set; }
}

이 풍부한 모델에서 단순히 읽고 쓸 속성을 ​​노출하는 것이 아니라 Customer의 공개 표면은 명시 적 메서드로 구성됩니다.

Figure 2 A Customer Type That’s a Rich Domain Model, Not Simply Properties

public class Customer : Contact
{
  public Customer(string firstName, string lastName, string email)
  {
    FullName = new FullName(firstName, lastName);
    EmailAddress = email;
    Status = CustomerStatus.Silver;
  }
  internal Customer()
  {
  }
  public void UseBillingAddressForShippingAddress()
  {
    ShippingAddress = new Address(
      BillingAddress.Street1, BillingAddress.Street2,
      BillingAddress.City, BillingAddress.Region,
      BillingAddress.Country, BillingAddress.PostalCode);
  }
  public void CreateNewShippingAddress(string street1, string street2,
   string city, string region, string country, string postalCode)
  {
    ShippingAddress = new Address(
      street1,street2,
      city,region,
      country,postalCode)
  }
  public void CreateBillingInformation(string street1,string street2,
   string city,string region,string country, string postalCode,
   string creditcardNumber, string bankName)
  {
    BillingAddress = new Address      (street1,street2, city,region,country,postalCode );
    CreditCard = new CustomerCreditCard (bankName, creditcardNumber );
  }
  public void SetCustomerContactDetails
   (string email, string phone, string companyName)
  {
    EmailAddress = email;
    Phone = phone;
    CompanyName = companyName;
  }
  public string SalesPersonId { get; private set; }
  public CustomerStatus Status { get; private set; }
  public Address ShippingAddress { get; private set; }
  public Address BillingAddress { get; private set; }
  public CustomerCreditCard CreditCard { get; private set; }
}

2
객체를 생성하고 새로 생성 된 객체에 속성을 할당하는 메서드에 문제가 있습니다. 따라서 코드의 확장 성과 유연성이 떨어집니다. 1) 코드 소비자가 여러 추가 속성을 사용하여 에서 상속 하지 Address않고 ExtendedAddress에서 상속 하려는 경우 어떻게 Address됩니까? 2) 아니면 CustomerCreditCard생성자 매개 변수를 변경 하여 BankID대신 BankName?
Lightman

주소를 생성하려면 객체를 구성하는 것보다 추가 서비스가 필요합니까? 이러한 서비스를 얻으려면 메서드 삽입이 필요합니다. 서비스가 많으면 어떨까요?
분쇄

8

풍부한 도메인 클래스의 이점 중 하나는 모든 계층의 개체에 대한 참조가있을 때마다 해당 동작 (메서드)을 호출 할 수 있다는 것입니다. 또한 함께 협력하는 작고 분산 된 방법을 작성하는 경향이 있습니다. 빈약 한 도메인 클래스에서는 일반적으로 사용 사례에 따라 구동되는 서비스 계층에서 복잡한 절차 방법을 작성하는 경향이 있습니다. 일반적으로 풍부한 도메인 클래스에 비해 유지 관리가 어렵습니다.

동작이있는 도메인 클래스의 예 :

class Order {

     String number

     List<OrderItem> items

     ItemList bonus

     Delivery delivery

     void addItem(Item item) { // add bonus if necessary }

     ItemList needToDeliver() { // items + bonus }

     void deliver() {
         delivery = new Delivery()
         delivery.items = needToDeliver()
     }

}

메서드 needToDeliver()는 보너스를 포함하여 배달해야하는 항목 목록을 반환합니다. 클래스 내부, 다른 관련 클래스 또는 다른 레이어에서 호출 할 수 있습니다. 예를 들어 Order보기로 전달 하면 needToDeliver()선택한 Order항목을 사용하여 사용자가 저장 버튼을 클릭하여 Order.

댓글에 응답

컨트롤러에서 도메인 클래스를 사용하는 방법은 다음과 같습니다.

def save = {
   Order order = new Order()
   order.addItem(new Item())
   order.addItem(new Item())
   repository.create(order)
}

생성 Order과 그 생성은 LineItem하나의 트랜잭션에 있습니다. LineItem둘 중 하나를 만들 수없는 경우에는 생성되지 않습니다 Order.

다음과 같은 단일 트랜잭션을 나타내는 메서드가있는 경향이 있습니다.

def deliver = {
   Order order = repository.findOrderByNumber('ORDER-1')
   order.deliver()       
   // save order if necessary
}

내부의 모든 deliver()것은 하나의 단일 트랜잭션으로 실행됩니다. 단일 트랜잭션에서 관련없는 많은 메서드를 실행해야하는 경우 서비스 클래스를 만듭니다.

지연로드 예외를 방지하기 위해 JPA 2.1 명명 된 엔티티 그래프를 사용합니다. 예를 들어, 배달 화면 컨트롤러, I는 로딩 방법 만들 수 delivery속성을 무시 bonus등을 repository.findOrderByNumberFetchDelivery(). 보너스 화면에서, 나는 부하가 다른 메서드를 호출 bonus속성을 무시 delivery같은 repository.findOrderByNumberFetchBonus(). 여전히 deliver()보너스 화면에서 전화를 걸 수 없기 때문에 dicipline이 필요합니다 .


1
거래 범위는 어떻습니까?
kboom

5
도메인 모델 동작에는 지속성 논리 (트랜잭션 포함)가 포함되지 않아야합니다. 데이터베이스에 연결하지 않고도 단위 테스트에서 테스트 할 수 있어야합니다. 트랜잭션 범위는 서비스 계층 또는 지속성 계층의 책임입니다.
jocki jul.

1
그렇다면 지연 로딩은 어떻습니까?
kboom

단위 테스트에서 도메인 클래스 인스턴스를 만들면 일반 개체이기 때문에 관리 상태가 아닙니다. 모든 동작을 적절하게 테스트 할 수 있습니다.
jocki jul.

서비스 계층에서 도메인 개체를 기대하면 어떻게됩니까? 그때 관리되지 않습니까?
kboom

8

모 놀리 식 데스크톱 앱을 작성했을 때 저는 풍부한 도메인 모델을 구축하여 즐겁게 구축했습니다.

이제 저는 작은 HTTP 마이크로 서비스를 작성합니다. 빈약 한 DTO를 포함하여 가능한 한 적은 코드가 있습니다.

DDD와이 빈약 한 논쟁은 모 놀리 식 데스크톱 또는 서버 앱 시대부터 시작되었다고 생각합니다. 그 시대를 기억하며 빈혈 모델이 이상하다는 데 동의합니다. 큰 모 놀리 식 FX 거래 앱을 만들었는데 모델이 없었습니다. 정말 끔찍했습니다.

마이크로 서비스를 사용하면 다양한 동작을하는 소규모 서비스가 도메인 내에서 구성 가능한 모델 및 집계 일 수 있습니다. 따라서 마이크로 서비스 구현 자체에는 추가 DDD가 필요하지 않을 수 있습니다. 마이크로 서비스 애플리케이션은 도메인 일 수 있습니다.

주문 마이크로 서비스에는 RESTful 리소스로 표현되거나 SOAP 등을 통해 표현되는 함수가 거의 없을 수 있습니다. 주문 마이크로 서비스 코드는 매우 간단 할 수 있습니다.

더 큰 모 놀리 식 단일 (마이크로) 서비스, 특히 모델을 RAM에 유지하는 서비스는 DDD의 이점을 누릴 수 있습니다.


현재의 최신 상태를 나타내는 HTTP 마이크로 서비스에 대한 코드 예제가 있습니까? 아무 것도 작성하라고 요구하지 말고, 지적 할 수있는 것이 있으면 링크를 공유하십시오. 감사.
Casey Plummer

3

문제의 근원은 잘못된 이분법에 있다고 생각합니다. 어떻게이 두 가지 모델을 추출 할 수 있습니까? 풍부하고 "빈혈"이고 서로 대조 할 수 있습니까? 수업이 무엇인지에 대해 잘못된 생각이있을 때만 가능하다고 생각합니다 . 잘 모르겠지만 Youtube의 Bozhidar Bozhanov 비디오 중 하나에서 찾은 것 같습니다. 클래스는이 데이터에 대한 데이터 + 메서드가 아닙니다. 클래스를 데이터 만, 그래서 빈약 한 모델데이터 + 메소드 로 나누는 것은 완전히 타당하지 않은 이해입니다 .

사실 클래스는 어떤 존재 론적 모델, 단어, 정의, 용어, 아이디어의 개념이며 DENOTAT 입니다. 그리고 이러한 이해는 잘못된 이분법을 제거합니다. 빈혈 모델 만 있거나 풍부한 모델 만 가질 수는 없습니다. 이는 모델이 적절하지 않다는 것을 의미하기 때문에 현실과 관련이 없습니다. 일부 개념에는 데이터 만 있고 일부는 방법 만 있고 일부는 그들 중 혼합됩니다. 이 경우 일부 카테고리, 객체 세트, 관계, 클래스가있는 개념을 설명하려고하기 때문에 우리가 아는 바와 같이 일부 개념은 프로세스 전용 (메서드)이고 일부는 속성 세트 (데이터), 일부는 속성과의 관계 (혼합)입니다.

적절한 응용 프로그램에는 모든 종류의 클래스가 포함되어야하고 단 하나의 모델에 광적으로 제한되지 않도록해야한다고 생각합니다. 논리가 어떻게 표현 되든 상관없이 : 코드 또는 해석 가능한 데이터 객체 (예 : Free Monads )를 사용하여 어쨌든 : 프로세스, 논리, 관계, 속성, 기능, 데이터 등을 나타내는 클래스 (개념, 표시)가 있어야합니다. 그들 중 일부를 피하거나 모두를 한 종류로만 줄이려고합니다.

따라서 논리를 다른 클래스로 추출하고 데이터를 원래 클래스에 남겨 둘 수 있지만 일부 개념에는 속성 및 관계 / 프로세스 / 메소드를 포함 할 수 있고 이들을 분리하면 개념이 2 개의 이름으로 복제 될 수 있으므로 의미가 없습니다. 패턴으로 축소 : "OBJECT-Attributes"및 "OBJECT-Logic". 절차 적 및 기능적 언어의 한계 때문에 괜찮지 만 모든 종류의 개념을 설명 할 수있는 언어에 대해서는 과도한 자기 제한입니다.


1

빈약 한 도메인 모델은 ORM과 네트워크를 통한 손쉬운 전송 (모든 상용 애플리케이션의 생명선)에 중요하지만 OO는 코드의 '트랜잭션 / 처리'부분을 캡슐화하고 단순화하는 데 매우 중요합니다.

그러므로 중요한 것은 한 세계에서 다른 세계로 식별하고 전환 할 수있는 것입니다.

AnemicUser 또는 UserDAO 등과 같은 Anemic 모델의 이름을 지정하면 개발자가 더 나은 클래스를 사용할 수 있음을 알 수 있으며 none Anemic 클래스에 대한 적절한 생성자가 있습니다.

User(AnemicUser au)

전송 / 지속성을위한 빈혈 클래스를 만드는 어댑터 메서드

User::ToAnemicUser() 

이동 / 지속성이없는 모든 곳에서 빈혈 사용자가 없음을 목표로합니다.


-1

다음은 도움이 될 수있는 예입니다.

빈혈

class Box
{
    public int Height { get; set; }
    public int Width { get; set; }
}

빈혈 없음

class Box
{
    public int Height { get; private set; }
    public int Width { get; private set; }

    public Box(int height, int width)
    {
        if (height <= 0) {
            throw new ArgumentOutOfRangeException(nameof(height));
        }
        if (width <= 0) {
            throw new ArgumentOutOfRangeException(nameof(width));
        }
        Height = height;
        Width = width;
    }

    public int area()
    {
       return Height * Width;
    }
}

이것은 ValueObject 대 엔티티로 변환 될 수있는 것처럼 보입니다.
code5

설명없이 Wikipedia에서 복사 붙여 넣기
wst

누가 더 빨리 썼습니까? @wst
Alireza Rahmani Khalili

@AlirezaRahmaniKhalili 위키 백과 역사에 따르면, 그들은 처음이었습니다 ... 당신의 질문을 이해하지 못했다면.
wst

-1

DDD에 대한 고전적인 접근 방식은 어떤 대가를 치르더라도 Anemic vs Rich Models를 피하도록 명시하지 않습니다. 그러나 MDA는 모든 DDD 개념 (경계 컨텍스트, 컨텍스트 맵, 값 개체 등)을 계속 적용 할 수 있지만 모든 경우에 Anemic 대 Rich 모델을 사용합니다. 도메인 서비스를 사용하여 도메인 집합 전체에서 복잡한 도메인 사용 사례를 조율하는 경우가 많습니다. 이는 응용 프로그램 계층에서 호출되는 집합보다 훨씬 더 나은 접근 방식입니다. 기존 DDD 접근 방식과의 유일한 차이점은 모든 유효성 검사 및 비즈니스 규칙이있는 위치입니다. 모델 유효성 검사기로 알려진 새로운 구조가 있습니다. 유효성 검사기는 사용 사례 또는 도메인 워크 플로가 발생하기 전에 전체 입력 모델의 무결성을 보장합니다. 집계 루트 및 하위 항목은 빈약하지만 필요에 따라 각각 자체 모델 유효성 검사기를 호출 할 수 있습니다. 루트 유효성 검사기입니다. 유효성 검사기는 여전히 SRP를 준수하고 유지 관리가 쉽고 단위 테스트가 가능합니다.

이러한 변화의 이유는 이제 마이크로 서비스에 대한 UX 우선 접근 방식보다 API 우선 접근 방식으로 더 많이 이동하고 있기 때문입니다. REST는 여기에서 매우 중요한 역할을했습니다. 기존의 API 접근 방식 (SOAP으로 인한)은 처음에 명령 기반 API 대 HTTP 동사 (POST, PUT, PATCH, GET 및 DELETE)에 고정되었습니다. 명령 기반 API는 Rich Model 객체 지향 접근 방식과 잘 맞으며 여전히 매우 유효합니다. 그러나 단순한 CRUD 기반 API는 리치 모델에 맞을 수 있지만 나머지를 오케스트레이션하기 위해 단순한 빈혈 모델, 유효성 검사기 및 도메인 서비스에 훨씬 더 적합합니다.

나는 DDD가 제공하는 모든 것을 좋아하지만 끊임없이 변화하고 아키텍처에 대한 더 나은 접근 방식에 맞게 약간 확장해야 할 때가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.