개발철학&개발용어

도메인 주도 설계(DDD), 속도는 빨라지는데 사람은 더 필요해집니다

 

 

"DDD요? 결국 폴더 구조 이쁘게 나누는 거 아니에요?"
"책은 읽었는데, 우리 프로젝트 어디서부터 손대야 할지 모르겠어요."
"그거 규모 큰 회사에서나 쓰는 거 아닌가요?"
"도입했더니 오히려 개발이 더 느려진 것 같은데요."

 

 

도메인 주도 설계(Domain-Driven Design), 줄여서 DDD를 두고 저 주위에서 자주 나오던 말들입니다. 재밌는 건 네 개 다 반쯤은 맞는 말이라는 점이에요. 저는 SI 현장과 서비스 개발을 오가면서 DDD를 몇 년 겪었는데, 그 과정에서 얻은 결론이 조금 삐딱합니다. DDD를 제대로 걸어두면 개발 속도가 확 붙는 건 맞는데, 그게 공짜가 아니라는 겁니다.

이걸 저는 요즘 후배들한테 설명할 때 싱글스레드와 멀티스레드에 비유합니다. 멀티스레드가 무조건 빠른 게 아니잖아요. 코어가 많고 일이 크면 비약적으로 빨라지지만, 일이 작으면 스레드 만드는 비용 때문에 오히려 느려지고요. DDD도 딱 그렇습니다. 이 글에서는 DDD가 뭔지 개념을 짚고, 왜 속도가 양날의 칼인지, 그리고 지금(2026년 기준) 어떤 프로젝트에 도입할 만한지까지 제 경험을 섞어서 풀어보겠습니다. 아키텍처를 고민 중인 팀 리드나, DDD 책은 읽었는데 실무 감이 안 잡히는 분들께 도움이 될 것 같습니다.

📋 목차

  1. DDD가 도대체 뭘 해결하려고 나왔나
  2. 유비쿼터스 언어 - 회의실에서 통역하던 시절
  3. 바운디드 컨텍스트 - 경계를 긋는다는 것
  4. 전략적 설계와 전술적 설계
  5. DDD와 마이크로서비스는 왜 붙어 다니나
  6. DDD는 멀티스레드를 닮았습니다
  7. 속도가 빨라지는 대신 사람이 늘어난다
  8. 작은 프로젝트에 풀세트로 넣었다가 데인 이야기
  9. 그래서 언제 도입해야 하나

1. DDD가 도대체 뭘 해결하려고 나왔나

DDD는 2003년 에릭 에반스(Eric Evans)가 쓴 책에서 시작됐습니다. 제목을 직역하면 "소프트웨어 심장부의 복잡성을 다루기" 정도인데, 여기서 핵심 단어는 복잡성입니다. 에반스가 문제 삼은 건 기술적 복잡성이 아니라 도메인, 그러니까 그 업무 자체가 원래 복잡하다는 점이었어요.

은행 업무, 보험 계약, 물류 배송 같은 걸 떠올려 보면 됩니다. 코드가 어려운 게 아니라 업무 규칙이 어렵죠. 그런데 우리는 보통 이 어려운 업무를 개발자 머릿속에서 대충 번역한 다음, 데이터베이스 테이블 구조에 억지로 욱여넣습니다. 그러다 보면 코드는 돌아가는데 정작 그 코드가 무슨 업무를 하는 건지 아무도 설명 못 하는 상황이 옵니다. 저는 이걸 "도메인이 코드랑 따로 노는 상태"라고 부릅니다. DDD는 이 간극을 좁히자는 이야기예요.

그래서 DDD를 폴더 구조나 특정 프레임워크로 이해하면 처음부터 어긋납니다. DDD는 라이브러리가 아니라 사고방식에 가깝습니다. 코드를 업무 언어에 최대한 붙여두려는 태도라고 보는 게 맞아요.

