[도메인 주도 설계 핵심] 2장, 3장 요약

바운디드 컨텍스트 및 보편언어와 전략적 설계

DDD

- 바운디드 컨텍스트 내에서 보편 언어를 모델링하는 것에 대한 것

 

바운디드 컨텍스트

- 의미적으로 동일한 컨텍스트의 범위를 표현하는 것

- 해당 범주 내에서 SW 모델의 각 컴포넌트는 특정한 의미를 갖고, 특정한 일을 수행한다는 것

- 바운디드 컨텍스트 내의 컴포넌트는 컨텍스트에 특화되어 있고, 컨텍스트 안에서 의미가 살아난다.

 

문제 영역

- 상위 수준의 전략적 분석을 수행하고, 주어진 프로젝트 제약사항 내에서 단계를 설계하는 곳

 

해결 영역

- 문제 영역의 논의가 핵심 도메인으로 바라보는 해결 방안을 구현하는 곳

- 바운디드 컨텍스트를 조직의 핵심 전략 계획으로 개발하고 있을 때, 이를 핵심 도메인이라고 부른다.

 

핵심 도메인

- 가치 있는 것들을 달성하는 수단이자 다른 조직과의 경쟁에 대한 차별화를 위한 것


하나의 언어에 대해 각 사업 기능이 서로 다른 정의를 가질 수 있는 경우가 존재한다. 

예시) 정책 - 계약 심사 정책 / 청구 정책 / 검사 정책

 

이런 경우에 세 가지 정책을 모두 하나의 정책으로 통합하는 경우 문제가 발생한다. 

DDD를 통해 서로 다른 개념들을 각기 다른 바운디드 컨텍스트 안으로 분리해 놓음으로써 개념 간 차이를 더욱 중시할 수 있게 된다.

 

컨텍스트를 분리해 놓고, 각각의 특성을 포함한 정책을 갖도록 수정

각 정책의 이름은 3개의 모든 바운디드 컨텍스트 내에서 단순히 정책으로 표현할 수 있게 된다.

 


기본적인 전략적 설계를 하기 위해서는 2가지 기본적인 전략적 설계 도구가 있다

 

1. 바운디드 컨텍스트

이는 "핵심이 무엇인가"에 답하도록 유도한다. 전략적 계획의 핵심이 되는 모든 개념들을 밀접하게 유지하면서 포용해야 하고, 나머지는 모두 제외시켜야 한다.

 

2. 보편 언어 (유비쿼터스 언어)

바운디드 컨텍스트에 남은 개념들이 팀이 사용하는 보편언어의 일부가 된다.

 

엄격하게 핵심만 걸러낸 후 살아남은 개념들은 해당 바운디드 컨텍스트를 소유하는 팀의 보편언어 일부가 되고, 경계는 그 안의 "엄격함"을 강조한다.

 

DDD를 수행하는 개발자는 핵심 전략 목표의 비즈니스 초점을 받아들이지 못하는 기술 중심의 주장을 하지 않도록 조심해야 한다.


컨텍스트를 통해 구분되지 않고, 뒤엉킨 복잡한 모델들을 컨텍스트로 나누고, 보편 언어를 만드는 방법

 

가장 간단한 방법은 거대한 모델들의 각 개념이 스크럼의 보편언어를 따르고 있는지 되묻는 것.

 

개발할 소프트웨어: 스크럼 기반 애자일 프로젝트 관리 애플리케이션

 

<이전에 설계되었던 거대 모델>

 

<도전과 통합>

1. 테넌트, 사용자, 권한은 스크럼과 아무런 관련이 없다 ➡️ 소프트웨어 모델에서 제외

2. Team(팀), ProductOwner(제품 책임자), TeamMember(팀원)은 스크럼의 보편언어에 맞춰볼 때 어울린다. 

3. SupportPlans(지원 계획), Payment(지불)는 스크럼 프로젝트 관리의 일부가 아니다. ➡️ 모델에서 제외

4. 인적 자원 활용 문제에 대한 부분도 BacklogItemTasks를 진행할 팀자원자가 직접 사용하지 않으므로 컨텍스트 외부에 존재한다 ➡️ 모델에서 제외

5. TeamMember가 작업에 참여하는 핵심 개념을 놓쳤다. 스크럼에서 이를 Volunteer라고 하며, Volunteer를 핵심 모델 언어에 포함

4, 5번 진행 후

