CS

도메인 주도 설계하기

ri5 2023. 4. 22. 18:01

도메인 주도 설계하기

도메인 주도 개발을 진행할 때 가장 먼저 진행해야되는 것은 도메인 모델바운디드 컨테스트를 정의하는 것이이다. 만약 개발 먼저 진행했을 때의 문제점을 아래와 같은 문제점이 발생할 수 있다. 아래와 같은 문제점을 발생하지 않기 위해서는 개발을 먼저 진행하기 전에 도메인 전문가와 함께 설계를 같이 진행해야 한다.

  1. 도메인 이해 부족: DDD 모두가 같은 수준의 도메인 지식을 가지는 것을 추구하고 통일된 유비쿼터스 언어를 사용하여 소통하는 것을 지향한다. 개발을 먼저 시작하면 같이 일하는 팀원 모두가 도메인에 대한 충분한 이해가 부족할 수 있다.
  2. 유지보수성 감소: 팀원 모두가 각각 다른 도메인 모델을 개발하면서 서로 간의 간극이 커지고 코드의 유지보수성이 감소하게 된다. 이는 시간이 지남에 따라 프로젝트의 비용과 복잡성을 증가시킬 있습니다.
  3. 협업 어려움: 도메인 주도 설계는 도메인 전문가와 개발자들이 협력하여 도메인의 복잡성을 이해하고 코드에 반영하는 것을 목표로 한다. 개발을 먼저 진행하게 되면, 도메인 전문가와 개발자 간의 소통이 어려워 질 수 있다.
  4. 일정 산정의 어려움: 개발자의 경험으로 일정을 산정할 수도 있지만 도메인을 설계를 먼저 진행하고 각각 도메인에 대한 기능을 먼저 정의하게 된다면 일정 산정의 충분한 근거가 될 수 있습니다.
  5. 유연성 감소실제로 개발에 임하면서 요구사항와 정책은 수시로 바뀌게 될 수 있습니다. 그때마다 요구사항 변경이나 새로운 기능 추가에 대한 대응하게 된다면 점점 복잡해지는 코드 구조를 가져갈 가능성이 높습니다.

도메인 요구 사항

요구사항은 스터디원분이 정의해주신 요구사항에 따라 개발을 진행하기로 했다. 오브젝트에 많이 나오는 영화 예매시스템을 참조하여 요구사항을 정의하였고 먼저 각각 요구사항을 충족하도록 도메인을 설계하고 스터디원이 모두 공유하면서 보충하는 형식으로 진행하기로 하였다. 

 

도메인 모델과 바운디드 컨텍스트 정의

도메인 모델이란? 

소프트웨어 공학에서 도메인 모델은 행위와 데이터를 둘 다 아우르는 도메인의 개념 모델이다.

도메인 모델은 간단하게 설명하자면 광범위한 도메인에서 문제를 해결하고자 하는 최소 범위가 도메인 모델이라고 정의할 수 있을 것이다. 예시로 들자면 쇼핑몰을 만든다고 한다면 상품 주문, 상품 검색, 상품 배송, 로그인, 장바구니 등의 많은 문제를 풀어야한다. 그리고 각각의 기능에 대해서는 각자 다른 정책과 요구사항을 가지고 있기 때문에 개발하면 할수록 소프트웨어에 복잡성이 높아진다. 그렇기 때문에 문제를 비슷한 문제들은 그룹화하여 도메인 모델이라는 추상적인 개념으로 표현하여 복잡성을 낮춘다.

 

바운디드 컨텍스트란?

도메인 모델은 소프트웨어 구조를 정의하는데 최소 범위이기때문에 문제를 해결하는 영역마다 다르게 해석될 여지가 있다. 예시로 각각의 팀에서 상품 추천, 상품 검색, 물류 등을 관리한는 개발팀들이 있다고 가정했을 때 각각의 팀이 상품이라는 도메인을 추천 상품이라고 사용할 수 있고 검색 상품이라고 사용할 수도 있으며 재고 상품이라고 사용될 수도 있다. 이처럼 도메인 모델만 정의했을 때의 애매모호함을 확실히 하기위해 경계를 정하여 바운디드 컨텍스트를 정의한다. 자세한 내용은 아래 링크를 참조 바란다.

https://martinfowler.com/bliki/BoundedContext.html

 

영화 예매 시스템 설계

