처음 DDD 를 공부할 때 알아두면 좋을 내용들

TL;DR

DDD 공부할때 추천하는 책들은 아래와 같다. (읽는 순서순)

한번도 DDD 를 경험해보지 못했다면, 파란책은 이해하기 가장 어렵다.

  1. 반 버논의 도메인 주도 설계 핵심
  2. 알베르토의 이벤트 스토밍
  3. 해리&밥의 파이썬으로 살펴보는 아키텍쳐 패턴1
  4. 반 버논의 빨간책(IDDD)
  5. 에릭 에반스의 파란책(DDD)

이벤트 스토밍만 빼고는 다 한글이고, 이벤트 스토밍은 엄청 간단하니깐 책보다 관련된 영상이나 글2들을 추천한다.

시작하며

나는 Domain Driven Design(DDD)를 아래와 같이 이해했다.

비즈니스 도메인 지식을 코드에 잘 반영하도록 도와주는 방법론이다.

처음 DDD 를 들은 것은 오래되었지만, 제대로(?) 공부한 것은 몇달전 이벤트스토밍을 써보고 나서이다.

이 단순한 이해를 위해서 몇달간 몇권의 책을 읽고 펫 프로젝트를 이용해서 DDD 실습을 해봤다. 아직 DDD 를 완전히 이해하지 못한것 같은 찜찜함은 있지만 (애자일 처음 공부했을때처럼), 다른 개발자들과 DDD 에 대해 기본적인 이야기를 해 볼 수 있는 정도까지는 이해한 것 같다.

이 글에서는 DDD 를 처음 공부하면서 개인적으로 이해가 잘 안되었던 내용들 몇개를 간단히 설명을 해본다.

보편언어와 바운디드 컨텍스트

개인적으로 DDD 초보자에게 가장 중요한 개념을 꼽으라면 보편언어라고 하겠다.

DDD 의 핵심 아이디어들을 이해하는데 가장 중요한 렌즈 역할을 하는것이 보편언어이기 때문이다.

DDD 이름에 도메인이 있는데? 도메인이 아니라고? 할 수도 있지만, DDD 의 각 컴포넌트들의 존재이유를 보편언어를 기반으로 생각하면 이해가 잘 되기 때문에 보편언어라고 생각한다.

보편언어(Ubiquitous Language)

보편언어는 정해진 범위(Bounded Context) 내에서만 제 의미를 가지는 사전이라고 생각할 수 있다.

보편언어에 대한 가장 쉬운 메타포어는 우리가 쓰는 언어일 것이다.

한국어는 한국이라는 범위내에서 사용할 때 가장 소통하기가 편하다.

한국어라는 보편언어를 독일에서 사용하면 소통이 원활해지지 않고, 특정 한국어 단어가 독일어로 존재하는데 의미는 서로 다르다면 화자와 청자가 다른 이해를 가지게 된다.

바운디드 컨텍스트

우리는 다른 사람(특히 다른 팀)과 논의 중에 다른 객체를 동일한 이름으로 부르거나(동음이의), 동일한 객체를 다르게 부르는 것을 자주 본다.

예로,

어떤 앱 회사가 있다.

앱이 시작하면 작게 이벤트가 뜨는 광고를 개발팀에서는 전면배너(FrontBannerAd) 라고 부르고 있다, (그리고 이 단어는 아마도 소스코드의 변수명과 밀접한 연관이 있을 것이다)

개발자하나가 마케팅팀과 이야기중 마케팅팀에서는 이것을 팝업광고 라고 부르고 있다는 사실을 알았다.

하지만 팝업광고는 의미가 너무 불분명하다는 이유로, 팝업하는 형태의 모든 광고를 나타내므로, 전면광고라고 부르기로 마케팅팀과 합의를 했다.

그런데 얼마 뒤 다른 사업제휴팀과 이야기해보니 전면배너를 팝업광고라고 부르고 있다는 사실과, 전면배너라고 부르는 팀은 개발팀 뿐이라는 사실을 알았다.

그 이유를 알아보니 전면배너는 앱에서 팝업형태로 뜨는 유일한 광고이고 주요 광고주가 항상 이 기능을 팝업광고라고 부르고 있기 때문에 광고주와 관련된 부서는 전부 팝업광고라고 소통하고 있었기 때문이었다.

(그리고 좀 더 엄밀히 말하면 저 광고는 배너형태의 광고도 아니다)

이 예제에서 보편언어는 전면배너와 팝업광고 이며, 바운디드 컨텍스트는 개발팀, 마케팅팀 그리고 사업제휴팀 이다.

전면배너와 팝업광고 라는 단어는 각 팀에서 서로 다른 의미로 해석되며, 팀간 소통을 할때는 적절한 번역이 필요할 수도 있다.

다시말해, 바운디드 컨텍스트는 보편언어가 명확히 소통될 수 있는 범위 를 나타낸다고 할 수 있다.

서브도메인과 바운디드 컨텍스트의 차이

위에서 DDD 를 비즈니스 도메인 지식을 코드에 잘 반영하도록 도와주는 방법론이다. 라고 정의했다.

