초보 개발자가 DDD를 배워야 하는 이유는 무엇일까?

2026. 7. 10. 21:32Dev & Tech/Etc

반응형

초보 개발자가 DDD를 배워야 하는 이유는 무엇일까?

"이 코드, 대체 어디서부터 손대야 하지?" 개발을 시작한 지 얼마 안 됐다면 한 번쯤 이런 생각을 해보셨을 겁니다. 분명 기능은 잘 동작하는데, 코드를 열어보면 검증 로직과 저장 로직, 알림 로직이 한 함수 안에 뒤섞여 있고, 어디를 고쳐야 할지 감이 안 오는 경우 말이죠.

DDD(Domain-Driven Design, 도메인 주도 설계)는 바로 이런 상황을 미리 막아주는 설계 방식입니다. 이름은 거창해 보이지만, 원리를 알고 나면 생각보다 단순합니다.

이번 글에서는 어려운 용어 없이, 왜 DDD를 배워야 하는지부터 어떻게 시작하면 되는지까지 차근차근 풀어보겠습니다. 이미 알고 계신 개념이 나오더라도, 비유를 통해 한 번 더 짚어보면서 읽어주시면 좋겠습니다.
목차
1. DDD를 모르면 어떤 문제가 생길까
2. DDD를 쓰면 무엇이 달라질까
3. 비유로 쉽게 이해하는 DDD의 핵심 원리
4. 지금 바로 시작할 수 있는 DDD 학습법

#1. DDD를 모르면 어떤 문제가 생길까
1) 신입 개발자가 흔히 겪는 상황
처음 실무 코드를 접하면 흔히 겪는 패턴이 있습니다. 주문 취소 기능 하나를 만드는데, 컨트롤러에서 바로 데이터베이스를 조회하고, 조건문으로 이것저것 검사하고, 다시 저장하는 코드를 한 메서드 안에 전부 몰아넣는 방식입니다. 처음에는 빠르고 편해 보이지만, 기능이 하나둘 늘어날수록 이 메서드는 점점 거대해지고 손대기 무서운 코드가 됩니다.
(1) 이런 코드가 반복되면 생기는 일
① 비슷한 검증 로직이 여러 파일에 복사·붙여넣기되면서 중복됩니다.

② 하나를 고치면 예상 못 한 다른 기능이 깨지는 일이 반복됩니다.

③ 새로운 팀원이 들어와도 코드만 봐서는 무슨 업무를 하는 코드인지 파악하기 어렵습니다.
· · · · ·
2) 왜 이런 문제가 생길까
근본 원인은 대부분 데이터 중심으로만 설계했기 때문입니다. 데이터베이스 테이블 구조를 그대로 클래스로 옮기고, 그 데이터를 다루는 로직은 전부 서비스 클래스에 절차적으로 나열하는 방식이죠. 이렇게 하면 '데이터'와 '그 데이터를 다루는 규칙'이 서로 다른 곳에 떨어져 있게 되고, 시간이 지날수록 둘 사이의 연결고리를 추적하기가 점점 힘들어집니다.
(1) 이름이 코드와 따로 노는 문제
기획자는 "주문을 취소한다"고 말하는데, 코드에는 deleteOrder, removeOrder, updateOrderStatus 같은 서로 다른 이름의 메서드가 여기저기 흩어져 있는 경우도 흔합니다. 이렇게 되면 새 기능을 요청받을 때마다 "이게 정확히 어떤 코드를 말하는 거지?"라는 되물음이 반복되고, 소통 비용이 눈에 띄게 늘어납니다.
(2) 신입 개발자가 특히 힘들어하는 이유
경력이 쌓인 개발자는 이런 코드도 감으로 어느 정도 파악하지만, 이제 막 실무를 시작한 신입 개발자에게는 이런 구조가 진입 장벽 그 자체입니다. "이 조건문은 왜 여기 있는 거지?", "이 메서드를 고치면 어디가 영향을 받지?" 같은 질문에 답할 실마리가 코드 어디에도 명확히 드러나 있지 않기 때문입니다.
(3) 결국 시간과 비용으로 돌아온다
이런 구조가 오래 방치되면 결국 기능 하나를 추가하는 데 걸리는 시간이 점점 길어지고, 버그 수정 중에 또 다른 버그가 생기는 악순환이 반복됩니다. 처음에는 사소해 보이는 설계 습관 하나가, 몇 달 뒤에는 팀 전체의 개발 속도를 갉아먹는 요인이 되는 셈입니다.
체크리스트해당 여부
서비스 클래스 하나가 300줄이 넘는다DDD 적용 검토 신호
같은 검증 로직이 여러 파일에 반복된다DDD 적용 검토 신호
기획 용어와 코드 이름이 서로 다르다DDD 적용 검토 신호
위 항목 중 하나라도 해당된다면, 지금이 DDD의 기본 개념을 배워볼 좋은 타이밍일 수 있습니다. 세 개 항목 모두에 해당한다면 더더욱 서두르시길 권해드립니다.
(1) 처음엔 완벽하지 않아도 괜찮다
표에서 여러 항목에 해당한다고 해서 당장 프로젝트 전체를 갈아엎을 필요는 없습니다. 가장 자주 바뀌고 가장 복잡한 기능 하나부터 시범 삼아 리팩터링해보고, 팀원들과 결과를 공유하면서 점진적으로 넓혀가는 방식을 추천드립니다.