2. 유비쿼터스 언어 - 회의실에서 통역하던 시절

DDD에서 제일 먼저 나오는 개념이 유비쿼터스 언어(Ubiquitous Language)입니다. 말은 거창한데, 뜻은 단순합니다. 기획자, 현업 담당자, 개발자가 같은 단어를 같은 뜻으로 쓰자는 겁니다.

이게 왜 중요한지는 겪어봐야 압니다. 2016년쯤 제가 어느 SI 프로젝트에서 중간 다리 역할을 할 때였어요. 현업에서는 "정산"이라고 부르는 걸 개발팀 코드에서는 settlement, payout, calc 세 가지 이름으로 제각각 부르고 있었습니다. 회의만 하면 제가 "그 정산이 그 정산이 아니고요..." 하면서 통역을 했어요. 그때는 이게 원래 개발이 그런 거지 싶었는데, 나중에 보니 이 통역 비용이 프로젝트 내내 조용히 새어 나가는 손실이더라고요.

 

 

💡 유비쿼터스 언어의 진짜 효과


단어를 통일하면 회의 시간이 줄어드는 게 아니라,

오해가 코드에 박히는 걸 막아줍니다.

현업이 "취소"라고 하는데 개발자가 "삭제"로 구현하면,

나중에 환불 로직 전체가 틀어집니다.

용어를 맞추는 건 문서 정리가 아니라 버그 예방입니다.

 

3. 바운디드 컨텍스트 - 경계를 긋는다는 것

유비쿼터스 언어를 하다 보면 벽에 부딪힙니다. 회사 전체가 쓰는 단어를 하나로 통일하는 게 불가능하다는 거예요. 같은 "상품"이라는 단어도 판매팀이 보는 상품과 물류팀이 보는 상품, 정산팀이 보는 상품이 전부 다릅니다.

그래서 나온 개념이 바운디드 컨텍스트(Bounded Context)입니다. "이 경계 안에서는 이 단어가 이 뜻이다"라고 선을 긋는 거죠. 주문 컨텍스트 안의 상품과 배송 컨텍스트 안의 상품은 다른 모델로 취급합니다. 억지로 하나로 합치지 않고요. 저는 이 개념을 처음 이해했을 때, 그동안 우리가 만든 거대한 공통 모델이 왜 그렇게 손대기 무서웠는지 알게 됐습니다. 모두가 공유하는 하나의 Product 클래스는, 한 군데를 고치면 어디가 터질지 아무도 모르는 지뢰밭이었거든요.

4. 전략적 설계와 전술적 설계

DDD는 크게 두 층으로 나뉩니다. 큰 그림을 그리는 전략적 설계, 그리고 코드 안을 구현하는 전술적 설계입니다. 이걸 헷갈리면 "DDD = 엔티티랑 리포지토리 만드는 것" 정도로 좁게 오해하게 됩니다.

반응형
구분 전략적 설계 전술적 설계
관심사 어디에 선을 그을 것인가 경계 안을 어떻게 구현할 것인가
대표 개념 유비쿼터스 언어, 바운디드 컨텍스트, 컨텍스트 맵 엔티티, 값 객체, 애그리거트, 리포지토리, 도메인 이벤트
실무 질문 "어디까지가 주문이고 어디부터 결제인가" "이 객체를 어떻게 저장하고 불변으로 지킬까"

전술적 설계 쪽 용어들은 처음 보면 낯선데, 하나씩 뜯어보면 이미 다 쓰고 있던 것들입니다.

  • 엔티티(Entity) - 고유 식별자로 구분되는 객체. 이름이 바뀌어도 같은 회원인 그 회원
  • 값 객체(Value Object) - 식별자 없이 값 자체로만 의미 있는 것. 금액, 주소, 좌표 같은 것들
  • 애그리거트(Aggregate) - 함께 다뤄야 하는 객체 묶음. 주문과 주문 항목처럼 항상 세트로 움직이는 단위
  • 리포지토리(Repository) - 애그리거트를 저장하고 꺼내오는 통로. DB 접근을 도메인에서 떼어내는 역할
  • 도메인 이벤트(Domain Event) - "주문이 완료됐다" 같은 사건. 컨텍스트끼리 느슨하게 연결할 때 씁니다

