다른 개발자분께서 도메인이 무엇이냐 라고 물어볼 때 정확히
답변을 하지 못해 공부하면서 다른 개발자분들에게도
알려주기 위해 정리하였습니다.
다른 개발자들과 대화하거나 아키텍처 관련 책을 읽을 때 "도메인" 이라는 단어를 자주 들엇습니다.
"도메인 레이어를 분리해야 합니다.", "도메인 모델에 비즈니스 로직을 모으세요.", "그건 도메인이 아니라 인프라 영역입니다."
대충 '비즈니스 로직이 들어가는 곳이네..' 하고 넘어가기는 했지만, 최근에 누군가 "그래서 도메인이 정확히 무엇인데?" 라고 물어보면 말문이 턱 막혔습니다.
따라서 오늘 이 글을 통해 소프트웨어 공학에서 말하는 도메인(Domain) 의 진짜 의미부터 시작해서, 왜 이 개념을 뼛속까지 이해해야 '지속 가능한 좋은 코드' 를 짤 수 있는지 아주 깊게 정리해 보았습니다.
도메인(Domain) 의 진짜 정의 - URL 이 아니라!
소프트웨어 공학에서의 도메인은 가장 먼저 떠오르는 주소창 도메인(naver.com) 이 아니라, 다음과 같습니다.
"소프트웨어가 해결하고자 하는 현실 세계의 비즈니스 문제 영역"
쉽게 말해, "당신이 지금 만들고 있는 프로그램이 현실의 어떤 문제를 해결하기 위한 것인가?" 에 대한 답이 바로 도메인입니다.
현실 세계의 예시로 이해하기
우리가 매일 사용하는 서비스들을 도메인 관점으로 쪼개보겠습니다.
- 배달의 민족
현실 세계의 '음식 주문, 가게 관리, 배달 라이더 매칭, 결제' 라는 문제를 해결합니다.
따라서 배달의민족 개발자들에게 도메인은 주문, 결제, 정산, 라이더, 메뉴 등이 됩니다.
- 토스
현실 세계의 '금융/자산 관리, 복잡한 송금' 문제를 해결합니다.
이들의 도메인은 송금, 계좌 ,신용도, 펀드, 대출이 됩니다.
- 네이버 웹툰
현실 세계의 '컨텐츠 소비, 작가 정산, 독자 관리' 문제를 해결합니다.
이들의 도메인은 웹툰, 회차, 유료쿠키, 작가, 댓글이 됩니다.
즉, 개발자들이 출근해서 인텔리제이( 혹은 이클립스 ) 를 켜고 작성하는 코드 중에서 "우리 회사가 돈을 벌기 위해 정의한 비즈니스 규칙" 을 다루는 영역이 모두 도메인에 해당됩니다.
왜 도메인이 소프트웨어의 중심이어야 할까?
"그냥 기능만 잘 돌아가면 되지, 왜 굳이 '도메인' 이라는 단어를 써가며 강조할까요?"
이를 이해하려면 과거 우리가 코딩했던 방식(데이터 중심 설계) 의 한계를 알아야 합니다.
과거의 방식: 데이터베이스(DB) 중심 설계
옛날(혹은 지금도 많은 곳에서) 서비스를 만들 때 가장 먼저 하는 일은 "DB 테이블 설계" 였습니다.
1. ORDERS 테이블을 만들고, ORDER_STATUS 컬럼 만들고..
2. 스프링에서 OrderVO 나 OrderDto 같은 데이터 껍데기를 만든 뒤..
3. OrderService 에서 모든 비즈니스 로직을 if-else 문으로 길게 짜고..
이 방식의 치명적인 단점은 비즈니스가 복잡해지면서 코드가 썩어 들어간다는 점입니다.
기획서에 "주문 취소는 배송 전에만 가능하다" 라는 규칙이 추가되면, OrderService 에 수백 줄짜리 스파게티 코드가 생기게 됩니다.
시간이 지나면 기획자가 "우리 서비스 로직이 지금 어떻게 되어 있나요?" 라고 물었을 때, 아무도 대답하지 못하고 쿼리문과 서비스 코드 수천 줄을 헤집고 다녀야 하는 비극이 발생하게 됩니다.
현대의 방식: 도메인 중심 설계
그래서 현대 아키텍처(DDD) 는 외치게 됩니다.
"DB 나 프레임워크는 껍데기일 뿐이다. 소프트웨어의 본질은 도메인(비즈니스)이다!!"
소프트웨어가 복잡해져도 살아남으려면, 기획자가 말하는 비즈니스 개념과 규칙이 코드(도메인 모델) 에 그대로 반영되어 있어야 합니다. 기획자가 "배송 후에는 취소 불가" 라고 하면, 코드에서도 Order.cancle() 메서드 안에 그 규칙이 정확히 한 곳에 명시되어 있어야 한다는 뜻입니다.
도메인(Domain) vs 인프라(Infrastructure)
도메인을 선명하게 이해하는 가장 좋은 방법은 "도메인이 아닌 것" 과 비교해 보는 것입니다.
소프트웨어는 크게 도메인 영역과 인프라 기술 영역으로 나뉩니다.
도메인 영역(Domain)
핵심 질문 : 우리 비즈니스의 규칙이 무엇인가?
관심사 : 주문, 결제, 환불, 회원상태, 할인 조건
변화 : 비즈니스 정책 변경( 할인율 10% → 할인율 15% )
인프라 영역(Infrastructure)
핵심 질문 : 그 규칙을 어떤 기술로 실현할 것인가?
관심사 : Spring, MySQL, Redis, AWS, HTTP
변화의 원인 : 기술적 필요 ( Oracle 에서 MySQL 로 마이그레이션 )
"만약 내일 당장 스프링 플러그인을 다 뽑아버리고, DB 도 안 쓰고 메모리에만 데이터를 저장하도록 프로그램을 바꾼다면, 내 코드에서 살아남아야 하는 핵심 로직은 무엇인가?"
그때도 여전히 살아남아 수식과 조건을 계산하고 있어야 하는 코드, 그게 바로 도메인입니다.
반면 스프링 프렝미워크 JPA, Controller, 쿼리문 등은 도메인을 도와주는 인프라에 불과합니다.
도메인을 더 깊게: 3가지 도메인
도메인은 단 한 덩어리로 존재하지 않습니다.
서비스가 커지면 도메인도 성격에 따라 쪼개지는데, 시니어들과 아키텍처를 논할 때 필수적인 개념이 바로 하위 도메인의 3가지 분류입니다. 배달 앱 서비스를 만든다고 가정하고 아래와 같이 3가지로 분석하였습니다.
핵심 도메인(Core Domain)
우리 회사의 가장 경쟁력 있고, 가장 돈을 잘 벌어다 주는 핵심 영역입니다.
절대 외주를 주면 안되고, 사내에서 가장 뛰어난 개발자들이 투입되어야 하는 곳이기도 합니다.
배달 앱에서의 '가게 추천 알고리즘', '효율적인 라이더 매칭 시스템' 이 해당될 수 있다고 봅니다.
지원 도메인(Supporting Domain)
핵심 도메인을 도와주기 위해 필수적이긴 하지만, 그 자체로 차별성을 가지지는 않는 영역입니다.
비즈니스 정체성에 꼭 필요하므로 직접 구현하는 경우가 많습니다. 예를 들어 '메뉴판 등록/관리' 를 말할 수 있습니다.
일반 도메인(Generic Domain)
비즈니스에 꼭 필요하지만, 이미 세상에 좋은 솔루션이 널리 있어서 우리가 밤새워 직접 개발할 필요가 없는 영역입니다.
오픈소스를 쓰거나 외부 SaaS 서비스를 사서 쓰는게 이득인 영역이기도 합니다. '본인인증', '알림톡 발송' 등이 해당됩니다.
자바 코드로 보는 도메인의 변화: 빈약 vs 풍부
개발 공부는 직접 코드를 짜고 봐야한다는 말이 백문이 불여일견이라고 백엔드 개발자라면 코드로 봐야 완벽히 이해가 갑니다.
제가 생각하기에 주니어들이 가장 많이 실수하는 패턴과 이를 도메인 중심으로 리팩토링한 코드를 비교해 보겠습니다.
안좋은 예시: 빈약한 도메인
많은 주니어들이 JPA @Entity 를 만들때 아무 생각 없이 Getter/Setter 를 기계적으로 생성하게 됩니다.
저도 그랬었습니다. 이로 인해 비즈니스 로직이 서비스 레이어에 절절 흐르는 절차지향적 코드가 완성되게 됩니다.
// 1. 도메인 객체가 그저 '데이터 껍데기' 역할만 함 (빈약한 모델)
@Entity
@Getter @Setter
public class Order {
@Id @GeneratedValue
private Long id;
private OrderStatus status; // START, SHIPPED, CANCELED 등
private int totalAmount;
}
// 2. 서비스 레이어 (뚱뚱한 서비스 - 모든 비즈니스 로직을 감당함)
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
@Transactional
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new IllegalArgumentException("주문이 없습니다."));
// 🚨 비즈니스 규칙이 도메인이 아닌 서비스에 들어있음!
// "이미 배송된 주문은 취소할 수 없다"는 중요 규칙이 여기에 숨겨져 있음.
if (order.getStatus() == OrderStatus.SHIPPED) {
throw new IllegalStateException("이미 배송된 주문은 취소할 수 없습니다.");
}
order.setStatus(OrderStatus.CANCELED); // Setter를 통해 외부에서 상태를 막 바꿈
}
}
무엇이 문제일까?
Order 객체는 스스로 할 수 있는 게 아무것도 없는 수동적인 존재입니다.
"배송된 주문은 취소 불가" 라는 비즈니스 규칙을 알고 싶으면 OrderService 코드를 다 뒤져야 합니다.
다른 서비스(AdminOrderService) 에서 취소 기능을 만들면 똑같은 if 문이 복사/붙여넣기 됩니다.
즉, 도메인의 응집도가 깨진 상태라고 볼 수 있습니다.
좋은 예시: 풍부한 도메인 모델
비즈니스 규칙을 도메인 객체 내부로 꽁꽁 숨겨(캡슐화) 객체지향적인 도메인 모델을 만든 코드입니다.
// 1. 스스로 비즈니스 규칙을 통제하는 '풍부한 도메인 모델'
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Order {
@Id @GeneratedValue
private Long id;
private OrderStatus status;
private int totalAmount;
// 🔒 Setter를 폐쇄하고 비즈니스 의도가 드러나는 생성자/메서드만 노출
public void cancel() {
// ✨ "내 상태는 내가 관리한다!" 도메인 규칙을 스스로 검증
if (this.status == OrderStatus.SHIPPED) {
throw new IllegalStateException("이미 배송된 주문은 취소할 수 없습니다.");
}
this.status = OrderStatus.CANCELED;
}
}
// 2. 서비스 레이어 (얇은 서비스 - 오케스트레이터 역할만 수행)
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
@Transactional
public void cancelOrder(Long orderId) {
// 1. 데이터 로드
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new IllegalArgumentException("주문이 없습니다."));
// 2. 도메인 객체에게 핵심 비즈니스 로직(메시지)을 위임
order.cancel();
// 3. 서비스는 흐름만 제어할 뿐, 비즈니스 규칙이 어떻게 되는지는 알 필요가 없음!
}
}
리팩토링 후 얻은 이점
주문 최소와 관련된 핵심 규칙이 Order 클래스 딱 한 곳에 모여있습니다.
기획이 바뀌면 이 클래스만 수정하면 됩니다.
또한 order.setStatus() 로 상태를 마음대로 조작할 수 없으므로 버그가 예방됩니다.
마무리하면서..
소프트웨어 공학에서 도메인이란 배달, 금융, 쇼핑몰처럼 우리가 소프트웨어로 해결하고자 하는 현실 세계의 문제 영역 그 자체를 의미한다고 볼 수 있습니다.
스프링 프레임워크가 제공하는 멋진 기능들(@Autowired, @Transactional) 은 결국 이 모데인 로직이 안전하고 편리하게 돌아가도록 뒤에서 받쳐주는 '기술 인프라' 라고 생각합니다. 기술의 화려함에 매몰되어 정작 본질인 비즈니스 도메인을 허술하게 짜게 된다면, 그 시스템은 금방 무너지게 될 것입니다. 앞으로 코드를 짤 때 "이 코드는 순수한 비즈니스(도메인) 인가, 아니면 기술(인프라) 인가?" 를 끊임없이 질문하고 이 질문에 스스로 답할 수 있게 되는 순간, 주니어를 넘어 시니어의 길로 접어들수 있다고 생각하며 그러한 개발자가 되기 위해 저 포함 다들 노력하면 좋겠습니다.
'Java' 카테고리의 다른 글
| [ 주니어 탈출기 ] "인터페이스랑 뭐가 다를까?" - abstract 의 활용법 (0) | 2026.05.28 |
|---|---|
| 1급 컬렉션 (0) | 2026.05.26 |
| 좌충우돌 원격 서버 배포 및 Jenkins CI/CD 구축기 (0) | 2026.04.28 |
| 빈 검증에 대하여 (1) | 2026.03.23 |
| 필터와 인터셉터 (0) | 2026.03.16 |