DDD 에서 비즈니스 도메인 지식이 잘 반영된 코드 를 다르게 말하면 보편언어로 표현된 핵심 비즈니스 로직의 집합 이라고 부를 수 있고, 이것을 도메인 모델이라고 부른다.

그런데 보편언어는 각 바운디드 컨텍스트 안에서만 명확한 의미를 가진다.

위의 내용을 종합하면 보편언어로 표현된 도메인 모델도 바운디드 컨텍스트 안에서만 명확하게 설명된다고 할 수 있다.

이렇게만 보면 바운디드 컨텍스트와 도메인 모델로도 DDD 의 핵심개념들이 다 설명될 수 있는 것처럼 보인다.

실제로 이상적인 DDD 에서는 바운디드 컨텍스트 하나당 도메인 모델이 하나, 즉, 1:1로 매핑된다. 각 도메인 모델은 서로 간섭하지 않고 바운디드 컨텍스트 안에서 완전히 설명된다.

하지만, 처음부터 도메인 모델을 고려하지 않은 레거시 서비스는 도메인 모델과 바운디드 컨텍스트(보편언어) 가 1:1로 매핑되지 않는 경우가 많다.

이러한 현실세계의 모호함 때문에, 바운디드 컨텍스트 경계를 넘나들면서 보편언어로 표현된 비즈니스 로직을 설명할 수 있는 서브도메인이라는 구분방법이 등장했다고 볼 수 있다.

즉, 비즈니스 로직의 책임은 서브도메인으로 경계를 나타내고, 보편언어로 설명 범위는 바운디드 컨텍스트로 경계를 나타낸다.

컨텍스트 매핑

바운디드 컨텍스트가 단지 보편언어가 정확히 설명될 수 있는 범위라는 것을 이해했다면, (바운디드)컨텍스트 매핑도 쉽게 이해할 수 있다.

각 컨텍스트 내에서 고객이라는 단어(보편언어)를 서로 다르게 사용하고 있다고 하자.

각 팀은 다른팀이 고객 을 뭐라고 부르고 있든 관계없이 팀내에서 사용할 의미를 결정하고 싶을 것이다.

더 나아가, 다른팀이 고객 의 의미를 바꿔서 사용하게 되더라도, 우리팀에서 설명하는 고객 에는 영향이 없기를 바랄 것이다.

즉, DDD 에서는 한 바운디드 컨텍스트가 다른 바운디드 컨텍스트의 변동사항에 영향을 받지 않기를 원한다.

한편, 개발팀이 사업팀과 협업해서 일을 해야하듯이 각각의 바운디드 컨텍스트도 서로 소통해야한다.

이 때, 모두 바운디드 컨텍스트내에서 사용되는 (보편언어로 표현된)도메인 모델이 항상 같은 의미를 가지도록 하는 매커니즘이 필요하고, 이러한 방법을 컨텍스트 매핑이라고 한다.

오픈 호스트 서비스(OHS), 발행된 언어(PL), 오염방지레이어(ACL) 등의 컨텍스트 매핑 기법들을 통해, 컨텍스트간의 정보교환을 허용하면서도 각 컨텍스트의 변경에 대해 다른 컨텍스트가 오염되는(혹은 망가지는) 것을 막아줄 수 있다.

컨텍스트 매핑과 마이크로 서비스

DDD는 마이크로서비스 아키텍쳐(MSA)와 직접적인 관련이 없지만, 각 마이크로서비스의 책임을 결정할 때 기준점을 잡는데 큰 도움을 준다.

하나의 바운디드 컨텍스트는 다른 컨텍스트의 도움없이 스스로 도메인 모델(혹은 비즈니스 로직)을 설명할 수 있다.

따라서 하나의 바운디드 컨텍스트를 하나의 마이크로서비스로 구성하면 다른 서비스와의 통신없이 (혹은 최소화하여) 비즈니스 로직을 처리할 수 있다.

만약 한 마이크로서비스가 핵심 비즈니스 로직을 처리하는데 다른 마이크로서비스의 트랜잭션이 선행되는 것을 요구한다면 아마도 두 마이크로 서비스는 한 바운디드 컨텍스트에 속해야할 가능성이 높다.

특히, 고전적인 UML 기반의 부실한(anemic) 도메인 모델을 사용하면 사소한 업데이트에도 두 개 이상의 서비스가 의존관계를 가지게 되어 SAGA(오케스트레이션/코리오그래피) 와 같은 분산트랜잭션을 요구하는 경우가 많다.

몇몇 케이스는 SAGA 대신 CQRS 와 같은 방법으로 우회할 수도 있겠지만, 기능이 추가되어 사용자 뷰가 추가될수록 개발 및 유지비용이 비선형적으로 증가하게 될 것이다.

마치며

위의 설명이 정확하지는 않지만, 기본적인 개념을 쉽게 설명한다는 측면에서 틀리지 않다고 생각된다.

위에 설명한 컴포넌트들만 대략 이해하고 공부를 시작해도, 훨씬 빠르게 DDD를 이해할 수 있을 것이다.