참고로 후대의 실무 적용은 본 반 버논(Vaughn Vernon)이 2013년에 쓴 책이 많이 채웠습니다. 에반스가 개념을 세웠다면, 그걸 코드로 어떻게 옮길지는 이쪽이 훨씬 친절합니다.

5. DDD와 마이크로서비스는 왜 붙어 다니나

DDD를 검색하면 마이크로서비스(MSA)가 거의 세트로 따라옵니다. 이유는 간단해요. 바운디드 컨텍스트가 서비스를 어디서 쪼갤지에 대한 가장 그럴듯한 답을 주기 때문입니다.

MSA를 하다 보면 제일 어려운 게 "서비스를 몇 개로, 어디서 나눌 것인가"입니다. 기술로 나누면 안 되고 업무로 나눠야 하는데, 그 업무 경계를 잡는 게 바로 컨텍스트를 긋는 일이거든요. 그래서 DDD의 바운디드 컨텍스트를 서비스 경계로 그대로 가져다 쓰는 경우가 많습니다. 다만 이 둘이 항상 1대 1은 아니라는 점은 짚어둘게요. 컨텍스트 하나가 서비스 여러 개일 수도, 그 반대일 수도 있습니다.

그리고 여기서부터가 이 글의 진짜 하고 싶은 이야기입니다. 바로 이 "쪼개기"가 속도의 양면성을 만듭니다.

6. DDD는 멀티스레드를 닮았습니다

싱글스레드로 도는 프로그램을 생각해 봅시다. 일을 순서대로 하나씩 처리하니까 구조가 단순하고, 스레드 간에 뭘 맞출 필요가 없습니다. 일이 작으면 이게 제일 빠릅니다. 오버헤드가 없으니까요.

멀티스레드는 다릅니다. 일을 쪼개서 동시에 굴리니까, 코어가 많고 일이 크면 비약적으로 빨라집니다. 그런데 공짜가 아니죠. 락 경합, 컨텍스트 스위칭, 동기화 비용이 붙습니다. 일이 작으면 이 부대비용이 병렬화 이득보다 커서, 멀티스레드가 오히려 더 느려지는 역전이 일어납니다. 스레드 만드는 값도 안 나오는 거예요.

 

 

📌 대응 관계로 보면 이렇습니다


- 바운디드 컨텍스트 = 스레드 (일을 나눠 병렬로 굴리는 단위)
- 컨텍스트 간 통합, 도메인 이벤트, 안티커럽션 레이어 = 동기화 비용, 락
- 큰 도메인 + 여러 팀 = 코어가 많은 상황 → 비약적으로 빨라짐
- 작은 도메인 + 소수 인원 = 코어 부족 → 오버헤드가 이득을 잡아먹음

 

 

DDD로 도메인을 잘게 나눠두면, 팀별로 자기 컨텍스트만 붙잡고 병렬로 개발할 수 있습니다. 서로 코드를 안 건드려도 되니까 충돌이 줄고, 각 팀이 자기 속도로 달립니다. 이게 제대로 물리면 확실히 빠릅니다. 저도 규모 있는 서비스에서 컨텍스트가 잘 갈린 팀이 얼마나 거침없이 나가는지 봤어요.

문제는 이 이득이 "일을 쪼갤 만큼 크고, 그 쪼갠 조각을 각각 붙잡을 사람이 있을 때"만 나온다는 겁니다.

7. 속도가 빨라지는 대신 사람이 늘어난다