#2. DDD를 쓰면 무엇이 달라질까
1) 코드가 업무를 그대로 설명해준다
DDD의 가장 큰 장점은 코드를 읽으면 업무 규칙이 그대로 보인다는 점입니다. "배송이 시작된 주문은 취소할 수 없다"는 규칙이 있다면, 이 규칙은 서비스 클래스의 조건문 속에 숨어 있는 대신 주문(Order) 객체 안에 명확한 이름의 메서드로 존재합니다.
// 규칙이 도메인 객체 안에 그대로 드러난다
public void cancel() {
  if (this.status == OrderStatus.SHIPPED) {
    throw new IllegalStateException("배송 시작 후에는 취소할 수 없습니다.");
  }
  this.status = OrderStatus.CANCELLED;
}
이 코드는 자바를 잘 모르는 기획자가 봐도 대략 무슨 규칙인지 짐작할 수 있습니다. 규칙이 코드 한 곳에 모여 있으니, 나중에 규칙이 바뀌어도 어디를 고쳐야 할지 헤맬 일이 줄어듭니다.
비교변경 전(데이터 중심)변경 후(DDD)
규칙 위치OrderService의 if문 속Order.cancel() 메서드 안
코드 읽는 느낌절차 나열, 의도 파악 어려움메서드 이름만 봐도 의도 파악
규칙 변경 시서비스 코드 전체를 뒤져야 함Order 클래스만 확인하면 됨
· · · · ·
2) 협업이 편해진다
DDD에서는 개발자와 기획자, 디자이너가 모두 같은 용어를 같은 의미로 사용하는 것을 중요하게 여깁니다. 이를 유비쿼터스 언어(공통 언어)라고 부릅니다. 회의에서 "주문 취소"라고 부르면 코드에서도 cancel이라는 이름을 그대로 사용하는 식입니다.
(1) 회의 시간이 줄어드는 이유
용어가 통일되면 "이 기능이 정확히 뭘 하는 거예요?"라고 되묻는 시간이 줄어듭니다. 신입 개발자 입장에서도 기획 문서와 코드 사이의 거리감이 줄어들어, 코드를 훨씬 빠르게 이해할 수 있습니다.
(2) 실제 대화가 어떻게 달라질까
용어가 통일되기 전에는 "그 취소 처리하는 API 좀 확인해주세요"라는 요청에 어느 API를 말하는지 한참 찾아야 하는 일이 흔합니다. 반면 용어가 통일돼 있다면 "Order.cancel() 로직 좀 확인해주세요"처럼 정확한 지점을 바로 짚을 수 있어, 커뮤니케이션 자체가 훨씬 명확해집니다.
· · · · ·
3) 변경에 강해진다
서비스는 늘 요구사항이 바뀝니다. DDD로 설계하면 로직이 여기저기 흩어져 있지 않고 관련 있는 것끼리 한곳에 모여 있기 때문에, 요구사항이 바뀌었을 때 수정할 범위가 명확해집니다. "어디를 고쳐야 하지?"라는 막막함이 크게 줄어드는 셈입니다.
· · · · ·
4) 테스트 코드를 작성하기 쉬워진다
초보 개발자가 테스트 코드 작성을 어려워하는 이유 중 하나는, 로직이 데이터베이스나 프레임워크와 뒤엉켜 있어서 독립적으로 테스트하기 어렵기 때문입니다. DDD에서는 도메인 객체가 순수한 자바 코드로만 이루어져 있어, 데이터베이스 연결 없이도 규칙이 제대로 동작하는지 바로 확인할 수 있습니다.
(1) 검증 코드 한 줄로 확인 가능
예를 들어 "배송된 주문은 취소할 수 없다"는 규칙을 테스트하고 싶다면, 데이터베이스를 띄우지 않고도 Order 객체 하나를 만들어 cancel() 메서드만 호출해보면 됩니다. 이렇게 테스트가 쉬워지면 자연스럽게 테스트를 더 자주 작성하게 되고, 결과적으로 버그도 줄어듭니다.
※ 참고: 본 설명은 에릭 에반스의 《도메인 주도 설계》 및 일반적인 실무 적용 사례를 바탕으로 쉽게 풀어 정리한 내용입니다.

