동작하는 도메인 만들기

도메인(domain): 사용자가 사용하는 프로그램을 사용하는 영역 도메인 모델: 도메인 지식을 엄격하게 구성하고 선택적으로 추상화 하는 것

  • 도메인 주도 설계에서 모델의 유용성

    1. 모델과 핵심 설계는 서로 영향을 주며 구체화 된다. 모델을 의미 있게 만들고 모델의 분석이 최종 산출물인 동작하는 프로그램에 적용 되게끔 보장하는 것이 다름 아닌 모델과 구현간의 긴밀한 연결이다. 이러한 모델과 구현의 연결은 유지보수와 계속되는 기능 개선에도 도움이 되는데 그 이유는 바로 모델을 이해한 바에 근거해 코드를 해석할 수 있기 때문이다.
    2. 모델은 모든 팀 구성원이 사용하는 언어의 중추다. 모델과 구현이 서로 연결되 있으므로 개발자는 이 언어를 토대로 프로그램에 관해 의견을 나눌 수 있다. 그러므로 개발자와 도메인 전문가가 의샅소통하는데 별도의 번역 절차가 필요하지 않다.
    3. 모델은 지식의 정수만을 뽑아낸 것이다. 모델은 도메인 지식을 조직화 하고 가장 주요한 요소를 구분하는 팀의 합의된 방식이다. 모델에는 우리가 용어를 선택하고 개념을 분류하며 분류한 지식을 서로 연관시킬 때 도메인에 관한 우리의 사고방식이 담겨 있다. 개발자와 도메인 전문가는 공유 언어를 바탕으로 갖가지 정보를 모델로 만들어 낼때 효과적으로 협업 할 수 있다. 모델과 구현이 연결돼 있다면 초기 버전의 소프트웨어를 통해 얻은 경험을 모델링 프로세스에 피드백으로 활용할 수 있다.
  • 소프트웨어의 본질 소프트웨어의 본질은 해당 소프트웨어의 사용자를 위해 도메인에 관련된 문제를 해결하는 능력에 있다. 그 나머지는 부수적인 요소에 불과하다.

도메인 이란?

도메인의 사전적 의미는 “정보와 활동의 영역” 을 말하며 특정 소프트웨어로 소프트웨어로 해결 하고자 하는 문제 영역 이다.

도메인 모델

특정 도메인을 개념적으로 표현한 것으로 객체 기반 다이어그램 상태 기반 다이어그램 등의 다양한 방식으로 모델링이 가능하다. 도메인을 적합하게 표현한다면 어떤 표현 방식이라도 가능하다. 도메인 모델은 기본적으로 개념 모델이며 이것을 가지고 바로 코드를 작성하지 못한다. 각 개발 환경에 맞는 구현모델이 필요하며 구현 모델은 개념 모델을 최대한 따르 도록 한다.

도메인 모델 도출

도메인 모델은 기회서 유즈 케이스 사용자 스토리와 같은 요구사항과 관ㄹ녀자와의 대화를 통해 도메인을 이해하고 이를 바탕으로 도메인 모델의 초안을 도출 한다. 개인적으노는 도메인 모델 설계시에는 사용자의 도메인 요구사항을 한 문장으로 정의하여 제약 사항을 정의한다.

  • 최소 한 종류 이상의 상품을 주문해야 한다.
  • 한 상품을 한개 이상 주문할 수 있다.
  • 총 주문 급액은 각 상품 구매 가격의 합을 모두 더한 금액이다.
  • 각 상품의 구매 가격 합은 상품 가격에 구매 개수를 곱한 값이다.
  • 주문할 때 매송지 정보를 만드시 지정해야 한다.
  • 출고를 하면 배송지 정보를 벼녁ㅇ 할 수 없다.
  • 출고 전에는 주문을 취소 할수 있다.

이러한 제약사항을 가지고 각 모델의 관련 기능을 함수로 정의 할수 있다.

type Order interface {
    ChangeShipped() err
    ChangeShippingInfo(ShippingInfo info) err
    Cancel() err
}

Entity와 Value

