1장: 도메인 모델 시작하기

도메인이란?

  • 개발자 입장에서 바라보는 구현해야 할 소프트웨어의 대상을 도메인이라고 한다.

  • 한 도메인은 여러 하위 도메인으로 나눌 수 있다.

  • 보통 일부 기능은 자체 시스템으로 구현하고 일부 기능은 외부 업체의 시스템을 사용한다.

도메인 전문가와 개발자 간 지식 공유

  • 개발자는 요구사항을 분석하고 설계하여 코드를 작성하며 테스트하고 배포한다. 여기서 첫 단추인 요구사항을 잘못 이해하면 잘못된 시스템을 만들게 되므로 주의해야 한다.

  • 개발자와 도메인 전문가가 직접 대화하는 것이 정보의 왜곡과 손실을 막을 수 있는 가장 좋은 방법이다.

  • 개발자는 요구사항을 이해할 때 왜 이런 기능을 요구하는지 또는 실제로 원하는 게 무엇인지 생각하고 전문가와 대화를 통해 진짜로 원하는 것을 찾아야 한다.

도메인 모델

  • 특정 도메인을 개념적으로 표현하여 도메인 자체에 대한 이해를 위한 개념 모델이다.

  • 구현 시에는 구현 기술에 맞는 구현 모델이 따로 필요하다.

  • 도메인 모델을 사용하면 여러 관계자들이 동일한 모습으로 도메인을 이해하고 도메인 지식을 공유하는 데 도움이 된다.

  • 처음부터 완벽한 개념 모델을 만들기보다는 전반적인 개요를 알 수 있는 수준으로 개념 모델을 작성해야 한다.

  • 프로젝트 초기에는 개요 수준의 개념 모델로 도메인에 대한 전체 윤곽을 이해하는 데 집중하고, 구현하는 과정에서 개념 모델을 구현 모델로 점진적으로 발전시켜 나가야 한다.

  • 모델링 방법으로는 객체 모델, 상태 다이어그램 모델 등 다양한 방법이 있다.

  • 모델의 각 구성요소는 특정 도메인으로 한정할 때 비로소 의미가 완전해지기 때문에 각 하위 도메인마다 별도로 모델을 만들어야 한다. 예를 들어 카탈로그와 배송 도메인 모델에서 ‘상품’의 의미가 다르게 사용되므로 카탈로그 하위 도메인과 배송 하위 도메인 모델을 따로 두어야 한다.

도메인 모델 패턴

  • 아키텍처 상의 도메인 계층을 객체 지향 기법으로 구현하는 패턴

  • 도메인 계층은 도메인 핵심 규칙을 구현한다. 예를 들어 주문 도메인에서 출고 전에만 배송지를 변경할 수 있다는 규칙이 있다면 이에 대한 구현 코드가 도메인 계층에 위치하게 된다.

  • 핵심 규칙을 구현한 코드는 도메인 모델에만 위치하기 때문에 규칙이 바뀌거나 규칙을 확장해야 할 때 다른 코드에 영향을 덜 주고 변경 내역을 모델에 반영할 수 있게 된다.

도메인 모델 도출

  • 도메인 모델링 시 기본이 되는 작업은 모델을 구성하는 핵심 구성요소, 규칙, 기능을 찾는 것이다.

  • 요구사항을 보며 어떠한 객체가 필요한지 찾아내는 과정을 거쳐 도메인 모델이 완성된다.

엔티티와 밸류

  • 엔티티

    • 각 엔티티 객체마다 고유한 식별자를 가진다. 예를 들어 주문 도메인에서 각 주문은 각각 다른 주문 번호를 가진다.

    • 엔티티의 식별자는 엔티티를 생성한 후 속성을 바꾸고 삭제할 때까지 바뀌지 않는다.

    • 엔티티의 식별자 생성 방식은 도메인의 특징과 사용하는 기술에 따라 달라진다. 특정 도메인의 규칙에 따라 생성하거나, UUID나 nano ID 등 고유 식별자 생성기를 사용하거나, DB의 자동 증가 컬럼을 사용하는 등 다양하다.

  • 밸류 타입

    • 개념적으로 완전한 하나의 데이터를 표현할 때 사용한다.

    • 예를 들어 주소라는 개념이 있다면 주소에 들어가는 데이터들을 하나의 Address 클래스로 래핑하는 것을 의미한다.

    • 밸류 타입이 꼭 두 개 이상의 데이터를 가져야 하는 것은 아니다. 의미를 명확하게 표현하기 위해 밸류 타입을 사용하는 경우도 있다.

    • 밸류 타입의 내부에는 기능을 추가할 수 있다.

    • 밸류 객체의 데이터를 변경할 때는 기존 데이터를 변경하기보다는 변경한 데이터를 갖는 새로운 밸류 객체를 생성하여 불변 객체를 사용하도록 한다. 이를 통해 코드의 안전성을 제공한다.

    • 엔티티 식별자를 위한 밸류 타입을 사용해서 의미가 잘 드러나도록 할 수 있다. 예를 들어 주문번호를 표현하기 위해 Order의 식별자 타입으로 String 대신 OrderNo 밸류 타입을 사용하면 타입을 통해 해당 필드가 주문번호라는 것을 알 수 있다.

    • setter 메서드를 사용하는 경우 도메인의 핵심 개념이나 의도를 코드에서 사라지게 한다. 예를 들어 setOrderState() 메서드는 의미를 갖지 않고 단순히 주문 상태를 설정하는 용도로 사용된다. 이를 completePayment()와 같이 상태 변경과 관련된 도메인 지식을 코드로 구현하는 것이 자연스럽다.

    • setter 메서드를 이용해 도메인 객체에 필요한 데이터를 주입하는 것보다 생성자에 주입하는 것이 불완전한 상태로 사용되는 것을 막을 수 있다.

    • 최근 개발 프레임워크나 개발 도구는 setter 메서드가 없어도 private 필드에 값을 지정할 수 있는 기능을 제공하기도 하므로 이를 최대한 활용한다면 불변의 장점을 누릴 수 있다.

  • 아래에서 Order, OrderLine 같은 객체를 엔티티라고 하고, Money, ShippingInfo 같은 객체를 밸류라고 한다.

도메인 용어와 유비쿼터스 언어

  • 도메인에서 사용하는 용어를 코드에 반영하지 않으면, 그 코드는 개발자에게 코드의 의미를 해석해야 하는 부담을 준다.

  • 최악의 경우 개발자가 아래와 같이 코드를 만들면 도메인 규칙이 드러나지 않기 때문에 의미 이해가 어려워진다.

public OrderState {
	STEP1, STEP2, STEP3, STEP4, STEP5, STEP6
}
  • 전문가, 관계자, 개발자가 도메인과 관련된 공통의 언어인 유비쿼터스 언어를 만들고 이를 대화, 문서, 도메인 모델, 코드, 테스트 등 모든 곳에서 같은 용어를 사용하여 소통 과정에서 발생하는 용어의 모호함을 줄일 수 있다.

  • 도메인에 어울리지 않은 단어를 사용하면 코드는 도메인과 점점 멀어지게 되므로, 어울리는 단어를 찾기 위한 시간을 들여야 한다.

Last updated