#3. 비유로 쉽게 이해하는 DDD의 핵심 원리
1) 식당 주방으로 이해하는 DDD
DDD를 처음 접하면 용어가 낯설어 어렵게 느껴질 수 있습니다. 식당 주방에 비유해서 생각해보면 훨씬 쉽습니다.
(1) 재료가 아니라 요리사가 일을 한다
데이터 중심 설계는 재료(데이터)를 손님(서비스 클래스)이 직접 이것저것 손질하는 것과 비슷합니다. 반면 DDD는 각 재료마다 전담 요리사(도메인 객체)가 있어서, "이 재료로 이런 요리는 만들 수 없어요"라는 규칙을 요리사 스스로 알고 있는 구조에 가깝습니다.
만약 손님이 직접 주방에 들어가 아무 재료나 마음대로 손질한다면 어떻게 될까요? 위생 규칙도, 조리 순서도 지켜지지 않을 가능성이 큽니다. 도메인 객체가 스스로 규칙을 지키게 만드는 것은, 주방 출입을 요리사로만 제한하고 정해진 레시피대로만 움직이게 하는 것과 같은 이치입니다.
(2) 주문서 양식을 통일하는 것과 같다
유비쿼터스 언어는 주방과 홀 직원이 같은 주문서 양식과 같은 메뉴 이름을 쓰는 것과 같습니다. 홀에서는 '곱빼기'라고 부르는데 주방에서는 '특대'라고 부른다면, 매번 헷갈리고 실수가 생기기 마련이죠.
· · · · ·
2) 도메인 객체가 스스로 일한다는 것
DDD에서 가장 헷갈리는 개념 중 하나가 "객체가 스스로 일한다"는 표현입니다. 쉽게 말해, 데이터를 담고만 있는 상자가 아니라 자기 자신을 검증하고 변경하는 능력을 가진 객체를 만든다는 뜻입니다.
구분데이터 중심 설계DDD 방식
규칙이 있는 곳서비스 클래스의 조건문도메인 객체 내부 메서드
객체의 역할단순히 값을 담는 그릇스스로 규칙을 지키는 주체
규칙 변경 시여러 서비스 코드를 찾아 수정객체 안 한 곳만 수정
· · · · ·
3) 아주 간단한 예시로 보기
말로만 설명하면 와닿지 않을 수 있으니, 아주 짧은 예시를 하나 보겠습니다. 회원 이름을 저장하는 값이 있다고 해봅시다.
// 데이터 중심 방식: 이름이 비어있는지 서비스에서 매번 검사
if (name == null || name.isEmpty()) {
  throw new IllegalArgumentException("이름은 비어있을 수 없습니다.");
}