일단 시스템이 복잡하지 않기 때문에 도메인 모델 == 바운디드 컨텍스트의 구조가 되었다. 영화 예매 시스템에서 영화, 상영, 예매, 결제, 할인이라는 도메인 모델을 정의하였다. 각각의 도메인 모델에서 어떤 행위를 할지 정의함으로써 해당 도메인이 어떤 범위까지 문제를 해결하는지 명확히 하였다. 여기서 할인 모델만이 모델 하위에 도메인 모델이 있는 것을 볼 수 있는데 이와 같은 형태의 도메인 모델을 애그리거트라고한다.


애그리거트의 사용: 문제를 해결하고자 하는 범위는 같지만 모델을 좀 더 단순화시키거나 복잡성을 낮추기 위해 분리시킬때 사용한다.

유비쿼터스 언어(보편 언어) 정의

유비쿼터스 언어란?

Ubiquitous Language is the term Eric Evans uses in Domain Driven Design for the practice of building up a common, rigorous language between developers and users.

도메인 주도 개발에서는 사용자와 개발자가 보편적으로 사용할 용어(유비쿼터스 언어)를 사용하여 도메인 모델을 설계하는 것을 권장한다. 그 이유는 불필요한 커뮤니케이션 비용을 줄이고 기획, 디자인, 개발, 테스트하는 과정에서 모두 같은 용어로 사용하면서 도메인의 구조를 쉽게 이해하는데에도 큰 도움을 준다.

영화 예매 시스템의 유비쿼터스 언어

도메인 모델까지 정의하였지만 유비쿼터스 언어까지는 저장하지 않았다. 유비쿼터스 언어를 정의하면서 각각 도메인 모델의 어떤 상태값을 가지게 하고 행동을 통해 어떤 상호작용을 하게 할 것인지 대략적으로 생각해볼 수 있는 시간이였다. 

 

참조: https://martinfowler.com/bliki/UbiquitousLanguage.html

영화   결제   상영  
등록 영화 이름 결제 결제 금액 등록 상영 시작 시간
변경 가격 환불 환불 금액 조회 상영 종료 시간
  상영 시간   결제 상태 변경 영화 아이디
      금융사   티켓수
      결제일자    
      환불일자    
예매   할인   할인 조건   할인 정책  
예매 하기 예매 유저 할인 등록 할인 영화 순서 조건 순서값 금액 할인 할인 금액 
예매 조회 예매한 상영시간 할인 적용 할인 조건 기간 조건 순서 적용 날짜 비율 할인 할인 비율
예매 취소 예매 날짜    할인 정책   기간 조건 시작일   할인 아이디
  예매 상태   할인 상태   기간 조건 종료일    
      적용일   할인 아이디    
      할인된 금액        
               

영화(Movie)

  • 등록: register
  • 변경: update
  • 영화 이름: movieName
  • 가격: price
  • 상영 시간: screenTime

결제(Payment)

  • 결제: pay
  • 환불: refund
  • 결제 금액: paidAmount
  • 환불 금액: refundedAmount
  • 결제상태: paymentStatus
  • 금융사: financialCompany
  • 결제 날짜: paidAt
  • 환불 날짜: refundedAt

상영(Screen)

  • 등록: regist
  • 변경: update
  • 조회: 보류(특정 요구사항에 맞춰야 하기 때문에 보류)
  • 상영시작시간: startedAt
  • 상영종료시간: endedAt
  • 티켓수: tickets

예매(Ticketing)

  • 예매하기: reserve
  • 예매취소: cancel
  • 예매일: reservedAt
  • 예매상태: TicketingStatus

할인(Discount)

  • 등록: regist
  • 적용: apply
  • 할인 영화: movieId
  • 할인 조건: discountCondition
  • 할인 정책: discountPolicy
  • 할인 상태: discountStatus
  • 적용일: appliedAt
  • 할인된 금액: discountedAmount

할인 조건(discountCondition)

  • 순서 조건: orderDiscountCondition
  • 날짜 조건: periodDiscountCondition
  • 순서값: orderConditionNumber
  • 순서날짜: orderConditionDate
  • 기간조건 시작날짜: discountConditionStartedAt
  • 기간조건 종료날짜: discountConditionEndedAt
  • 할인 아이디: discountId

