71 lines
9.3 KiB
Markdown
71 lines
9.3 KiB
Markdown
---
|
|
category: Unified
|
|
tags: [auto-wikified, technical-documentation]
|
|
title: Domain-Driven Design
|
|
description: "Domain-Driven Design(DDD)은 소프트웨어가 실제 비즈니스 로직과 규칙을 정확히 반영하도록 핵심 비즈니스 도메인(예: 판매, 물류 등)을 모델링하는 데 집중하는 설계 철학이자 접근법이다[1]."
|
|
last_updated: 2026-05-02
|
|
---
|
|
|
|
# Domain-Driven Design
|
|
|
|
## 📌 Brief Summary
|
|
Domain-Driven Design(DDD)은 소프트웨어가 실제 비즈니스 로직과 규칙을 정확히 반영하도록 핵심 비즈니스 도메인(예: 판매, 물류 등)을 모델링하는 데 집중하는 설계 철학이자 접근법이다[1]. 도메인 전문가와 개발자 간의 지속적인 협업 및 '보편적 언어(Ubiquitous Language)' 사용을 통해 비즈니스 요구사항과 코드를 일치시킨다[2]. 프레임워크별 실전 패턴에서 DDD는 주로 육각형 아키텍처(Hexagonal Architecture)와 결합하여 핵심 비즈니스 로직을 외부 기술로부터 완벽히 격리하고 보호하는 데 사용된다[3, 4].
|
|
|
|
## 📖 Core Content
|
|
* **핵심 구성 요소**
|
|
DDD는 도메인을 모델링하기 위해 보편적 언어(Ubiquitous Language), 제한된 컨텍스트(Bounded Contexts), 정체성을 가지는 엔티티(Entities)와 특성을 나타내는 값 객체(Value Objects), 애그리게이트(Aggregates), 도메인 서비스(Domain Services), 리포지토리(Repositories), 도메인 이벤트(Domain Events) 및 안티 코럽션 레이어(Anti-Corruption Layer) 등의 요소로 구성된다[2].
|
|
* **육각형 아키텍처와의 상호 보완성**
|
|
육각형 아키텍처는 DDD 모델을 캡슐화하고 외부로부터 격리하는 '구조(Structure)'를 제공하며, DDD는 코어에 해당하는 '내용(Content)'을 제공하는 방식으로 자연스럽게 결합된다[3]. 도메인 계층은 도메인 객체만을 입력 및 출력으로 관리하여 인프라의 간섭으로부터 스스로를 보호하며 자립적으로 동작한다[5].
|
|
* **프레임워크 적용 (Spring Boot & NestJS)**
|
|
Spring Boot 환경에서는 도메인 엔티티를 데이터베이스 매핑용 `@Entity` 어노테이션으로부터 분리하여 순수 자바 객체(POJO)로 유지하는 패턴이 권장된다[4, 6]. NestJS에서도 도메인과 인프라를 엄격히 분리하고, 복잡한 모듈 간 상호작용을 다루기 위해 도메인 이벤트 및 CQRS와 함께 DDD 개념이 적극 차용된다[7, 8].
|
|
* **데이터 품질 및 무결성 보장**
|
|
도메인 객체는 생성 단계에서 불변성(Invariants)을 검증해야 한다. 외부 서드파티 서비스에서 잘못된 형태의 데이터(DTO)가 들어오더라도 도메인 생성자에서 이를 차단함으로써 비즈니스 로직이 버그가 있는 데이터에 의해 오염되는 것을 방지한다[9].
|
|
|
|
## ⚖️ Trade-offs & Caveats
|
|
* **테스트 시 모킹(Mocking) 사용의 위험성**
|
|
도메인 비즈니스 로직을 테스트할 때 Mockito 등 모킹 프레임워크를 사용하면, 기능적으로 잘못된 동작을 테스트 코드에 하드코딩하게 될 위험이 크다. 이 경우 도메인 로직이 변경되더라도 모의 객체(Mock)가 자체적인 논리를 유지해 테스트가 통과해버리는 치명적인 결함이 발생할 수 있다. 따라서 도메인 내부 테스트에서는 모킹을 지양하고 실제 코드나 인메모리 스텁(Stub)을 사용해야 하며, 모킹은 인프라스트럭처 어댑터를 격리 테스트할 때만 제한적으로 사용해야 한다[10-13].
|
|
* **리소스-도메인 비대칭성(Resource-Domain Asymmetry)**
|
|
도메인 객체를 REST 리소스로 직접 직렬화하는 것은 권장되지 않는다. 도메인 내부에는 외부에 노출할 필요가 없는 기준(Criteria)이나 필드가 포함될 수 있기 때문이다. 리소스를 위해 전용 클래스를 두어 '안티 코럽션 레이어(Anti-Corruption Layer)' 역할을 부여하면, 도메인 객체를 리팩토링하더라도 기존 웹 API의 형태가 깨지는 것을 방지할 수 있다[14, 15].
|
|
* **파괴적 디커플링(Destructive Decoupling) 및 복잡도 증가**
|
|
단순한 CRUD 수준의 작은 기능에까지 DDD와 포트-어댑터 구조를 엄격하게 적용하면 오히려 불필요한 추상화, 인터페이스, 레이어가 남발되어 유지보수가 극도로 어려워질 수 있다[16]. 프로젝트의 도메인 복잡도에 맞춰 초기 도입 비용을 상쇄할 수 있는 수준에서 전략적으로 선택해야 한다[17].
|
|
|
|
## 🔗 Knowledge Connections
|
|
|
|
### Related Concepts
|
|
|
|
#### [관계 유형 A: 아키텍처/기반 기술]
|
|
- [[Hexagonal Architecture]]
|
|
- 연결 이유: 육각형 아키텍처는 DDD의 도메인 모델을 외부 프레임워크나 데이터베이스로부터 격리시키고 보호하기 위한 완벽한 구조적 껍질을 제공하기 때문이다[3].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 포트(Ports)와 어댑터(Adapters)를 활용하여 의존성이 무조건 도메인 코어 쪽을 향하도록 설계하는 구체적 구현 방식[3].
|
|
- [[Clean Architecture]]
|
|
- 연결 이유: 비즈니스 규칙(엔티티와 유스케이스)을 가장 안쪽 중심에 두고, 프레임워크 등 세부 기술을 외부 계층에 배치하는 의존성 역전 원칙을 DDD와 공유한다[18].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 계층 간 경계(Boundaries)를 설정하고 동심원 모델에서 제어의 흐름이 어떻게 관리되는지 이해할 수 있다[18].
|
|
|
|
#### [관계 유형 B: 구현/활용 도구]
|
|
- [[Anti-Corruption Layer]]
|
|
- 연결 이유: 외부 시스템(예: 서드파티 API, DB, UI)과의 통신 시 그 영향이 도메인 코어로 침투하지 못하도록 막는 DDD의 전술적 패턴 중 하나이다[2].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 데이터 표현 방식(DTO)과 도메인 모델 간의 구조적 차이를 어댑터 계층에서 버퍼링하고 변환하는 이유와 설계법[15].
|
|
- [[CQRS]]
|
|
- 연결 이유: 복잡한 애플리케이션 아키텍처에서 데이터를 읽는 작업과 도메인의 상태를 변경하는(쓰기) 작업을 분리하기 위해 DDD 및 마이크로서비스 설계 시 자주 도입된다[7, 19].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 읽기 최적화 쿼리와 쓰기를 위한 무거운 ORM 도구를 하이브리드 패턴으로 사용하는 백엔드 최적화 기법[19].
|
|
|
|
### Deeper Research Questions
|
|
- DDD의 '보편적 언어(Ubiquitous Language)'를 실제 프레임워크 소스코드(클래스명, 변수명, 패키지명)에 반영하고자 할 때, 기술적 컨벤션과 언어 간의 충돌을 어떻게 최소화할 수 있는가?
|
|
- Spring Boot나 NestJS 환경에서 도메인 엔티티를 프레임워크 의존성 없이 순수 객체(POJO 등)로 유지하면서 영속성(Persistence)을 처리할 때 발생할 수 있는 매핑 성능 오버헤드의 해결책은 무엇인가?
|
|
- 도메인 주도 설계 적용 시 도메인 테스트에서 모킹(Mocking)을 배제해야 한다는 원칙을 지키면서, 외부 API나 서드파티 통신이 필수적인 로직을 격리 테스트하기 위해 인메모리 스텁(Stub)을 구축하는 최적의 방법은 무엇인가?
|
|
- 모놀리식 구조에서 마이크로서비스 아키텍처로 점진적 전환을 시도할 때, DDD의 '제한된 컨텍스트(Bounded Contexts)' 개념이 서비스 경계 분리와 데이터베이스 분리에 구체적으로 어떻게 적용되는가?
|
|
- 프론트엔드 환경(예: React, Vue)에서도 DDD 패턴을 차용하여 순수 비즈니스 로직과 UI 컴포넌트 간의 의존성을 효과적으로 분리하는 실전 설계 사례는 어떠한가?
|
|
|
|
### Practical Application Contexts
|
|
- **Implementation:** 백엔드(예: Java/Spring, NestJS) 개발 시 비즈니스 규칙이 담긴 엔티티 객체에 `@Entity` 같은 인프라 어노테이션 사용을 엄격히 배제하여 프레임워크 기술에 비종속적인 코어 구현[4, 20].
|
|
- **System Design:** 소프트웨어 설계 시 시스템을 '제한된 컨텍스트' 단위로 쪼개어 모듈 또는 서비스 간 경계를 설정하며, 포트와 어댑터를 통해서만 통신을 허용하는 인터페이스 설계 수립[3, 21].
|
|
- **Operation / Maintenance:** DB를 교체하거나 외부 결제 API 공급자를 변경하더라도, 도메인 코어는 전혀 수정하지 않고 해당 어댑터 구현체만 새롭게 갈아끼워 시스템을 유지보수함[4, 22].
|
|
- **Learning Path:** 클린 아키텍처 및 육각형 아키텍처를 통해 의존성 관리 규칙을 먼저 학습한 후, 해당 아키텍처 코어 내부를 어떻게 설계할 것인지에 대한 해답으로서 DDD의 전술/전략 패턴을 학습.
|
|
- **My Project Relevance:** 복잡한 비즈니스 요건이 자주 바뀌는 엔터프라이즈 프로젝트에서, 비즈니스 핵심 코드가 UI와 DB 구조 변화에 휩쓸리지 않도록 보호하는 견고한 아키텍처 기반으로 활용 가능.
|
|
|
|
### Adjacent Topics
|
|
- [[Microservices Architecture]]
|
|
- 확장 방향: DDD에서 분할한 '제한된 컨텍스트(Bounded Contexts)'를 독립적으로 배포 및 실행 가능한 개별 마이크로서비스 단위로 매핑하고, 서비스 간 통합 패턴 설계 방향으로 확장[21].
|
|
|
|
---
|
|
*Last updated: 2026-05-02* |