// DDD 방식: 이름 객체 스스로 규칙을 가진다
public class MemberName {
  private final String value;
  public MemberName(String value) {
    if (value == null || value.isEmpty()) {
      throw new IllegalArgumentException("이름은 비어있을 수 없습니다.");
    }
    this.value = value;
  }
}
이렇게 하면 이름 검증 규칙을 딱 한 곳에서만 관리할 수 있습니다. 프로젝트 어디에서 회원 이름을 만들더라도 이 규칙을 빠뜨릴 걱정이 없습니다.
· · · · ·
4) '경계'라는 개념도 비유로 이해하기
DDD 용어 중 바운디드 컨텍스트(Bounded Context)도 처음에는 낯설게 느껴집니다. 쉽게 말하면 "같은 단어라도 부서마다 다르게 쓸 수 있다는 걸 인정하고, 그 경계를 명확히 나누자"는 개념입니다.
(1) 같은 단어, 다른 의미
식당으로 치면 '주문'이라는 단어를 주방에서는 "어떤 요리를 만들어야 하는가"의 의미로 쓰지만, 카운터에서는 "얼마를 받아야 하는가"의 의미로 씁니다. 같은 단어인데 관심사가 다른 것이죠. DDD에서는 이런 부서(컨텍스트)별 차이를 억지로 하나로 통일하려 하지 않고, 각자의 경계를 인정한 채 설계합니다. 처음 배울 때는 이 개념까지 완벽히 이해하지 않아도 괜찮습니다. 우선은 "같은 단어도 상황에 따라 다르게 쓰일 수 있다"는 감각만 가지고 있어도 충분합니다.

#4. 지금 바로 시작할 수 있는 DDD 학습법
1) 처음부터 완벽하게 하려 하지 않기
DDD를 처음 접하면 애그리거트, 바운디드 컨텍스트 같은 용어에 압도되기 쉽습니다. 하지만 처음부터 모든 개념을 완벽히 적용하려 할 필요는 없습니다. 우선은 "데이터를 검증하는 로직을 해당 데이터를 가진 객체 안으로 옮긴다"는 것부터 시작해도 충분합니다.
· · · · ·
2) 추천하는 학습 순서
작은 기능 하나를 골라 리팩터링해보기 - 지금 있는 프로젝트에서 검증 로직이 서비스 클래스에 있는 부분을 도메인 객체로 옮겨보는 것부터 시작합니다.

엔티티와 값 객체의 차이 이해하기 - 식별자가 있는지 없는지만 구분해도 절반은 이해한 것입니다.

작은 토이 프로젝트에 전체 구조 적용해보기 - Controller, Application Service, Domain, Repository로 나눠보는 연습을 합니다.

팀 스터디나 코드 리뷰를 통해 다른 사람의 시선으로 검증받기 - 혼자 적용하다 보면 놓치는 부분이 많아, 함께 리뷰하는 과정이 큰 도움이 됩니다.
단계목표기간 가이드
1단계검증 로직을 도메인 객체로 옮겨보기1~2주
2단계엔티티·값 객체 구분 연습1~2주
3단계토이 프로젝트에 계층 구조 적용2~4주
4단계실무 코드에 부분 적용 및 리뷰지속적으로
표에 적힌 기간은 어디까지나 참고용 가이드일 뿐, 개인 학습 속도와 프로젝트 상황에 따라 얼마든지 달라질 수 있습니다. 중요한 것은 순서를 건너뛰지 않고 차근차근 밟아가는 것입니다.
(1) 참고하면 좋은 자료
① 에릭 에반스의 원저 《도메인 주도 설계》 - DDD의 뿌리가 되는 책으로, 다소 두껍고 어렵게 느껴질 수 있어 처음부터 완독하기보다는 필요할 때 찾아보는 사전처럼 활용해도 좋습니다.