할인 정책(discountPolicy)

  • 금액할인: amountDiscount
  • 비율할인: percentDiscount
  • 할인금액: discountedAmount
  • 할인비율: discountedPercent
  • 할인아이디: discountId

 

도메인 별 요구사항 정리

도메인 모델과 바운디드 컨텍스트를 정의하고 유비쿼터스 언어를 정했다. 이제 바로 개발을 들어가도 상관 없지만 도메인의 행동에 대해서 어떤 요구사항을 충족해야되는지 추가적으로 정리하게 되면 테스트를 작성할 때 어떤 테스트를 통과해야되고 미처 생각하지 못했던 정책에 대해서 생각할 수 있다는 장점이 있으니 개발을 들어가기전에 도메인의 행동에 대한 요구사항을 정리하는 시간을 가져보는 것을 추천한다.

영화(Movie)

  • 등록 
    • 영화이름, 가격, 상영시간을 필수적으로 정보를 받습니다.
    • 가격은 마이너스 값이 들어갈 수 없습니다.
    • 상영시간이 0초일 수는 없습니다.

상영(Screen)

  • 등록
    • 상영 영화, 상영 시작 시간,  상영 종료 시간, 티켓수는 필수로 입력받습니다.
    • 등록시 할인 조건을 선택적으로 적용할 수 있습니다.
    • 동일한 시간대에 두개의 영화가 상영될 수 없습니다.
    • 상영 종료 시간은 상영시작시간에 영화상영시간을 더한 시간 입니다.
    • 상영 시작 시간은 등록 시간 하루 전 등록해야 됩니다.
    • 상영 시작 시간은 이전 상영 영화보다 이후 최소 10분 후에 상영되어야합니다.

예매(Ticketing)

  • 예매
    • 현재 시각 이후로 상영되는 영화만을 예매할 수 있습니다.
    • 예매한 시간과 상영 시간이 일치하지 않으면 예매를 하지 못합니다.
  • 예매 취소
    • 상영 시작전 영화만 예매를 취소할 수 있습니다.
    • 환불된 금액은 지불한 금액 그대로 환불합니다.

할인(Discout)

  • 할인의 조건은 순서 조건 하나만 할인으로 선택할 수 있다.
  • 할인 정책은 하나의 조건만 선택할 수 있다.
  • 상영이 시작안된 영화만 할인이 적용 가능합니다.
  • 할인은 선택적으로 적용할 수 있습니다.

할인 조건(discountCodition)

  • 순서 할인을 적용할 날짜와 순서를 선택하여 할인을 적용합니다.

할인 정책(discountPolicy)

  • 하나의 할인 정책만 적용 가능합니다.
  • 비율 할인으로 소수점인 값이 있다면 반올림하여 할인합니다.
  • 금액 할인은 예매 금액보다 큰 금액을 할인 할 수 없습니다.
  • 금액할인과 비율할인은 1이상의 값이여야 합니다.

스터디 후기

이번에 스터디를 진행하면서 어려웠던 부분은 변경이나 삭제라는 기능이 연관된 다른 도메인에 대해 영향을 줄 수 있다는 것을 도메인 설계를 하면서 발견해낼 수 있었고 이로 생기는 복잡해지는 요구사항을 줄이고 난이도를 낮추기 위해 이번에는 빼고 진행하기로 했다. 해당 스터디를 진행하면서 스터디원분들이 도메인 설계를 해놓고 서로 어려웠었던 내용에 대해 공유하면서 피드백을 주고받는 시간을 가질 수 있었고 아래와 같은 내용을 다시 되새길 수 있었다.

  • 엔티티와 벨류의 차이는 엔티티는 고유한 식별자를 가지고  도메인과 행동과 상태를 표현한다. 벨류는 도메인의 연산을 대신 해주는 역활을 할 수 있지만 도메인처럼 상태와 역활을 가지지 못한다.
  • 엔티티 내부의 들어가는 상태들을 다른 도메인에 의존하지 않도록 최소화하자.
  • 바텀업이 방식이 아니라 탑다운 방식으로 개발해보자, 쿼리를 먼저 작성하여 인프라 계층부터 개발하다보면 도메인 로직이 인프라 스트럭처 계층과 긴밀하게 의존하고 있는 구조로 될 수 있다. 통합 테스트를 먼저 작성해보고 프레젠테이션 계층부터 설계해보자