6. 일정 기반의 개념들인 Milestone(마일스톤)과 Retrospective(회고) 등은 컨텍스트 내에 존재하지만 이들에 대한 모델링 작업은 다음 스프린트에서 진행할 것이라고 가정 ➡️ 개념들은 컨텍스트 내에 존재하지만 현재 시점에는 범위 밖에 있음

7. 진행 중인 Discussion이 핵심 모델의 일부라는 점을 명확하게 표현하고 싶어한다. ➡️ Discussion을 모델 내에 포함시킴 (보편언어 중 일부이자 바운디드 컨텍스트 내에 위치한다는 뜻)

 

이처럼 모델 관련 여러가지 시도를 통해 깔끔하고 명확한 보편언어 모델이 만들어졌지만 스크럼 모델에서의 Discussion이라는 보편언어가 필요한 의미를 잘 표현하기 어려울 수 있다.

➡️ 여러 부수적인 소프트웨어 컴포넌트가 필요하며 때문에, Discussion을 스크럼의 바운디드 컨텍스트 안에 모델링하는 것은 적절하지 않은 것처럼 보일 수 있다. 

그러나 온전한 협업 소프트웨어는 컨텍스트 바깥에 존재할 수 밖에 없으며, Discussion은 다른 바운디드 컨텍스트와의 협업을 통해 보다 적절하게 동작할 것이며 이것이 협업 컨텍스트가 된다.

 

<만들어진 협업 컨텍스트>

협업 컨텍스트

이런 단계를 거치면 간결해진 핵심 도메인만 남게 되며, 핵심 도메인은 시간이 지남에 따라 확장된다. 

Planning, Retrospective, Milestone, 일정 기반 모델들이 추가될 수 있으며, 그 외의 도메인이 추가될 수 있다.
단, 스크럼의 보편언어에 따르는 새로운 개념들로만 확장되어야 한다.

 

<핵심 도메인 컨텍스트와 핵심 도메인에서 제외시켰던 다른 모델링 개념들을 포함한 컨텍스트들>

 

핵심 도메인에서 제외된 개념들 중 몇몇은 각각의 바운디드 컨텍스트 내에 정의될 가능성이 높고 각각의 보편언어에 연결된다. 

그리고 이들은 컨텍스트 매핑을 통해 통합시키게 된다.


보편 언어 개발하기

핵심 도메인을 명사에만 제한시킬 필요가 없다. 핵심 도메인이 도메인 모델에 나타난 개념에 대한 구체적인 시나리오들을 나타낼 수 있게 만들어야 한다. 

 

<스크럼의 보편언어에 맞는 시나리오 사례>

각 백로그 아이템을 스프린트에 할당한다. 백로그 아이템은 이미 릴리스에 예정되어 있는 경우에만 할당할 수 있다. 
만일, 이미 다른 스프린트에 할당되었다면 먼저 이를 해제시킨다. 할당이 완료되면 관련된 대상에게 알린다.

 

시나리오는 사람이 프로젝트에서 스크럼을 사용하는 방법만을 의미하는 것이 아닌, 매우 실제적인 소프트웨어 모델 컴포넌트들이 스크럼 기반 프로젝트 관리를 지원하기 위해 어떻게 동작할 것인지를 나타내는 세부사항이다.

 

앞의 시나리오에서 보편언어의 일부를 개선하려면 무엇을 해야할까?

누가 스프린트에 백로그 아이템을 할당하는지 궁금할 것이다. 

각 백로그 아이템을 스프린트에 할당한다. ➡️ 제품 책임자는 각 백로그 아이템을 스프린트에 할당한다.

 

시나리오 안의 각 대표적 역할마다 이름을 부여하고, 백로그 아이템, 스프린트 같은 개념들을 구분짓는 특성을 부여하는 것이 도움이 된다면 별도의 이름과 구분짓는 특성을 부여하자

제품 책임자는 각 백로그 아이템을 스프린트에 할당한다. ➡️ 제품 책임자 이사벨은 사용자 프로필 인도 스프린트에 사용자 프로필 조회 백로그 아이템을 할당한다.

 

제품 책임자가 개인적이고 독단적으로 스프린트에 할당할 백로그 아이템을 결정할 수는 없다. 제품 책임자에게 백로그 아이템의 할당을 허용하기 전에, 그 백로그 아이템을 작업할 건지에 대해 적어도 몇 팀의 합의가 있어야 하므로 다음과 같이 시나리오를 개선할 수 있다. 

