Domain은 소프트웨어 공학에서 사용하는 용어로 소프트웨어 시스템이나 프로젝트가 다루고 있는 문제 영역 이나 전문적인 분야(금융, 커머스, 가상화폐 등등)을 의미합니다. 즉 소프트웨어가 구현해야하는 현실세계의 문제들을 가르킵니다. 그렇기 때문에 제대로 요구사항들을 구현하기 위해서는 도메인에 대한 지식을 충분히 가지고 개발하거나 도메인 관련해서 이해가 안간다면 도메인 전문가와 협력해서 소프트웨어를 개발하는 것이 좋습니다.
Domain Model은 Domain에 대한 개념적 모델을 이야기합니다. 즉 Domain에 대한 체계적이고 구조화된 지식을 나타내고 Entity간의 관계를 식별합니다. 일반적으로 아래와 같이 UML 다이어그램을 통해 시각적으로 나타냅니다.
출처: https://en.wikipedia.org/wiki/Domain_model
Ubiquitous Language는 도메인 전문가, 기획자, 디자이너, 개발자, 아키텍트 즉 프로젝트 구성원 모두에게 공유된 일관적인 언어를 뜻합니다. 이러한 언어를 사용하면서 구성원 간 의사소통을 원할하게 할 수 있습니다. Ubiquitous Language의 예를 하나 들자면 대학교 시스템에서 학사 관리 시스템, 도서관 관리 시스템, 기숙사 관리 시스템이 있다고 가정했을 때 학부생에 대한 정보는 모든 시스템이 사용합니다. 하지만 학사 관리 시스템에서는 학부생 도서관 관리 시스템에서는 도서관 이용자 기숙사 관리 시스템에서는 기숙사 이용자 이렇게 의미론적으로 사용하면서 본질은 학부생이지만 각 도메인에 따라 다르게 불립니다.
Bounded Context는 하나의 독립적인 시스템이 될 수 있는 경계를 의미합니다. 이러한 경계를 나누는 이유는 복잡한 시스템을 잘게 쪼개어 복잡성을 낮추게 되는 이점도 있고 경계를 나누지 않았을 때는 하나의 주체로서 모든 도메인에서 사용을 했지만 경계를 나누게 되면서 하나의 주체를 각 도메인의 성격에 맞게 나누고 Ubiquitous Language로 표현할 수 있기 때문에 해당 도메인에 맞는 언어를 사용하기 때문에 해당 도메인을 개발하는 관점에서 봤을 때 일관성있고 명확하기 때문에 직관적입니다. 또한 하나의 독립적인 시스템으로서 관리할 수도 있어 확장성에 용이하다는 장점이 있기 때문에 Bounded Context라는 패턴이 생겨나게 되었습니다.
아래 예제를 통해 좀 더 직관적으로 이해해보도록 하겠습니다.
이해를 돕기 위해 실제는 아니고 제가 직접 구상한 대학교 시스템를 도메인으로 나눠보았습니다.
크게 학사 관리, 도서관 관리, 기숙사 관리로 Bounded Context가 나뉘게 되었습니다. 도서관 관리, 기숙사 관리 시스템에서는 학사 관리 시스템에 있는 학부생이라는 도메인에 관심이 많습니다. 물론 학부생이라는 도메인으로 통일시킬 수 있지만 도서관 관리 시스템에서는 학부생이 아닌 도서관 이용자로 볼 것이고 기숙사 관리 시스템에서는 기숙사 이용자로 불릴 것입니다. 본질적으로는 학부생이지만 Bounded Context마다 각각 다른 유비쿼터스 언어로 표현됩니다. 이러한 특성으로 나중에 도서관 관리 시스템의 도서관 이용자(학부생)나 기숙사 관리 시스템의 기숙사 이용자(학부생)만의 비즈니스 로직이 생긴다해도 서로 다른 경계(Bounded Context)에 있기 때문에 학사 관리 시스템에 있는 학부생은 영향을 받지 않습니다.
Domain Event는 소프트웨어 시스템 내에서 발생하는 중요한 비즈니스 사건을 나타내는 개념이고 시스템 내의 중요한 변경이나 상태 변화를 표현하며, 이를 통해 다른 부분의 시스템이나 서비스가 그 사건에 반응할 수 있도록 합니다.
특징
Domain Event를 도입하게 되면 비즈니스 로직을 한 곳에 집중시키지 않고 여러 시스템이나 서비스에 걸쳐 재사용할 수 있어 시스템간의 결합도가 감소하고 시스템의 한 부분에서 일어난 사건을 다른 부분이 비동기적으로 처리할 수 있게 해줍니다.
Aggregate는 서로 관련이 있는 여러 객체들이 모여 이루는 그룹이며 동일한 라이프사이클을 가지고 있습니다.
이러한 특징으로 인해 복잡한 도메인 로직을 관리하고, 도메인 모델의 일관성을 보장하는 데 도움을 줍니다.
Aggregate 내에는 'Root Entity'라고 불리는 중심 엔티티가 존재합니다. 이 Root Entity는 Aggregate의 외부와의 모든 상호작용을 관리하며, Aggregate 내의 다른 객체들에 대한 참조를 유지합니다. 외부 객체는 Aggregate Root를 통해서만 Aggregate 내의 객체와 상호작용할 수 있습니다.
Aggregate는 자체적으로 일관성과 유효성을 검증할 수 있는 능력을 가지고 있습니다. 이는 도메인 규칙이 Aggregate 내부에 캡슐화되어 있음을 의미합니다.
그래서 Domain Driven Design는 위에서 설명한 요소들을 이용해 복잡한 소프트웨어 시스템을 설계하고 개발할 때 도메인 모델을 중심으로 하는 설계 접근 방식입니다. 이 방법론은 소프트웨어가 해결해야 할 비즈니스 문제를 중심으로 설계되어야 한다는 원칙을 강조합니다. DDD는 소프트웨어 개발자들이 비즈니스 도메인의 복잡성을 이해하고 이를 반영하여 유연하고 효율적인 시스템을 구축할 수 있도록 돕습니다.
DDD를 도입하게 되면 요구사항에 대해 좀 더 잘 이해하는 습관을 들일 수 있고 이러한 요구사항 이해를 바탕으로 객체에 대한 행위를 도출하기가 비교적 쉽기 때문에 객체지향 설계하기에도 용이합니다. Ubiquitous Language를 이용해 코드와 요구사항에서 이야기 하는 용어를 어느정도 일치시켜 비즈니스 로직에 대해 이해하기 쉽습니다. 무엇보다도 도메인을 기준으로 나누기 때문에 서비스를 MSA로 분리하거나 유지보수 하기에도 용이합니다.
DDD를 기반으로 제대로 설계하려면 도메인 및 시스템의 비즈니스 요구 사항에 대한 깊은 이해는 물론 이해관계자, 도메인 전문가 및 개발자와의 원할한 커뮤니케이션이 제일 중요하다고 생각이듭니다. 애매하게 이해한것을 기반으로 개발을 진행하게 되면 오히려 커뮤니케이션 비용이 많이 들고 개발의 복잡성 또한 증가된다고 생각이듭니다.
이러한 부분들을 참고해서 설계를 하게 되면 무조건 좋은 설계로 발전되는건 아니지만 어느정도 준수한 설계를 할 수 있다고 생각합니다.