최근 Domain-Driven Design(이하 DDD) 개념이 많은 IT 종사자들에게 퍼지고있다.
이번 포스팅에선 필자의 현업에서 경험한 내용을 바탕으로 DDD에 대한 이야기를 작성해보려한다.
작성자 배경
미용의료 병원용 B2B SaaS 제품을 만들고있으며, 총 인원 10-15명 정도의 신사업팀에서 백엔드 엔지니어를 담당하고있고, 팀 내엔 DDD에 익숙한, 익숙하지 않은 이들이 모여있다.
엔지니어는 총 8명이 있고, 백엔드는 필자 포함 2명이다. 다른 이들은 PO(Product Owner), PD (Product Desginer), Tech Sales (Domain Expert 1) 분들이 계신다.
DDD를 사용해서 좋은점이 뭔가요?
팀 내 도메인 지식을 표준화하고 명확한 소통을 할 수 있다
팀 내 이해관계자들(Stakeholders)간 원활한 의사소통은 가장 필요로 하는것 중 하나이다.
DDD에는 크게 두가지로 전술적 패턴과 전략적 패턴이 존재한다.
전략적 패턴에 보편 언어(Uniquitous Language)라는 개념이 존재하는데, 주 목적은 모든 팀 구성원이 동일한 언어로 도메인을 이해하고 이야기 할 수 있는것이다.
이 때, 보편 언어를 정의할 때는 제품 사용성에 대해 집중해야한다. 제품 사용자들이 실제 사용하는 언어, 행위 등과 준 동치되는 개념으로 투영되도록 정의하는게 중요하다는것이다.
그래서 팀 내 도메인 전문가(Domain Expert)를 초빙하여, 의사소통에 필요한 개념들의 표준화를 다같이 정의한다. 물론 이 보편 언어는 단방에 정의할 수는 없다. 실제 DDD Guide에서도 한번에 정의내리는것이 아닌 여러 *지식 탐구(Crunching Knowledge) 시간을 여러번 가지며 정의내릴 수 있다고 말한다.
ref. 지식탐구? - https://www.dddcommunity.org/wp-content/uploads/files/books/chapter01.pdf
예시로 보면
보편언어가 정해져있지 않을 때
팀원: 고객이 병원에 워크인해서 데스크에 말한 뒤 예약을 생성할 수 있어요.
위 내용을 도메인 전문가 또는 팀원에서 보편 언어를 설정하면 다음과 같이 변경할 수 있다.
보편 언어를 정한 뒤에 소통할 때
팀원: 고객이 워크인해서 접수한 뒤 예약을 할 수 있어요.
좀 더 간단하고 명확한 표현으로 정리된다. 이는 아래에서 다루겠지만, 엔지니어들에게도 매우 중요한 변경사항이다.참고로 필자의 팀 내에선 노션으로 보편 언어 문서를 관리한다. (아래 이미지 참고)
위 노션 문서에는 제품의 많은 보편언어들이 정리가 되어있다.
위에서 언급했듯이 보편 언어는 엔지니어들에게도 중요한 변경사항이다.
왜 보편 언어가 개발자한테 중요한가요?
DDD의 또 하나의 장점은 기술과 비지니스의 경계를 허무는것이다. 즉, 비지니스 가치를 중심으로 개발을 할 수 있다는 것이다.
최초 보편언어가 정해져있지않을 때 예약 서비스를 만든다면 아래와 같이 도메인 이벤트, 명령들을 정의할 수 있을것같다.
class CreateReservationCommand(...) {} // 예약을 생성하는 DTO
class ReservationCreated(...) {} // 예약 생성됨을 뜻하는 도메인 이벤트
데이터적인 사고를 배제하면 예약을 생성한다는 어색하다. 실제 비지니스에서 보더라도 병원 관리자가 고객에게 “예약 생성하시고 오셨나요?“라고 물어보진 않을것이다.
그래서 실제 비지니스의 행위에 맞는 보편언어를 정했을 때 System에도 그대로 투영 되도록 설계하는것이 중요하다.
보편언어를 정한 이후엔 아래와 같이 정의할 수 있다.
class ReserveCommand(...) {} // 예약 DTO
class Reserved(...) {} //예약됨을 뜻하는 도메인 이벤트
우리가 해결하고자 하는 비지니스 문제, 상황에 맞추어 클래스, 메서드, 변수 등을 정의내릴 수 있다. 이러한 행위들은 결국 시스템이 커질수록 빛을 바랄 수 있다.
제품을 만들다보면, 비스무리하지만 살짝 다른 개념들이 정말 많이 나온다. 이럴 때일 수록 명확하게 보편언어를 팀내에서 설정하고 만들다보면 스파게티가 될 확률이 매우 높아진다. 자연스레 코드에서도 스파게티 개념들을 녹이다보면 유지보수성이 매우 떨어질 수 있다.
복잡한 현실세계의 문제를 명확한 경계를 나누어 해결할 수 있다
이는 DDD에서 전략적 설계의 Bounded Context에 해당되는 이야기이다.
소프트웨어 개발 과정에서 현실세계의 문제를 그대로 코드로 옮기다보면 복잡도가 급격하게 증가한다. 특히, 여러 도메인이 얽혀있는 경우 의미가 다른 개념들이 혼재되어 혼란을 야기할 수 있다.
(필자가 만들고있는 제품에서 식별한 도메인만 해도 10개가 넘는 Bounded Context가 있다)
Bounded Context? (이하 B.C)
‘하나의 시스템을 여러개의 독립적인 컨텍스트로 나누어 관리하는 개념’
특정 도메인 모델이 유효한 경계(boundary)를 정의하며, 각 B.C 내에서 도메인 모델은 일관성을 유지한다.
B.C 간의 경계를 명확히 함으로써 모델의 충돌을 피하고 각 컨텍스트 내에서 독립적으로 모델을 발전시킬 수 있다.
설계를 통해 B.C를 도출하고 연관 관계를 맺었다면, 그 관계를 유지하기 위해 어떻게든 우회해서 유지하는게 좋다.
예를 들어, 필자가 개발중인 제품에는 다양한 도메인 요구사항이 존재한다.
스케줄(예약) 관리
수납 관리
시술권 관리
DDD를 하고있다면 이 각각의 영역들의 경계 컨텍스트를 명확히 정의내리고, 각 경계별로 어떤 모델들을 가지는지, 의존성은 어떻게 관리하는지 등에 대해 정리를 해야한다. (아래 이미지 참고)
위와 같이 각 B.C 별로 의존성 관계를 설정하고, 앞으로 확장되는 요구사항이 생길 때마다 각 경계의 책임에 맞추어 설계 및 개발이 이루어져야한다. 만약, 제품의 확장성, 유지보수성을 고려하지않고 경계를 정의하지않고 서로 양방향 의존성이 생기도록 개발이 되면 추후 확장되면서 점차 감당할 수 없는 논리들이 마구마구 생겨날 것이다.
이렇게 잘 정의된 B.C는 모듈화를 촉진하고, 재사용성을 높일 수 있게된다.
B.C.를 나누지않으면 무슨 문제들이 발생할까?
모델 충돌 및 혼란
- 도메인 모델이 하나의 컨텍스트 안에서 혼재해 있을 때, 동일한 개념이 다른 의미로 사용되거나 서로 다른 용어가 동일한 의미를 가지는 경우가 발생할 수 있다.
비지니스 로직의 분산
도메인 로직이 여러곳에 분산되어있을 경우, 비지니스 로직을 이해하고 수정하는데 어려움이 발생한다.
특정 로직이 어디에 위치하는지 찾기가 어려워지고, 이는 개발자의 생산성과 시스템의 일관성을 저해한다.
DDD는 모든 상황에 적합한 방법론이 아니다
(세상에 트레이드 오프 없는 방법론이 존재할까🤔)
DDD는 복잡한 도메인을 다루기 위한 강력한 설계 방법론으로 많은 장점을 제공하지만, 모든 상황에 적합하지는 않다. 특히, 팀의 경험과 조직 환경, 도메인의 복잡성에 따라 DDD가 기대만큼 효과를 발휘하지 못할 수 있다. 이와 같은 트레이드 오프를 이해하고 상황에 따라 적절히 활용하는것이 중요하다 생각된다.
팀의 경험에 따라 결과가 천차만별이다
DDD의 성공 여부는 팀의 역량과 경험에 크게 의존한다.
DDD는 단순한 방법론이 아니며, 도메인 중심의 사고방식과 이를 구현하기 위한 전략적·전술적 설계 모두에 깊은 이해가 필요하다. 하지만 팀 내 DDD에 대한 경험이 부족한 경우, 오히려 복잡한 설계로 인해 효율성이 떨어질 수 있다.
e.g.
Bounded Context를 잘못 정의하면 경계 간 의존성이 얽히면서 시스템이 복잡해지고, 이는 유지보수성에 악영향을 미친다.
또한, 전술적 빌딩 블록(애그리거트, 엔터티, 값 객체, 도메인 이벤트, …)을 잘못 적용하면 모델이 지나치게 세밀하거나, 반대로 지나치게 추상적이게 될 수 있다.
팀원 모두가 DDD를 학습해야한다 (러닝 커브 비용)
DDD를 팀에 도입하려면 모든 구성원이 DDD의 개념과 이를 실무에 적용하는 방법을 이해해야한다.
DDD는 도메인 모델링, 보편 언어, 바운디드 컨텍스트, 컨텍스트 매핑 등 많은 새로운 개념을 학습해야한다. 엔지니어뿐만 아니라, PO, PD, Domain Expert 등 비개발자 구성원도 도메인 중심의 사고방식에 익숙해져야 하기 때문에 학습 범위가 넓다. 따라서 이러한 학습 과정에서 생산성이 일시적으로 하락할 가능성이 높아지며, 팀원들의 반발을 살 수 있다.
도메인 전문가 확보가 어렵다
DDD의 가장 큰 핵심은 도메인 모델링이며, 이를 위해 도메인 전문가(Domain Expert)와의 긴밀한 협력이 필수적이다.
도메인 전문가가 없다면, 개발자가 도메인을 완전히 이해하지못하고 추측에 의존하여 설계를 하게된다. 또는 도메인 전문가가 있다고 하더라도, 그들의 시간을 확보하거나 협업을 이끌어내는 일이 어려울 수 있다.
특히, 소규모 팀일 수록 도메인 전문가를 따로 두기 어려운 경우가 많다. 이로인해, 도메인의 전문 지식이 산발적으로 흩어져 있을 때 도메인 모델링의 품질이 낮아질 수 있고, 도메인 전문가가 모델링 과정에 충분히 참여하지못하면 개발자와 도메인 간의 괴리가 생기고 잘못된 설계로 이어질 가능성이 커진다.
그래서 도메인 전문가를 확보하기 어려운게 일반적인 환경이다보니, 팀 내 PO, PD, Sales, Developer 등 모두가 내부의 지식을 최대한 축적하기 위해 시장 고객과 이야기를 하며 전문성을 키워나가는것이 중요하다 생각한다. (이 때, 문서화, 위키를 적극 활용하는것이 중요하다.)
조직 문화와의 부합하지않으면 적용이 어렵다
DDD는 단순한 기술적 도구가 아니라, 비지니스와 기술의 경계를 허물고 팀의 협업을 중심으로 하는 접근 방식이다.
기존에 빠르게 결과물을 내놓는데 익숙한 팀이거나, 개발 속도를 중시하는 조직에서는 DDD의 점진적 설계 방식이 받아들여지기 어려울 수 있다. 특히 비지니스와 기술 간의 장벽이 존재하거나, 팀 간의 협업이 원활하지 않은 환경에서는 DDD가 성공적으로 정착하기 어렵다.
e.g.
도메인 모델을 정의하고, 보편언어를 설정하는 과정(지식 탐구)에 시간 투자하는것을 조직이 낭비로 간주할 가능성이 있다.
팀 간 소통 문화가 부족하거나, 개발자들이 비지니스에 관심을 두지 않은 경우 DDD의 효과는 크게 줄어들 수 밖에 없다.
필자는 개인적으로 조직의 특성, 목적, 목표을 존중하는것도 팀원의 몫이라고 생각한다. DDD를 활용하고싶지만 조직의 목표에 맞지않는다면 가감히 포기하는것도 나쁘지않다 생각한다. 그런데 팀의 목표를 이루기위해 DDD가 적절하다고 생각된다면, 조직의 리더쉽과 기대효과에 대해 많은 논의를 거치며 설득해 나가는 과정을 겪는것도 좋다 생각한다.
복잡하지 않은 시스템에 DDD는 오히려 복잡도가 증가한다. (오버 엔지니어링)
DDD는 복잡한 비즈니스 문제를 해결하기 위해 고안된 강력한 설계 방법론이다.
단순한 비지니스 로직이나 작은 규모의 시스템에서는 DDD를 도입하는것이 오히려 오버 엔지니어링이 될 수 있다. 복잡하지 않은 시스템에서는 CRUD 중심의 데이터 접근 방식이 훨씬 더 효율적일 수 있다.
단순한 시스템에 적용하다보면 아래와 같은 문제를 야기할 수 있다.
불필요한 복잡도 증가
- 도메인을 세분화하고 경계를 나누는 작업은 비용이 많이 들며, 작은 시스템에서는 그 자체가 불필요한 복잡도를 초래한다.
생산성 저하
- 빠르게 배포하고 피드백을 받아야 하는 초기 MVP 단계에서 DDD를 도입하면 개발 속도가 저하될 수 있다.
관리 부담
- 전술적 설계(Aggregate, Entity, Value-Object 등)를 적용하려는 시도가 오히려 코드를 이해하기 어렵게 만들 수 있다.
마치며
DDD는 강력한 도구이지만, 이를 효과적으로 활용하려면 팀과 조직이 충분히 납득하고 준비되어있어야한다. 팀의 경험 부족, 학습 곡선의 높음, 도메인 전문가의 확보 어려움 등 DDD 적용이 어려워질 수 있다. 하지만 DDD의 특성과 장점들을 속한 조직에 투영시켜보고 도움이 된다 판단된다면, 점진적으로 팀원들과 합심하여 도입해보는것이 좋을것같다 생각한다.
마지막으로 DDD는 만능 해결책이 아니다
라는 점을 강조하며 글을 끝내본다.