제품 책임자 이사벨은 사용자 프로필 인도 스프린트에 사용자 프로필 조회 백로그 아이템을 할당한다.
➡️ 제품 책임자는 스프린트에 백로그 아이템을 할당한다. 백로그 아이템은 이미 릴리스에 예정되어 있고, 팀원의 정족수가 작업을 승인한 경우에 한해 할당한다.

 

여기에서 "정족수"라는 새로운 모델 개념이 등장했고, 정제된 보편 언어에 추가되었다. 

 

또한, 모델에서 놓친 또 다른 것이 존재한다.

"관련된 대상"이 누구인지이다. 이러한 질문은 모델링 통찰로 이어질 수 있다. 중요한 모델 요소는 스프린트 자체이며, 시나리오에서 스프린트는 전체 스프린트 할당 및 스프린트의 모든 작업을 인도하기 위해 필요한 노력을 추적해야 한다는 것이다.

즉, 중요한 점은 백로그 아이템이 스프린트에 할당되면 이를 알려야 한다는 것이지, 누구한테 알려야 한다는 것은 중요하지 않다.

 

만일, 이미 다른 스프린트에 할당되었다면 먼저 이를 해제시킨다. 할당이 완료되면 관련된 대상에게 알린다.
➡️ 만일, 이미 다른 스프린트에 할당되었다면 먼저 이를 해제한다. 할당이 완료되면 할당이 어디서 해제되었고, 현재 어디에 할당되어 있는지 알린다.

 

정제된 전체 시나리오는 다음과 같습니다.

제품 책임자는 스프린트에 백로그 아이템을 할당한다. 백로그 아이템은 이미 릴리스에 예정되어 있고, 팀원의 정족수가 작업을 승인한 경우에 한해 할당한다. 만일, 이미 다른 스프린트에 할당되었다면 먼저 이를 해제시킨다. 할당이 완료되면, 할당이 어디서 해제되었고, 현재 어디에 할당되어 있는지 알린다.

 


작업에 시나리오 넣기

"사례를 통한 명세"를 사용하여 작성된 시나리오를 팀의 명세서와 비교해 도메인 모델을 검증하는데 사용할 산출물로 전환할 수 있다. 이는 BDD(행위 주도 개발)이라고도 불린다.

 

공유된 이해를 기반으로 보편언어와 모델을 협업을 통해 개발, 정제하고 모델이 명세서를 준수하고 있는지를 확인할 수 있으며, 인수 테스트를 통해 이를 수행할 수 있다.

 

<앞의 시나리오를 실행가능한 명세로 바꾸기>

시나리오: 제품 책임자는 스프린트에 백로그 아이템을 할당한다.
Given: 릴리즈 일정에 계획된 백로그 아이템,
해당 백로그 아이템의 제품 책임자,
할당할 스프린트,
작업 승인을 위한 팀 정족수가 주어지고
When: 제품 책임자가 스프린트에 백로그 아이템을 할당하면
Then: 백로그 아이템이 스프린트에 할당되고,
백로그 아이템 할당 이벤트가 생성된다.

 

이런 형식으로 작성된 시나리오를 만들고, 명세를 실행해볼 수 있는 도구를 활용해서 이들 시나리오를 뒷받침하는 코드를 만들어볼 수 있다.


아키텍처

바운디드 컨텍스트가 도메인 모델 이상의 다양한 요소들로 구성되는 것을 확인할 수 있으며, 이러한 레이어들은 거의 모든 바운디드 컨텍스트 내에 존재한다.

 

- 인풋 어댑터: 사용자 인터페이스 컨트롤러, REST 엔드포인트, 메시지 리스너

- 애플리케이션 서비스: 유스케이스를 조율하고, 트랜잭션을 관리

- 도메인 모델: 핵심 

- 아웃풋 어댑터: 영속성 관리, 메시지 발송기

 

기술은 아키텍처 전반에 걸쳐 산재해있지만, 도메인 모델은 기술로부터 최대한 자유로워야 한다. 

예를 들면 트랜잭션은 애플리케이션 서비스에 의해 관리되는 것이지, 도메인 모델에 의해 관리되는 것은 아니다.

 


서브 도메인과 전략적 설계

DDD 프로젝트 내부에는 다수의 바운디드 컨텍스트가 존재한다.이 컨텍스트들 중 하나는 핵심 도메인이 되며, 다른 바운디드 컨텍스트에는 다양한 서브 도메인이 존재하게 된다. 