멀티스레드 비유의 마지막 조각이 이겁니다. 스레드를 여러 개 만들어도 코어가 하나면 결국 한 코어가 스레드들을 번갈아 처리합니다. 컨텍스트 스위칭만 늘고 진짜 병렬은 안 되죠.

DDD도 똑같습니다. 컨텍스트를 여덟 개로 나눠놨는데 개발자가 두 명이면, 한 명이 컨텍스트 네 개를 오가며 붙잡아야 합니다. 이 사람 머릿속에서 컨텍스트 스위칭이 계속 일어나요. 경계마다 규칙이 다르고 모델이 다르니까, 왔다 갔다 하는 것만으로 피로가 쌓입니다. 결과적으로 나눠놓은 게 이득이 아니라 짐이 됩니다.

그러니까 DDD로 속도를 뽑아내려면 절대적인 인원이 늘어날 수밖에 없는 구조입니다. 병렬화의 이득은 그 병렬을 실제로 소화할 사람이 있어야 실현되니까요. 저는 이 지점을 오래 오해했습니다. DDD를 잘 하면 적은 인원으로도 빨라진다고 생각했는데, 실제로는 "쪼갤 수 있게 만들어두고, 사람을 붙여서, 병렬로 태우는" 조합이 맞아떨어질 때 빨라지는 거였어요.

MSA로 서비스를 여러 개로 갈랐던 어느 프로젝트에서, 경계를 잘못 잡은 탓에 서비스끼리 서로를 계속 호출하는 구조가 된 적이 있습니다. 부산 쪽에 트러블슈팅하러 내려가서 로그를 까보니, 한 요청이 서비스 대여섯 개를 왕복하고 있더라고요. 이게 딱 락 경합이었습니다. 나눠서 빨라지라고 만든 구조가, 나눈 조각들이 서로 물려서 더 느려진 상황이요.

8. 작은 프로젝트에 풀세트로 넣었다가 데인 이야기

제 5년 차 전후는 설계에 좀 집착하던 시기였습니다. 웹소켓, NoSQL, 도커 이것저것 파던 무렵인데, 설계도 멋있게 하고 싶었어요. 그때 규모가 크지 않은 프로젝트에 애그리거트, 리포지토리, 도메인 이벤트, 안티커럽션 레이어까지 교과서 그대로 다 넣어봤습니다.

결과는 별로였습니다. 단순 CRUD면 끝날 화면 하나 만드는 데 파일이 열 몇 개씩 생겼고, 팀원들이 "이거 어디를 고쳐야 하냐"고 계속 물었어요. 도메인이 그렇게까지 복잡하지도 않은데 구조만 무거웠던 겁니다. 싱글스레드로 순서대로 짜면 반나절이면 될 걸, 멀티스레드 프레임 씌우느라 이틀을 쓴 셈이죠. 그때는 이게 정석이라고 우겼는데, 지금 돌아보면 명백한 오버엔지니어링이었습니다.

 

 

💡 그때 깨달은 것


DDD의 전술 패턴은 도메인이 복잡할 때 복잡함을 관리하는 도구입니다.

도메인이 안 복잡하면, 그 도구 자체가 새로운 복잡함이 됩니다.

관리할 복잡성이 없는데 관리 장치만 얹은 꼴이죠.

 

9. 그래서 언제 도입해야 하나

정답은 없지만, 제가 지금 판단할 때 보는 기준을 정리해 보겠습니다. 확실한 공식은 아니고 어디까지나 제 경험에서 나온 감각입니다.

 

📌 DDD가 값을 하는 조건


- 도메인 규칙 자체가 복잡하다 (금융, 정산, 보험, 물류처럼)
- 오래 살아남아야 하는 서비스다 (몇 년 굴릴 제품)
- 사람이 여럿이거나 팀이 나뉜다 (병렬로 태울 코어가 있다)
- 현업과 개발이 자주 대화한다 (유비쿼터스 언어가 굴러갈 토양)

 

 