도출한 모델은 크게 Entity 와 Value 로 구문할 수 있으며 요구 사항 분석 과정에서도 Entity 와 Value 를 구분하여 설계한다.

  • Entity

    고유 식별자를 가지는 모델로서 상태가 변경 되더라도 식별자는 변경되지 않는다. 엔티티의 식별자가 같으면 같은 엔티티로 판단한다. 엔티티의 식별자를 생성하는 시점은 도메인에 따라 다르며 생성 방식은 아래 4가지를 주로 사용한다. 용도에 따라서 적정하게 선택하여 사용하면 된다.

    • 특정 규칙에 따라 생성
    • UUID 사용
    • 값을 직접 입력
    • 일련 번호 사용 (시퀀스 또는 자동 증가값)
  • Value

    식별자를 가지지 않은 값 으로서 개념적인 완전한 하나의 값을 표현 불변 타입을 사용할경우 보다 안전한 코드 작성이 가능하다.(받는 사람 , 어드레스 ,전화번호) 밸류 타입은 일반적은 데이터 타입을 사용하기 보다는 도메인 데이터 타입을 사용자 정의 하여 사용하는것이 도메인 표현과 코드 가독성에 도움이 된다. 벨류 타입은 값을 변경하기 보다는 새로운 밸류를 생성하는 방식을 선호 하며 각 객체는 불변으로 유지 하는것이 안전한 코드에 도움이 된다.

도메인 용어

코드를 작성 할때는 도메인에서 사용하는 용어를 사용하느 것이 매우 중요하다. 도메인에서 사용하는 용어를 코드의 사용하지 않을 경우 개발자와 사용자의 커뮤니케이션이 잘못될 수 있다.

일반적인 도메인 주도 아키텍처 개요

  • 표현(Presentation) 사용자 인터페이스(UI): 사용자의 요청을 처리 하고 사용자에게 정보를 보여준다. 여기서 사용자는 소프트웨어를 사용하는 사람뿐만 아니라 외부 시스템도 사용자가 될 수 있다.
  • 응용(Application) : 사용자가 요청한 기능을 실행한다. 업무로직을 직접 구현하지 않으며 도메인 계층을 조합하여 기능을 실행한다.
  • 도메인(Domain) : 시스템이 제공할 도메인의 규칙을 구현한다. 비지니스 로직은 도메인 레이어에서 구현하낟.
  • 인프라스트럭처 (Infrastructure) : 데이터베이스나 메시징 시스템과 같은 외부 시스템과의 연동을 처리 한다.

어그리게잇 (aggregate)

  • 어그리거트는 관련된 모델이며 데이터 변경의 일관성을 가지는 모델의 묶음이다.
  • 어그리거트는 루트와 경계로 이루어 진다. 경계는 어그리거트에 무엇이 포함되지 않는지를 정의 한다.
  • 루트는 단 하나만 존재하며 어그리거트에 포함된 특정 엔티티를 가리키며 경계 안의 객체는 서로 참조할 수 있지만 경계 바깥의 객체는 해당 어그리거트의 루트만 참조할 수 있다.
  • 한 어그리거트에 속한 객체는 다른 어그리거트에 속하지 않는다.

어그리거트 루트

  • 루트객체는 어그리거트 전체 객체아 대한 일관성 유지의 책임을 가진다.
  • 어그리거트에 속한 객체는 직접또는 간접적으로 루트 객체에 속한다 .
  • 어그리거트는 일관성과 도메인 규칙을 유지하기 위해 멧서드의 공개 범위를 조정 하여 외부 어그리거트에서 접근하지 못하도록 해야 한다.
  • 루트객체는 어그리커드 내부의 하위 객체를 조합하여 기능을 완성한다.

리포지터리

응용 서비스

응용 서비스는 사용자가(클라이언트)가 요청한 기능을 실행한다. 응용 서비스는 도메인 영역과 표현영역을 연결해 주는 파사트(Facade)의 역할을 하며 도메인 객체 간의 흐름을 제어한다.

  • 응용 서비스에 도메인 로직을 넣지 말아야 하는 이유

    1. 코드의 응집성이 떨어진다. 코드를 이해햐기 위해 도메인 영역과 어플리케이션 영역을 중복해서 확인해야 한다.
    2. 응용 서비스에 동일한 도메인 로직을 구현할 가능성이 높아지고 코드 중복이 일어날 수 있다.
  • 응용 서비스의 구현

    • 응용 서비스의 크기

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

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

    • 메서드의 파람미터와 값 리턴

표현 영역

도메인 서비스

도메인 서비스는 한 애그리게이트에 넣기 애매한 도메인 개념을 구현하려면 애그리거트에 억지로 넣기 보다는 도메인 서비스를 이용해서 도메인 개념을 명시적으로 드러내는데 사용한다. 도메인 서비스는 상태를 가지지 않는것이 좋으며 도메인의 로직만을 구현한다. 부적절한 내용을 도메인 서비스에 구현할 경우 코드의 중복이 발행하는 문제가 발생한다. 도메인 서비스는 도메인 로직을 실행하므로 도메인 서비스의 위치는 다른 도메일 구성 요소와 동일한 패키지에 위치한다. 분리를 원하는 경우 도메인에 화위 팩키지를 두어 구분해서 위치 시켜도 좋다.

어그리게이트와 트랜젝션 관리