DDD는 강력한 접근이지만 모든 문제에 필요한 것은 아니다. 복잡한 도메인에는 큰 도움이 되지만, 단순한 CRUD 시스템에 과하게 적용하면 오히려 비용만 늘어날 수 있다.
따라서 DDD를 도입하기 전에 먼저 질문해야 한다. 우리에게 정말 DDD가 필요한가? 필요하다면 어디에 적용해야 하는가? 팀은 도메인 전문가와 대화할 준비가 되어 있는가? 현재 코드에서 가장 큰 문제는 무엇인가?
이 글은 DDD 도입 여부를 판단하기 위한 체크리스트다. 정답을 주는 목록이라기보다, 팀이 함께 대화하기 위한 질문 모음에 가깝다.
1. 도메인이 충분히 복잡한가
DDD는 복잡한 도메인을 다루기 위한 방법이다. 따라서 먼저 복잡성이 어디에 있는지 봐야 한다.
상태 전이가 많은가?
비즈니스 규칙이 자주 바뀌는가?
예외 정책이 많은가?
같은 기능이라도 고객 유형이나 상황에 따라 다르게 동작하는가?
운영자가 수동으로 판단하는 경우가 많은가?
예를 들어 구독 서비스에서 갱신, 만료, 해지, 환불, 요금제 변경, 무료 체험, 유예 기간이 복잡하게 얽혀 있다면 DDD를 고려할 만하다.
반대로 단순히 제목과 내용을 저장하는 공지사항 관리라면 DDD의 깊은 모델링이 필요하지 않을 수 있다.
중요한 것은 복잡한 곳과 단순한 곳을 구분하는 것이다.
2. Core Domain은 무엇인가
모든 영역에 같은 수준의 설계가 필요하지 않다. DDD를 도입한다면 먼저 Core Domain을 찾아야 한다.
우리 서비스의 경쟁력은 어디에서 나오는가?
잘못 설계했을 때 비즈니스 영향이 가장 큰 영역은 어디인가?
가장 자주 바뀌는 정책은 무엇인가?
도메인 전문가와 가장 많이 대화해야 하는 기능은 무엇인가?
Core Domain이 명확하지 않으면 DDD는 모든 곳에 퍼진다. 그러면 단순한 기능까지 무거워지고, 팀은 DDD를 부담스러운 절차로 느끼게 된다.
DDD는 전체 적용보다 집중 적용이 중요하다.
3. 도메인 전문가와 대화할 수 있는가
DDD는 개발자만의 설계 활동이 아니다. 도메인 전문가와의 대화가 필요하다.
도메인 규칙을 설명해줄 사람이 있는가?
개발자가 도메인 질문을 던질 수 있는 채널이 있는가?
요구사항 문서 외에 실제 운영 지식을 들을 수 있는가?
용어 차이를 논의하고 정리할 시간이 있는가?
도메인 전문가 없이 개발자끼리만 모델링하면 모델은 추측이 된다. 물론 항상 이상적인 도메인 전문가가 있는 것은 아니다. 그럴 때는 운영자, 기획자, 고객센터, 데이터 분석가, 기존 코드와 운영 문서를 통해 도메인 지식을 찾아야 한다.
중요한 것은 도메인 지식을 코드 밖에서 계속 탐구하려는 태도다.
4. 같은 단어가 다른 의미로 쓰이는가
Bounded Context가 필요한 신호 중 하나는 같은 단어가 맥락마다 다르게 쓰이는 경우다.
회원은 인증 시스템의 사용자와 같은가?
고객은 구매자, 구독자, 청구 대상자 중 무엇인가?
상품은 전시 상품인가, 주문 상품인가, 정산 상품인가?
구독 해지는 환불과 같은가, 다른가?
결제 취소와 환불은 같은 말인가?
이런 질문에 답하기 어렵다면 모델의 경계를 고민해야 한다. 하나의 공통 모델로 모두를 표현하려고 하면 시간이 지날수록 모델이 비대해진다.
DDD 도입의 중요한 출발점은 용어의 충돌을 발견하는 것이다.
5. 현재 코드에서 도메인 규칙은 어디에 있는가
코드를 열어 도메인 규칙이 어디에 있는지 확인해보자.
Entity 안에 있는가?
Application Service에 있는가?
Controller에 있는가?
Repository 쿼리에 숨어 있는가?
프론트엔드에 중복되어 있는가?
운영 매뉴얼이나 사람의 기억 속에만 있는가?
규칙이 여러 곳에 흩어져 있다면 DDD가 도움이 될 수 있다. 도메인 객체, Policy, Domain Service, 테스트를 통해 규칙을 명시적으로 모을 수 있기 때문이다.
특히 다음과 같은 코드가 많다면 경고 신호다.
if (status == "A" && paymentStatus == "P" && type != "TRIAL") {
// ...
}
이 조건이 무엇을 의미하는지 이름이 없다면, 도메인 개념이 코드 안에서 숨어 있는 것이다.
6. 트랜잭션 경계가 불명확한가
DDD에서 Aggregate는 일관성의 경계다. 현재 시스템에서 무엇을 한 트랜잭션 안에서 지켜야 하는지 불명확하다면 Aggregate 설계가 필요할 수 있다.
어떤 객체들이 항상 함께 변경되어야 하는가?
어떤 규칙은 잠시라도 깨지면 안 되는가?
어떤 후속 처리는 나중에 처리해도 되는가?
모든 것을 한 트랜잭션에 넣느라 모델이 커지고 있지는 않은가?
트랜잭션이 너무 크면 성능과 변경성이 나빠진다. 반대로 반드시 함께 지켜야 할 규칙이 분산되어 있으면 데이터가 쉽게 깨진다.
DDD는 일관성의 종류를 구분하게 해준다.
7. 팀이 설계 비용을 감당할 수 있는가
DDD는 공짜가 아니다. 용어를 맞추고, 모델을 정제하고, 경계를 나누고, 테스트를 작성하는 데 시간이 든다.
팀이 도메인 모델을 함께 리뷰할 수 있는가?
코드 리뷰에서 도메인 언어를 논의할 수 있는가?
설계 결정을 문서화하거나 공유할 수 있는가?
짧은 일정 속에서도 핵심 도메인에 시간을 쓸 수 있는가?
DDD를 제대로 하려면 팀의 학습과 협업이 필요하다. 한두 명만 DDD를 이해하고 나머지는 패턴만 따라 하면 실패하기 쉽다.
작게 시작하는 것이 좋다. Core Domain의 한 유스케이스부터 모델링하고, 테스트를 작성하고, 팀과 언어를 맞춰가는 방식이 현실적이다.
8. 모든 곳에 DDD를 적용하려고 하지는 않는가
DDD 도입에서 가장 흔한 실패는 과잉 적용이다.
단순 CRUD에도 Aggregate를 만든다.
모든 상태 변경에 Domain Event를 발행한다.
모든 외부 호출에 복잡한 Port와 Adapter를 둔다.
모든 조건문을 Specification으로 만든다.
이런 방식은 DDD를 무거운 구조로 만든다. DDD는 중요한 도메인에 설계 에너지를 집중하는 방법이다. 단순한 영역에는 단순한 구조를 허용해야 한다.
좋은 체크리스트에는 “어디에 적용할 것인가”뿐 아니라 “어디에는 적용하지 않을 것인가”도 포함되어야 한다.
9. 점진적으로 시작할 수 있는가
DDD는 한 번에 도입하기보다 점진적으로 도입하는 편이 좋다.
복잡한 조건문 하나를 Policy로 분리한다.
원시값 하나를 Value Object로 바꾼다.
setter 기반 상태 변경 하나를 도메인 행위로 바꾼다.
핵심 유스케이스 하나에 도메인 테스트를 작성한다.
외부 API 모델 하나를 ACL 뒤로 숨긴다.
작은 성공이 팀의 신뢰를 만든다. 처음부터 전체 아키텍처를 바꾸려 하면 저항도 크고 실패 비용도 크다.
DDD는 도입 프로젝트가 아니라 지속적인 모델 정제 과정에 가깝다.
마치며
DDD를 도입할지 말지는 유행이나 기술 선호로 결정할 문제가 아니다. 도메인의 복잡성, 비즈니스 가치, 팀의 협업 방식, 현재 코드의 문제를 함께 봐야 한다.
좋은 질문은 다음과 같다.
우리에게 복잡한 도메인이 있는가?
그 복잡성이 코드 안에서 흩어지고 있는가?
도메인 전문가와 같은 언어를 만들 수 있는가?
어디가 Core Domain인가?
어디에는 DDD를 쓰지 않아도 되는가?
작게 시작할 수 있는가?
이 질문에 답할 수 있다면 DDD는 훨씬 현실적인 선택이 된다. 반대로 이 질문 없이 Entity, Aggregate, Repository부터 만들기 시작하면 DDD는 쉽게 형식적인 구조가 된다.
DDD 도입은 패턴 적용이 아니라 질문에서 시작한다. 좋은 질문이 좋은 모델을 만든다.