안녕하세요. 2025년을 준비 중인 개발자 stark입니다!
이번 포스팅에서는 '유비쿼터스 언어'에 대해 설명드리고자 합니다. 이 포스팅은 유비쿼터스 언어를 사용하는 DDD(Domain-Driven Design)에 대해 이해를 하고 오셨다고 가정하고 글이 작성되었습니다. 그래도 혹시 모르니 정말 간단히 설명드리자면 DDD는 '복잡한 도메인 문제'를 해결하기 위한 '설계 철학'으로, 개발팀과 비즈니스 팀 간의 긴밀한 협업을 강조합니다. 그 핵심 요소 중 하나가 바로 유비쿼터스 언어(Ubiquitous Language)입니다.
1. DDD에서 유비쿼터스 언어가 필요한 이유
유비쿼터스 언어는 팀원들의 '협업'과 '의사소통'의 중심이 됩니다.
소프트웨어 개발 과정에서 가장 흔한 문제 중 하나는 도메인 전문가와 개발자 간의 언어적 단절입니다. 도메인 전문가는 비즈니스 용어를, 개발자는 기술적 용어를 사용하면서 중요한 정보가 누락되거나 잘못 전달되기 쉽습니다.
예를 들어, 비즈니스에서 "주문"이라는 단어가 특정 상태를 의미한다고 가정해 봅시다. 이 상태를 개발자가 잘못 이해하거나 코드에서 다른 용도로 사용한다면, 이는 시스템의 버그나 비즈니스 논리의 왜곡으로 이어질 수 있습니다.
유비쿼터스 언어는 이 문제를 해결하기 위해 존재합니다. 도메인 전문가와 개발자가 같은 언어로 대화하고, 이 언어가 코드와 문서에 반영되도록 합니다. 결과적으로 다음과 같은 효과를 얻을 수 있습니다.
- 정확한 의사소통: 도메인 전문가와 개발자가 같은 단어를 동일한 의미로 사용합니다.
- 코드와 도메인의 일치: 코드가 도메인의 복잡성을 올바르게 반영하여 유지보수가 쉬워집니다.
- 도메인 지식의 누적: 팀 전체가 도메인을 명확히 이해하게 됩니다.
즉, 유비쿼터스 언어는 문제 해결의 기반입니다.
DDD의 목표는 단순히 소프트웨어를 작성하는 것이 아니라, '도메인 문제를 해결'하는 것입니다. 유비쿼터스 언어는 문제를 명확히 정의하고, 도메인 모델에 기반한 해결책을 도출하는 데 필수적입니다. 이를 통해 복잡한 비즈니스 로직도 간결하고 직관적으로 표현할 수 있습니다.
2. 기획자, 도메인 전문가, 개발자의 용어를 비교하며 이해해 봅시다.
도메인 전문가 (서점 매니저)
- "매장에서는 '예약도서'와 '주문도서'를 구분합니다."
- 예약도서: 출간 전 도서를 미리 신청하는 것
- 주문도서: 현재 매장에 없는 책을 주문하는 것
- 품절도서: 출판사에서 추가 생산 계획이 없는 도서
- 절판도서: 더 이상 출판되지 않는 도서
기획자
- "온라인 서비스에서는 용어를 이렇게 정리하면 좋겠습니다."
- '예약하기' 버튼: 출간 예정 도서에만 표시
- '주문하기' 버튼: 현재 재고 없는 도서에 표시
- '품절' 표시: 재입고 불가능한 상태 표시
- '절판' 표시: 구매 자체가 불가능한 상태 표시
개발자
- "아, 그러면 도서 상태값을 이렇게 이해하면 되겠네요."
- RESERVED: 예약도서 (출간 전 예약)
- ORDERED: 주문도서 (재고 없음)
- OUT_OF_STOCK: 품절 (재입고 불가)
- DISCONTINUED: 절판 (구매 불가)
이렇게 세 직군이 동일한 용어를 사용함으로써 다음과 같은 효과를 얻을 수 있습니다.
- 도메인 전문가의 지식이 정확히 전달되고
- 기획자가 올바른 서비스 기획을 할 수 있으며
- 개발자가 정확한 비즈니스 로직을 구현할 수 있습니다
유비쿼터스 언어는 도메인 전문가, 기획자, 개발자 사이의 소통을 하나로 만듭니다. 예를 들어 온라인 서점에서 'RESERVED'라는 상태값이 있다고 해봅시다. 도메인 전문가는 '예약도서는 출간 전에 미리 신청받는 도서'라고 설명합니다. 기획자는 '예약하기 버튼은 출간 전 도서에만 표시'하도록 기획합니다. 개발자는 'RESERVED 상태는 출간 전 예약 상태'로 구현합니다.
만약 여기서 개발자가 RESERVED를 '재고 있음'으로 잘못 해석했다면? 출간 전 도서가 구매 가능한 것처럼 잘못 구현될 수 있습니다. 유비쿼터스 언어는 이런 오해를 방지합니다. 모두가 같은 언어로 대화하고, 이 언어가 코드와 문서에 그대로 반영되어 하나의 일관된 의미를 가지게 됩니다.
3. 유비쿼터스 언어의 특징을 이해해 봅시다.
위에서 유비쿼터스 언어가 어떤 식으로 구성되는지 간단히 맛보셨을 텐데요.. 유비쿼터스 언어(Ubiquitous Language)란 도메인 전문가, 기획자, 개발자가 서로 공유하며 사용하는 공통 언어입니다. 이는 단순한 용어 사전이 아닌, 도메인의 지식을 정확히 표현하고 문제 해결을 지원하는 핵심 도구입니다.
유비쿼터스 언어의 특성을 살펴봅시다.
- 도메인 중심적: 도메인의 개념과 행동을 정확히 반영해야 합니다.
- 팀의 공유 언어: 모든 팀원이 이해하고 사용할 수 있어야 합니다.
- 코드와 문서화의 일관성: 코드, 테스트 케이스, 설계 문서에서 동일하게 표현됩니다.
온라인 쇼핑몰 도메인을 예로 들어봅시다. 아래와 같은 용어들이 사용될 것입니다.
- 상품(Product): 고객이 구매 가능한 항목.
- 주문(Order): 상품을 구매하기 위해 생성된 요청.
- 결제(Payment): 주문에 대한 금전적 거래.
- 배송(Delivery): 주문이 고객에게 전달되는 과정.
이러한 용어는 비즈니스 회의, 설계 문서, 코드에서 동일하게 사용됩니다. 예를 들어, "주문 생성"은 코드에서 createOrder 메서드로 표현될 수 있습니다.
유비쿼터스 언어와 도메인 모델
유비쿼터스 언어는 도메인 모델의 뼈대입니다. 클래스, 메서드, 속성의 이름이 유비쿼터스 언어를 기반으로 작성되어야 도메인 전문가와 개발자가 코드에 대해 자연스럽게 논의할 수 있습니다.
은행 도메인을 예시로 알아봅시다.
- 계좌(Account): 고객의 금융 활동을 기록하는 기본 단위.
- 거래(Transaction): 계좌 간의 금전 이동.
- 잔고(Balance): 계좌에 남아있는 금액.
이 개념들을 기반으로 코드를 작성하면 다음과 같이 표현할 수 있습니다.
public class Account {
private String accountId; // 계좌 ID
private double balance; // 현재 잔고
// 다른 계좌로 금액을 이체하는 메서드
public void transferTo(Account targetAccount, double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("이체 금액은 양수여야 합니다.");
}
if (this.balance < amount) {
throw new IllegalStateException("잔고가 부족합니다.");
}
this.balance -= amount; // 잔고 차감
targetAccount.deposit(amount); // 상대 계좌에 금액 추가
}
// 계좌에 금액을 입금하는 메서드
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("입금 금액은 양수여야 합니다.");
}
this.balance += amount;
}
// 현재 잔고를 조회하는 메서드
public double getBalance() {
return this.balance;
}
}
- transferTo 메서드는 "거래(Transaction)" 개념을 직접적으로 표현합니다. 이 메서드에서는 금액의 유효성 검사와 잔고 부족 상황을 처리합니다.
- deposit 메서드는 "입금"이라는 도메인 행위를 구현합니다.
- 도메인 용어(예: "계좌", "잔고", "거래")가 코드에 그대로 반영되어 있어, 코드가 도메인 모델을 정확히 표현합니다.
이를 통해 도메인 전문가와 개발자는 이 코드에 대해 쉽게 논의할 수 있습니다. 예를 들어, "이체 금액이 음수일 경우 에러가 발생해야 한다"는 비즈니스 규칙이 코드에서도 명확히 반영됩니다.
4. 지속적인 지식 탐구와 리팩토링의 필요성
도메인 지식은 계속 변화합니다.
우리가 개발하는 도중에도 비즈니스 환경은 끊임없이 변합니다. 새로운 요구사항이 생기고, 도메인 모델 역시 이에 맞게 발전해야 합니다. 예를 들면 초기에는 '주문(Order) = 주문 생성 + 결제 완료' 였던 비즈니스에 '환불'이라는 개념이 추가되면서 '주문(Order)과 결제(Payment)'를 별도의 비즈니스로 정의하도록 변경될 수 있습니다.
이러한 변화는 도메인 지식의 지속적 탐구와 코드 리팩토링을 요구합니다. 이 과정을 무시하면 시스템이 도메인의 실제 상태와 점점 괴리되며, 유지보수가 어려워질 수 있습니다. 그렇기에 지속적인 리팩토링이 굉장히 중요합니다. 아래의 작업들이 지속적으로 유지되어야만 합니다.
1. 도메인 모델의 최신화: 도메인의 변화를 반영하여 모델을 업데이트.
2. 코드의 일관성 유지: 유비쿼터스 언어에 따라 코드를 리팩터링 하여 유지보수를 용이하게 만듭니다.
5. 유비쿼터스 언어는 팀원 간 소통의 핵심 도구입니다.
소통의 표준화와 협업이 강화됩니다.
유비쿼터스 언어는 단순히 공통 용어를 정의하는 것을 넘어, 팀 내에서 협업을 강화하는 도구입니다. 이를 통해 팀원들은 동일한 맥락에서 문제를 이해하고, 효과적으로 해결책을 논의할 수 있습니다. 구체적으로 살펴봅시다.
- 효율적인 회의: 회의 중 불필요한 설명을 줄이고, 논의를 빠르게 진행할 수 있습니다.
- 문서화의 간결성: 표준화된 용어 덕분에 문서가 직관적이고 이해하기 쉬워집니다.
- 개발 생산성 향상: 요구사항 분석, 코드 리뷰, 테스트 설계가 단순화됩니다.
유비쿼터스 언어는 팀원들의 공동 책임입니다.
유비쿼터스 언어는 개발자와 기획자 그리고 도메인 전문가 모두의 책임입니다. 팀원들은 이를 중심으로 협업하며, 정기적으로 용어와 모델을 업데이트하여 팀 내 일관성을 유지해야 합니다. 예를 들어, 새로운 도메인 개념이 등장하면 모두가 이해할 수 있도록 용어와 모델을 공유하고 검토하는 과정이 필요합니다. (개인적으로는 이 과정이 제일 힘든 부분인 것 같습니다.)
6. Model-Driven Design과 유비쿼터스 언어
MDD란 무엇인가?
Model-Driven Design(MDD)은 도메인 모델이 '설계'와 '구현'의 중심에 위치하도록 강조하는 방법론입니다. 이는 소프트웨어 개발에서 도메인 모델이 단순한 문서화 수준에 머무르지 않고, 설계와 코드에 직접 반영되도록 하는 접근 방식입니다.
MDD와 유비쿼터스 언어의 관계
MDD에서 유비쿼터스 언어는 모델을 정확히 정의하고 구현할 수 있는 핵심 도구로 작용합니다. 유비쿼터스 언어를 기반으로 작성된 도메인 모델은 설계와 구현 간의 간극을 줄이고, 도메인 변화에 따른 시스템의 유연성을 높입니다.
- 모델과 설계의 일치: 유비쿼터스 언어에서 정의된 용어를 클래스, 메서드 이름으로 반영.
- 변화에 대한 적응성: 도메인 요구사항이 변경될 때 모델을 업데이트하여 코드에 반영.
물류 관리 시스템으로 이해해 봅시다.
- 창고(Warehouse): 물품을 저장하는 장소.
- 재고(Inventory): 창고에 보관된 물품.
- 배송(Delivery): 고객에게 물품을 전달하는 과정.
public class Warehouse {
private String location;
private List<Inventory> inventories;
public Warehouse(String location) {
this.location = location;
this.inventories = new ArrayList<>();
}
public void addInventory(Inventory inventory) {
inventories.add(inventory);
}
}
public class Inventory {
private String itemId;
private int quantity;
public Inventory(String itemId, int quantity) {
this.itemId = itemId;
this.quantity = quantity;
}
public void updateQuantity(int newQuantity) {
this.quantity = newQuantity;
}
}
- 위 코드에서 도메인 용어 "창고"와 "재고"가 명확히 반영되어 있으며, 비즈니스 로직을 쉽게 이해할 수 있습니다.
마무리하며
유비쿼터스 언어는 DDD의 핵심 요소로, 팀의 협업, 도메인 이해, 설계와 구현의 일치를 가능하게 합니다. 이를 발전시키기 위해서는 지속적으로 모두가 도메인 지식을 탐구하고, 코드와 모델을 리팩터링 하며, 팀원 간의 소통을 유비쿼터스 언어 중심으로 이루어야 합니다.
저도 어떻게 해야 프로젝트에서 더 좋은 유비쿼터스 언어를 구성하고 모든 팀원들이 유연하게 사용할 수 있을지에 대해 정말 많은 고민을 하고 있습니다. 이 부분에서 특히 어렵게 느껴지는 것은 지식을 탐구하며 공유하는 과정에서 서로의 감정이 상할 수도 있기에 너무 강한 어조나 확고한 자기주장을 하지 않도록 주의하면서 말하고자 노력하는 것과 본인이 몰랐던 지식을 배울 때는 거부감을 없애고 유연하게 받아들이고자 노력하는 자세입니다.
회의라는 것은 다양한 생각을 가진 여러 사람들이 자신의 생각을 공유하며 더 좋은 방법을 찾아가고 성장시키며 발전해 가는 과정이기에 대화하면서 어느 정도는 격한 감정이 올라올 수도 있습니다. 그러나 내가 회의를 하는 이유를 한번 더 생각해 보고 회의라는 것을 하나의 관점 확장 방법이라고 생각하며 참석하다 보면 누군가의 주장이 옳거나 잘못되었다는 것을 조금 더 이성적으로 판단할 수 있다는 것을 최근 배웠습니다. (물론 이건 제가 개인적으로 느낀 점이기에 모두가 동일하지는 않습니다. ㅎㅎ)
그래서 제가 생각하는 유비쿼터스 언어를 잘 구성하기 위해 가장 중요한 것은 서로 다른 분야의 사람들이('비즈니스 전문가, 기획자, 개발자') 서로를 배려하며 의견을 이해하고자 하는 노력에서부터 시작되는 것이 아닐까 생각합니다. 서로를 이해하며 어느 순간 모두의 대화가 하나의 호흡으로 합쳐질 때 DDD의 승패가 결정되는 것 같습니다.
모두 긴 글 읽어주셔서 감사합니다 :)
'DDD' 카테고리의 다른 글
화살표 if문을 DDD로 우아하게 리팩토링하기 (1) | 2024.10.29 |
---|---|
스프링에서 도메인 객체를 사용하는 건에 대해 (6) | 2024.08.31 |