② 본 볼드윈 등이 쓴 《도메인 주도 설계 구현》 계열의 실전서 - 원저보다 실무 코드 예시가 많아 초보자가 접근하기 상대적으로 수월합니다.

③ 사내·사외 스터디 - 혼자보다는 같이 코드를 리뷰해줄 동료가 있을 때 학습 속도가 훨씬 빨라집니다.
· · · · ·
3) 흔한 오해와 주의할 점
(1) DDD는 특정 프레임워크가 아니다
DDD는 스프링(Spring)처럼 설치하는 라이브러리가 아니라 설계에 대한 사고방식입니다. 어떤 언어나 프레임워크를 쓰든 적용할 수 있습니다.
(2) 작은 프로젝트에 무리하게 적용하지 않기
단순한 게시판이나 개인 토이 프로젝트에 4계층 구조를 무리하게 적용하면 오히려 배보다 배꼽이 커지는 상황이 될 수 있습니다. 우선은 개념을 익히는 데 의의를 두고, 실제 현업 프로젝트에서는 도메인 복잡도를 보고 판단하시길 권해드립니다.
(3) 완벽한 정답은 없다
DDD 관련 자료마다 세부적인 구현 방식이 조금씩 다릅니다. 원칙(관심사 분리, 도메인 로직 응집)만 지킨다면 팀 상황에 맞게 구조를 유연하게 조정해도 괜찮습니다.
· · · · ·
4) 처음 배울 때 자주 헷갈리는 지점
DDD를 공부하다 보면 몇 가지 질문이 반복해서 떠오릅니다. 여기서 미리 짚어보면 앞으로 학습이 한결 수월해질 것입니다.
스프링 없이도 DDD를 쓸 수 있는지 궁금해하는 분들이 많은데, 언어나 프레임워크와 무관하게 적용 가능한 개념이라 자바가 아닌 다른 언어로도 똑같이 활용할 수 있습니다. 또한 데이터베이스 테이블 구조와 도메인 객체 구조가 반드시 똑같아야 하는지 궁금해하는 경우도 많은데, 오히려 도메인 객체는 업무 규칙에 맞게, 테이블은 저장 효율에 맞게 서로 다르게 설계되는 경우가 흔합니다. 이 둘을 서로 변환해주는 역할을 리포지토리 구현체가 담당합니다.

마무리
DDD는 처음 들으면 어려운 이론처럼 느껴지지만, 결국 핵심은 단순합니다. 데이터와 그 데이터를 다루는 규칙을 한곳에 모아, 코드만 봐도 업무를 이해할 수 있게 만드는 것입니다. 신입 개발자일수록 이런 습관을 일찍 들이면, 나중에 복잡한 프로젝트를 맡았을 때 훨씬 수월하게 적응할 수 있습니다.

처음부터 애그리거트, 바운디드 컨텍스트 같은 용어를 완벽히 외우려 하지 않아도 괜찮습니다. "이 규칙은 누구의 책임인가?"라는 질문 하나만 습관처럼 던져봐도, 이미 DDD적인 사고를 시작한 것입니다.

오늘부터 거창한 아키텍처를 새로 짜려 하기보다, 지금 작성 중인 코드에서 검증 로직 하나를 도메인 객체 안으로 옮겨보는 것부터 시작해보시길 권해드립니다. 작은 실천이 쌓이면 어느새 DDD의 사고방식이 몸에 배어 있을 것입니다.
긴 글 읽어주셔서 감사합니다.


끝.


반응형