Ubiquitous Language

정의

Ubiquitous Language(보편 언어)는 도메인 모델을 중심으로 구조화되어, 하나의 Bounded Context 안에서 팀 전원이 사용하는 언어다. 팀의 모든 활동을 소프트웨어와 연결하는 역할을 한다.

Evans가 이 용어로 가리키는 것은 개발자와 사용자 사이에 공통되고 엄격한 언어를 구축하는 실천이다. 이 언어는 소프트웨어에서 사용하는 도메인 모델에 기반해야 한다. 소프트웨어는 모호함을 잘 처리하지 못하므로 언어가 엄격해야 하기 때문이다.


동작 원리

언어가 파편화되는 방식

하나의 Bounded Context 안에서도 언어는 여러 갈래로 쪼개진다.

  • 모델이 기술 담당자를 위한 UML 다이어그램을 그리는 데만 쓰인다면, DDD의 핵심인 창의적 협업에 기여하지 못한다
  • 도메인 전문가는 자기 업계 용어를 쓰고, 기술 담당자는 설계 관점에서 도메인을 논하기 위한 자기 언어를 쓴다
  • 일상 대화의 용어가 코드에 박힌 용어와 단절된다. 코드야말로 소프트웨어 프로젝트의 가장 중요한 산출물인데도 그렇다
  • 같은 사람도 말할 때와 쓸 때 다른 언어를 쓴다. 그래서 도메인을 가장 예리하게 표현한 말이 순간적인 형태로 등장했다가 코드에도 문서에도 남지 않고 사라진다

번역은 소통을 무디게 만들고 지식 정제를 빈혈 상태로 만든다. 그리고 이 방언들 중 어느 것도 공통 언어가 될 수 없다. 어느 것도 모든 요구를 충족시키지 못하기 때문이다.

언어를 바꾸는 것은 모델을 바꾸는 것이다

Evans의 처방은 다음과 같다.

모델을 언어의 뼈대로 사용하라. 팀 내 모든 소통과 코드에서 그 언어를 집요하게 사용하도록 팀을 헌신시켜라. Bounded Context 안에서는 다이어그램, 글, 그리고 특히 말에서 같은 언어를 사용하라.

언어의 변화가 곧 모델의 변화임을 인식하라. 대안적 표현을 실험하여 어려움을 해소하라. 대안적 표현은 대안적 모델을 반영한다. 그런 다음 코드를 리팩터링하여 클래스, 메서드, 모듈의 이름을 새 모델에 맞게 바꿔라.

여기서 핵심은 언어와 모델이 하나라는 점이다. 용어가 어색하다는 것은 모델이 어색하다는 신호이고, 용어를 바꾸기로 했다면 코드의 이름도 함께 바뀌어야 한다.

검증 방법

Evans는 도메인 전문가와의 대화에서 보편 언어를 사용하는 것이 그 언어(그리고 도메인 모델)를 테스트하는 중요한 방법이라고 분명히 밝힌다.

모델에 대해 이야기하면서 모델을 가지고 놀아라. 모델의 요소와 상호작용을 사용해 시나리오를 소리 내어 설명하고, 모델이 허용하는 방식으로 개념을 조합하라. 필요한 말을 더 쉽게 할 방법을 찾고, 그 새로운 아이디어를 다이어그램과 코드로 되가져가라.

역할 분담도 명확하다.

도메인 전문가는 도메인 이해를 전달하기에 어색하거나 부적절한 용어와 구조에 이의를 제기해야 한다. 개발자는 설계를 무너뜨릴 모호함이나 불일치를 주시해야 한다.

그리고 언어와 모델은 팀의 도메인 이해가 자라남에 따라 함께 진화해야 한다.


예제

공연 티켓 예매 시스템에서 “예약"이라는 말이 두 가지 다른 상태를 동시에 가리키면 reserve()라는 메서드가 무엇을 하는지 매번 코드를 열어봐야 한다. 용어를 넷으로 분리하고 코드와 DB가 그 용어를 그대로 쓰게 하면 이 문제가 사라진다.

용어코드DB
선점(hold)결제 전 일정 시간 좌석 잠금ShowSeat.hold()status='HELD', held_until
예약(reservation)선점된 좌석 묶음 = 주문Reservationreservation.status='PENDING'
확정(confirm)결제 승인 후Reservation.confirm()status='CONFIRMED'
만료(expire)제한 시간 내 미결제스위퍼 배치status='EXPIRED'

실천 조건

Hands-on Modelers

Evans는 보편 언어가 성립하기 위한 조직적 전제로 이 패턴을 제시한다. 코드를 쓰는 사람이 모델에 책임을 느끼지 않거나 모델을 애플리케이션에서 동작하게 만드는 법을 이해하지 못하면, 모델은 소프트웨어와 아무 상관이 없어진다.

  • 개발자가 코드를 바꾸는 것이 모델을 바꾸는 것임을 인식하지 못하면, 리팩터링이 모델을 강화하는 대신 약화시킨다
  • 모델러가 구현 과정에서 분리되면 구현 제약에 대한 감각을 잃는다

처방은 단순하다. 모델에 기여하는 기술 담당자는 어떤 역할이든 코드를 만지는 시간을 가져야 하고, 코드를 바꾸는 책임이 있는 사람은 코드로 모델을 표현하는 법을 배워야 한다.

Model-Driven Design

코드를 모델에 긴밀하게 연결하는 것이 코드에 의미를 주고 모델을 유효하게 만든다. 설계의 중심 부분이 도메인 모델에 대응하지 않으면 그 모델은 가치가 거의 없고, 소프트웨어의 정확성도 의심스러워진다.

모델과 설계 사이의 복잡한 매핑은 이해하기 어렵고 실무에서는 설계가 변할 때 유지가 불가능하다. 그러면 분석과 설계 사이에 치명적인 간극이 생겨 어느 쪽에서 얻은 통찰도 반대쪽으로 흘러가지 못한다.


1인 프로젝트에서도 필요한 이유

보편 언어는 팀 규모가 클 때만 의미 있어 보이지만, 용어를 고정하지 않으면 개인 프로젝트에서도 같은 비용이 발생한다. 메서드 이름이 무엇을 하는지 매번 구현을 확인해야 하고, 상태 값의 의미가 파일마다 미묘하게 달라진다. 3개월 뒤의 자신은 도메인 전문가가 아니라 새로 합류한 팀원에 가깝다.


관련 개념

  • Bounded Context - 보편 언어가 통용되는 범위. 언어가 달라지는 지점이 경계다
  • DDD 개요 - Evans의 3점 요약 중 세 번째가 이 패턴이다
  • Repository와 Service - Service의 이름도 보편 언어의 일부가 된다

참고 자료

  • Eric Evans, Domain-Driven Design Reference (2015), “Ubiquitous Language”, “Model-Driven Design”, “Hands-on Modelers”
  • Martin Fowler, Ubiquitous Language