일반적으로 하나의 바운디드 컨텍스트 안에 하나의 서브 도메인이 포함되며, 만약 다수의 서브 도메인이 포함되었다면 최적의 모델을 구성했다고 보기엔 어렵다.

 

서브 도메인이란 무엇인가

서브 도메인전체 비즈니스 도메인의 하위 부분이며 하나의 논리적 도메인 모델이다. 

거대하고 복잡한 프로젝트에서 문제 영역을 이해할 수 있도록 전체 비즈니스 도메인을 논리적으로 쪼개기 위해 사용된다.

서브 도메인을 개발하는 데 DDD를 사용했다면 명확한 바운디드 컨텍스트를 구현할 수 있다.


서브 도메인의 유형

3가지 주요 서브 도메인 유형

1. 핵심 도메인

2. 지원 서브 도메인

3. 일반 서브 도메인

 

<핵심 도메인>

보편 언어를 신중하게 만들기 위한 전략적 투자 영역. 주요 자원을 할당하는 명시적인 바운디드 컨텍스트이며, 잘 정의된 도메인 모델이 존재한다. 이 도메인은 다른 경쟁자들에 대한 차별화를 만들 영역이므로 높은 우선순위를 갖는다.

 

<지원 서브 도메인>

이미 존재하는 제품으로는 해결할 수 없는 맞춤 제작 개발이 필요한 모델링 영역. 핵심 도메인에서와 같은 투자 방식을 동일하게 따를 필요는 없다. 지원 형태의 바운디드 컨텍스트에 많은 투자를 하지 않기 위해 아웃소싱을 고려해볼 수도 있다. 그러나 지원 서브 도메인 없이 핵심 도메인을 성공시킬 수 없기 때문에 중요한 소프트웨어 모델이다.

 

<일반 서브 도메인>

기존 제품 구매를 통해 바로 충족시킬 수 있는 경우에 해당하며, 아웃소싱을 할 수도 있고 핵심 도메인 또는 좀 더 작은 지원 서브 도메인에 할당된 팀에서 직접 개발할 수도 있다. 일반 서브 도메인을 핵심 도메인으로 오해하지 않도록 주의해야 한다.


복잡성 다루기

비즈니스 도메인 안의 시스템 경계 중 일부는 레거시 시스템일 가능성이 높다.

레거시 시스템을 개선하는 작업들을 많이 진행하기 어려울 수도 있지만 여전히 그 시스템들이 핵심 도메인 프로젝트에 어떤 영향을 주고 있는지는 명확히 해야한다. 이런 경우, 문제 영역에 대해 논의하기 위한 도구로 서브도메인을 사용한다. 

 

레거시 시스템

 

레거시 시스템을 논할 때, 그 안에 몇 개의 논리적 도메인 모델이 존재한다면 이것을 서브 도메인으로 생각해볼 수 있다. 앞의 레거시 시스템 안에 존재할 수 있는 논리적 서브도메인을 점선으로 나타내보면 다음과 같다. 

 

서브 도메인을 활용하면 작업 중이거나 관련있는 핵심 도메인을 하나의 간단한 다이어그램 안에 표현해볼 수 있다. 

이 다이어그램을 통해 서브 도메인간 관련성과 의존성을 이해하는데 도움을 줄 수 있다. 

DDD를 사용할 때, 바운디드 컨텍스토와 서브 도메인은 1:1 관계를 맺어야 한다.

즉, 하나의 바운디드 컨텍스트 안에 오직 1개의 서브 도메인을 두는 것을 목표로 하는 것이 좋다. 이는 바운디드 컨텍스트를 정확하게 유지시키고 핵심 전략 목표에 집중하는데 도움을 주기 때문이다. 

 

만약 핵심 도메인 안에 존재하는 동일한 바운디드 컨텍스트 안에 다른 모델을 만들어야 하는 경우, 핵심 도메인으로부터 완전히 분리된 모듈(IDDD) 형태로 그 모델을 별도의 영역에 정의해야 한다. 이것은 하나의 모델이 핵심을 이루고 다른 모델들은 지원하는 역할이라는 구성을 정확하게 나타낸다. 

즉, 핵심 도메인과 지원 서브 도메인을 2개의 서로 다운디드 컨텍스트로 분리하는 것이 현실적이지 않은 경우 DDD 모듈로 그것을 분리할 수 있다.