반대로 도메인이 단순한 관리자 페이지, 짧게 쓰고 버릴 프로토타입, 혼자 또는 두세 명이 빠르게 쳐내야 하는 프로젝트라면, 저는 굳이 풀세트를 권하지 않습니다. 유비쿼터스 언어나 값 객체 정도만 가볍게 챙기고 나머지는 안 넣는 편이 낫습니다. 전략적 설계의 태도만 빌려오고 전술 패턴은 접어두는 거죠.

마무리

DDD를 두고 좋다 나쁘다로 답하는 게 애초에 틀린 질문이라고 생각합니다. 멀티스레드가 좋냐 나쁘냐고 물으면 "일에 따라 다르다"고 답할 수밖에 없는 것처럼요. DDD도 그렇습니다. 복잡한 도메인을 여러 사람이 오래 다뤄야 한다면 속도를 크게 끌어올려 주지만, 그 이득은 쪼갠 조각을 붙잡을 인원이 있을 때 비로소 실현됩니다. 규모가 작으면 오히려 발목을 잡고요.

그러니 도입을 고민 중이라면, 책의 패턴을 얼마나 정확히 따라 할지보다 "우리 도메인이 정말 이만큼 복잡한가", "이걸 병렬로 태울 사람이 있는가"를 먼저 따져보시길 권합니다. 도구는 문제 크기에 맞춰 고르는 거니까요. 저도 여기까지 오는 데 잘못 넣어보고 데이는 시간이 꽤 걸렸습니다.

🎲 개발은전투다 블로그 추천 세트

 

레드마인 vs 지라, 무료 유료 따지기 전에 팀부터 봐야 하는 이유

레드마인과 지라(Jira)는 개발 팀에서 가장 많이 쓰는 협업툴이자 이슈 트래커입니다. 하나는 무료 오픈소스고 하나는 유료 구독이라, '무료 레드마인 vs 유료 지라' 비교 글은 검색하면 끝도 없이

devwar.tistory.com

 

Jira도 Redmine도 써봤지만 결국 Notion으로 정착한 이유 (협업툴 도입 실패와 교훈)

"협업툴 뭐 써요? Jira? Redmine?""이슈 트래커 도입했는데 왜 아무도 안 쓰죠?""기능은 좋다는데 막상 우리 팀엔 안 맞던데요." 협업툴을 한 번이라도 직접 도입해 본 분이라면 공감하실 겁니다.좋다

devwar.tistory.com

 

깃(Git)과 깃허브(GitHub) 차이, 깃 호스팅 4대장 정리 (feat. 죽다 살아난 CodeCommit)

개발 공부를 시작하면 깃(Git)과 깃허브(GitHub)라는 단어를 거의 매일 만나게 됩니다. 둘은 비슷해 보이지만 사실 다른 물건이고, 여기에 깃랩(GitLab), 비트버킷(Bitbucket), AWS 코드커밋(CodeCommit)까지

devwar.tistory.com

 

트렐로(Trello) 칸반보드, 도요타 공장에서 시작된 무료 협업 도구의 역사와 실전 활용법

트렐로(Trello)는 보드·리스트·카드 세 가지만으로 할 일과 일정을 눈에 보이게 정리하는 무료 프로젝트 관리 도구입니다. 2011년에 나온 칸반보드 기반의 협업 툴인데, 13년 동안 현장에서 이런저

devwar.tistory.com

 

[프로젝트 관리] 돈 쓰지 마세요! 무료 끝판왕 '레드마인(Redmine)' 완벽 가이드 (Jira와 비교 분석)

레드마인(Redmine)은 서버에 직접 설치해서 쓰는 무료 오픈소스 프로젝트 관리 도구입니다. 이슈 추적, 간트 차트, 위키, 시간 기록까지 프로젝트에 필요한 기능을 인원 제한 없이 공짜로 제공하죠

devwar.tistory.com

반응형