조영호님의 오프라인 DDD 세미나 정리 - 1
조영호님의 DDD 오프라인 세미나를 듣고, 내용을 정리해봤습니다.
해당 세미나에서는 에릭 에반스가 2003년도에 만든 도메인 주도 설계(DDD) 책의 난해한 내용들을 정리했습니다.
또한 실무와 관련되어 DDD를 어떻게 반영할 수 있을지 약간의 가이드를 제시해주었습니다.
파트1. 동작하는 도메인 모델 만들기
동작하는 도메인 모델 만들기란?
도메인 모델이란?
도메인은 특정한 업무 영역이나 문제를 해결하기 위해 소프트웨어가 자동화할 수 있는 부분을 말합니다.
개발자는 필요한 부분을 코드로 구현하여 자동화합니다. 그러나 모든 과정을 자동화하는 것은 불가능합니다.
개발자는 특정한 업무 영역을 자동화할 수 있으며, 이를 도메인이라고 합니다.
예를 들어, 배달 과정을 자동화한다고 가정해보겠습니다. 흐름은 다음과 같습니다.
- 고객이 메뉴를 확인
- 주문
- 결제
- 사장이 조리
- 배달기사가 배달
이 과정에서 고객이 메뉴를 확인하고 주문하고 결제하는 것은 자동화가 가능하지만, 사장이 조리하고 배달기사가 음식을 배달하는 것은 자동화가 불가능합니다.
따라서 고객이 메뉴를 확인하고, 주문하고, 결제하는 부분이 자동화할 수 있는 도메인에 해당됩니다.
모델은 대상의 단순화를 의미합니다.
당면한 문제를 해결하는 과정에서 중요한것은 추상화하고, 안중요한 부분은 전부 생략하는것 입니다.
너무 세부적이고 디테일한 내용들은 제외하고 추상화하는것을 의미합니다.
결국에 도메인 모델이란 개발자가 자동화하여 해결하고자 하는 영역을 간단하게 추상화한것을 의미합니다.
DDD 방법론에서는 도메인 모델을 기반으로 핵심 설계와 코드를 작성합니다.
기술에 집중하는게 아니라 도메인에 집중해야한다고 합니다.
그래서 코드를 바꾸면 도메인 모델이 변경되어야하고 설계가 바뀌어야합니다.
반대로 도메인 모델이 변경되어도 코드가 변경되고 설계가 변경되어야합니다.
이렇게 모델과 핵심 설계는 반복적으로 서로 영향을 주며 구체화됩니다. 이것을 동작하는 도메인 모델이라고 합니다.
제품의 전 과정에서 도메인 전문가와 같이 도메인 지식을 공유하면서 도메인 모델을 만들어야합니다. 이 과정을 지식탐구라고 합니다.
지식탐구를 위해서는 일관된 용어를 사용하는것이 중요합니다. 이를 위해서 유비쿼터스 언어를 만들고 사용합니다.
결과적으로 동작하는 도메인 모델 만들기란, 도메인 전문가와 개발자가 팀을 이루어서 유비쿼터스 언어를 활용해 지식을 탐구하여 도메인 모델을 만들고 설계하고 코드를 만드는 과정을 반복하는것을 의미합니다.
요약
Domain-Driven Design | Evans, Eric
- 1장) 지식 탐구 -> 요약 : 제품의 모든 과정에서 도메인 전문가와 소통해라
- 2장) 의사소통과 언어 사용 → 요약 : 모두가 이해할 수 있는 유비쿼터스 언어를 사용해라]
- 3장) 모델과 구현의 연계 → 요약 : 도메인 전문가와 지식을 같이 탐구하면서 도메인 모델을 창조해라. 유비쿼터스 언어를 함께 만들고 커뮤니케이션에 이용해라. 그리고 도메인 모델과 코드와 설계의 라이프사이클을 같이 가져가라.
왜 이런 사상이 등장하게 되었을까?
DDD는 객체지향보다 더 상위 개념을 다루기 위한 방법론입니다.
기존에 1990년대에서 2000년대까지는 객체지향의 세대이었습니다.
GUI가 등장하면서 객체의 흥행이 시작됩니다.
생각해보면 GUI는 객체지향에 가장 적합한 구조입니다.
이 때 당시에는 앱 프로그램안에 모델 뷰 컨트롤러가 같이 들어가면서 객체들이 전부 프로그램에 들어가고 이 때부터 MVC 패턴이 각광받게 됩니다.
그러다가 브라우저가 등장하고 서버가 분리되어 대부분의 도메인 로직이 애플리케이션 티어로 움직입니다.
그러면서 분산 객체라는 기술이 유행하게됩니다. 이를 프레임워크로 만든게 EJB입니다.
하지만 분산 객체는 기술의 침투가 너무 많았습니다. 결과로 도메인 로직과 기술이 강하게 뒤섞이게됩니다.
EJB의 경우 단순한 도메인 모델을 만드려고해도 EJB 인터페이스를 최소 3개를 구현해야합니다.
그래야 프레임워크가 분산객체를 동작시켜주면서 서버가 뜰 수 있습니다.
이러한 이유로 단위테스토도 불가능해지고, 코드는 기술과 강력하게 엮이면서 코드만 보고 도메인을 이해하는게 불가능해집니다.
결국 개발자들은 분산 객체와 같은 이상적인 기술에 집착하기보다, 도메인 지식을 공유하면서 개발하는게 중요하다는것을 깨닫게됩니다.
POJO라는 단어도 이 때 등장하게 됩니다.
이러한 상황에서 2003년에 에반스의 도메인주도설계가 등장하게되었고, 머릿속에 있는 도메인과 코드의 차이를 좁히는것이 대세가되었습니다.
파트2. 모델 주도 설계의 빌딩 블록
요약
‘그래서 해당 파트2는 도메인 모델을 어떻게 코드로 잘 끌고 올 수 있을까’ 에 대한 내용입니다.
DDD는 아키텍처를 강제하지 않습니다. 도메인 로직이 격리만되어있으면 전략적 설계는 이루어져있다고 볼 수 있습니다.
빌딩 블록이라는 개념이 등장합니다.
빌딩 블록의 목적은 구현에 대한 가이드를 제공해서 복잡도를 낮추는것입니다.
도메인을 표현하기 위한 빌딩 블록은 아래와 같습니다.
- ASSOCIATION
- VALUE OBJECT
- ENTITY
- SERVIE
- MODULE
생명주기를 관리하기 위한 빌딩 블록은 아래와 같습니다.
- AGGREGATE
- REPOSITORY
- FACTORY
에그리게이트의 기준은 불변식을 지키기 위한 객체들의 모임입니다.
불변식이란 객체가 상태가 변경되는 상황에서 꼭 지켜야하는 제약조건입니다. 예를 들어서 세트 메뉴의 가격은 각 단품의 가격의 합보다 작아야한다
라는게 불변식입니다.
객체를 한 묶음으로 묶게되면 이런 규칙을 이쁘게 지킬 수 있습니다.
에그리게이트는 마치 데이터베이스 트랜잭션과 같이 우리의 도메인 내에서 데이터 정합성을 보장하는 라이프사이클 빌딩 블록입니다.
그래서 트랜잭션 하나에는 하나의 에그리게이트만이 존재해야합니다.
유즈케이스에서 다른 에그리게이트의 데이터를 변화시켜야한다면 도메인 이벤트를 발행해야합니다.
예를 들어서 주문에 따른 마일리지가 적립되어야하는 상황을 생각해봅니다.
주문과 주문 아이템은 불변식을 지켜주기 위해서 하나의 트랜잭션에서 관리되어야하고, 주문 애그리거트가 변화하면 도메인 이벤트를 발행합니다.
그리고 해당 이벤트를 컨숨해서 마일리지를 적립해줘야합니다.
레포지토리는 애그리게이트별로 하나씩만 존재해야합니다.
그래야 데이터 일관성을 지켜줄 수 있습니다.
요약
4장) 도메인의 격리 → 요약 : 도메인 주도 설계의 전제 조건은 도메인 로직이 다른 곳에 의존하지 않는 것이다. 5장) 소프트웨어에서 표현되는 모델 → 요약 : 연관관계, 엔티티, 값 객체, 서비스, 모듈 6장) 도메인 객체의 생명주기 → 요약 : 에그리게이트, 리파지토리, 팩토리 7장) 언어 사용 -> 요약 : 확장 예제
파트3. 더 심층적인 통찰력을 향한 리팩터링
개발이라는게 애초에 건축과 디자인보다 훨씬 뒤에 생겨진 분야로, 건축과 디자인에서 많은 부분들을 차용해왔습니다.
건축에서는 10층까지 아파트를 쌓아올리고 설계를 도중에 변경하는게 불가능합니다.
따라서 사전 설계가 완벽해야합니다.
하지만 소프트웨어는 초반부터 완벽하게 설계하고 구현하는것이 불가능합니다.
현대 사회에서는 빠르게 서비스를 출시하고, 지속적으로 고객에게 더 나은 경험을 제공할 수 있도록 코드를 지속적으로 변경해야합니다.
초반부터 요구사항이 명확한 경우는 거의 없고, 과도한 사전 설계는 소프트웨어에서 어울리지 않습니다.
이러한 이유로 애자일이 등장합니다.
캔트백이 설립한 XP라는 애자일 방법론은 변경을 수용하라고 적혀있습니다.
XP에서의 핵심은 반복을 통한 피드백입니다.
전체 시스템에서 일부만 먼저 개발하고 개발된 결과를 바탕으로 피드백하고 변경을 수용하면서 리팩토링하고 다음 반복 계획을 세우는것이 핵심입니다.
이를 통해서 흐릿햇던 요구사항이 시간이 지나면서 점점 뚜렷해집니다.
에자일은 DDD에서도 확인할 수 있습니다.
도메인 전문가와 개발자가 함께 도메인에 대한 통찰을 반영하여 도메인 모델을 지속적으로 리팩토링하는것이 DDD입니다.
초반부터 완벽한 도메인 모델을 만드는것은 어렵습니다.
처음에는 절차적으로 작성하고 반복적으로 개발과 피드백을 반복하면서 리팩토링 과정에서 도메인 모델을 완벽하게 만들어나가는게 DDD에서의 애자일입니다.
요약
8장) 도약 -> 반복적인 설계와 리팩토링으로 도약 9장) 암시적인 개념을 명확하게 → 반복적인 설계로 인해 초반 흐릿했던 요구사항이 시간이 갈수록 명확해진다. 10장) 유연한 설계 → 반복적인 설계, 구현이 반복되다보니 요구사항의 변경에 유연해진다. 11장) 분석 패턴의 적용 12장) 모델과 디자인 패턴의 연결 13장) 더 심층적인 통찰력을 향한 리팩터링
파트4. 전략적 설계
개발자의 경우 대부분 중복을 싫어합니다.
하지만 중복이 필요한 경우가 분명하게 존재합니다.
도메인 모델을 하나로만 관리하려고하면 어마어마하게 커지는것을 금방 볼 수 있습니다.
어느정도 규모가 커진 조직이라면 코드의 중복을 발생시키더라도 팀간에 모델을 분리해서 가져가야합니다.
확장성이 좋은 코드를 만들기 위해서는 우리는 응집도는 높고 결합도는 낮은 코드를 지향해야합니다.
응집도가 높다는것은 코드의 변경이 하나의 이유로 이뤄진다는것을 의미합니다. 반대로 응집도가 낮다는것은 여러가지 이유로 코드의 변경이 발생할 수 있다는것을 의미합니다.
만약에 내가 작성하는 코드에서 다른 팀원과 컨플릭이 자주 발생한다면 이는 응집도가 낮은것이 원인일 가능성이 매우 높습니다.
즉 어느정도 중복을 허용하더라도 모델이 단일 관심사를 갖도록 구성하는게 좋은데, 바운디드 컨택스트가 이러한 개념을 나타냅니다.
바운디드 컨텍스트란 도메인 모델을 적용할 수 있는 범위를 나타냅니다.
얘를 들어서 티켓이라는 모델이 있을때, 티켓의 배송과 판매와 출력을 하나의 모델로 관리하는것은 좋지 않습니다.
각 모델별로 티켓에 대한 어느정도의 중복 데이터가 있을 수 있겠지만, 배송 컨택스트, 판매 컨택스트, 출력 컨택스트로 모델을 분리하는것이 좋습니다.
적절하게 도메인 모델을 적용할 수 있는 범위를 분리하는것이 좋고, 이게 바운디드 컨택스트입니다.
이러한 관점은 MSA의 호스트 기준이되기도합니다.
하지만 바운디드 컨택스트 개념이 MSA에서 서비스 단위로 적절해서 가끔 차용되는것이지 MSA와 DDD는 전혀 다른것입니다.
바운디드 컨택스트는 조직 관리와 설계가 만나는 지점입니다.
전략적 디스틸레이션
전략적 디스틸레이션이란 도메인 지식을 명확하고 효과적으로 정의하는 과정을 말합니다.
하위 도메인을 분리하고 바운디드 컨택스트를 관리하는 것이 대표적입니다.
이 과정은 도메인의 복잡성을 줄이고 중요한 비지니스 가치를 가진 부분을 식별하여 더 쉽게 관리할 수 있도록 도와줍니다.
코어 도메인은 사업의 성공을 결정하는 핵심적인 서브 도메인을 의미합니다.
제네릭 서브 도메인은 비지니스에 경쟁 우위를 제공하지않고 타사의 여러 애플리케이션에 공통으로 존재하는 서브도메인을 의미합니다.
지원 서브 도메인은 비지니스에 경쟁 우위를 제공하지 않지만 비지니스의 일부로 코어 도메인을 지원하는 서브도메인을 의미합니다.
서브 도메인과 바운디드 컨택스트의 개념이 헷갈릴 수 있습니다.
이상적으로 나눠져야하는 기준은 서브 도메인으로 보면되고, 실제로 우리의 코드가 여러가지 이유로 인해 이상과 다르게 나눠지는것을 바운디드 컨택스트로 보면됩니다.
대규모 구조
에그리게이트를 수정하면 도메인 이벤트를 발행합니다.
여기에서 이벤트 소싱이라는 개념이 등장하는데, 이는 도메인 이벤트를 이벤트 스토어에 전부 저장하는것입니다.
마치 은행의 입출금 이동 기록을 전부 기록하는것과 같습니다.
이렇게 사용할 경우 장점은 데이터의 변화 히스토리를 알 수 있다는 점입니다.
이벤트 소싱을 사용하면 RDB는 사용하지않습니다.
실무에서 이벤트 소싱까지 필요한 경우가 많다고 볼 순 없습니다.
법적으로 데이터의 변화를 꼭 기록해야하는 경우에만 보통 사용합니다.
도메인 이벤트의 데이터 유실은 트랜잭션 아웃박스 패턴을 사용하거나 배치를 통한 데이터를 보정해주거나, 아니면 데이터 유실이 치명적이지않은곳에서 사용하는게 좋다.
에그리게이트 기준
에그리게이트를 조회를 기준으로 묶으면 안됩니다. 우리가 말하는 비지니스 로직이란 수정 로직입니다.
수정시에 불변식을 위해 협력하는 객체들을 묶은게 에그리게이트입니다.
CQRS
CQRS는 어느정도의 규모가 되면 웬만하면 사용하는것이 좋습니다.
수정과 생성을하면 플랫한 데이터를 발행하고 조회는 이를 저장했다가 플랫한 데이터를 화면에 뿌려주면 됩니다.
조회 로직을 복잡한 비지니스로직으로부터 분리하는것입니다.
사실 CQRS와 DDD는 직접적인 관계는 없지만, DDD라는게 도메인 모델 분리를 통한 복잡성 해결을 목적으로 하고있는데 CQRS가 조회와 수정을 분리함으로써 모델을 분리해서 복잡성을 해결하기때문에 CQRS도 DDD에서 다뤄집니다.
이 때에는 웬만하면 DB도 분리하는것이 좋습니다.
헥사고날
헥사고날도 도메인 로직을 외부 요청하는곳으로부터 의존성을 제거한다는 아키텍처인데, DDD와 도메인 로직을 격리시킨다는 점이 같을 뿐이지 나머지는 관계가 없습니다.
요약
14장) 모델의 무결성 유지 → 바운디드 컨텍스트, 컨텍스트 맵 15장) 디스틸레이션 → 핵심 하위 도메인, 일반 하위 도메인, 지원 하위 도메인 16장) 대규모 구조 17장) 전략의 종합