본문 바로가기

엔지니어링(TA, AA, SA)/아키텍처

[아키텍처] 도메인 주도 설계(1) - 지식 탐구

성공한 프로젝트의 공통적인 특징은 반복적 설계를 거쳐 발전하고 프로젝트의 일부분이 된 풍부한 도메인 모델이 있었다는 것이다. 도메인 주도 설계와 관련된 의사결정을 내리는데 기반이 되는 틀과 도메인 설계에 대해 논의할때 사용되는 기술적 어휘를 익히고, 복잡한 도메인에 직면한 소프트웨어 개발팀은 도메인 주도 설계에 체계적으로 접근하는데 이 틀을 활용할 수 있을 것이다.

 

단순한 소프트웨어는 설계에 그리 신경 쓰지 않고도 만들 수 있기에 별다른 문제가 없다. 그러나 도메인 모델이나 프로젝트의 공통적인 언어조차 없고 구조화되어있지 않은 설계는 프로젝트를 실패에 이르게 한다. 업무로직을 성공적으로 다루지 못하고, 너무 일찍 유지보수 비용이 많이드는 레거시 시스템으로 굳어버리게 된다.

 

복잡성으로 생기는 한계를 극복하려면 도메인 로직 설계에 좀더 진지하게 접근해야 한다. 복잡성이 첫번째 프로젝트 수준인 도메인을 가진 간단한 애플리케이션에서 시작됐다. 점점 개발에 박차가 가해지면서, 각 반복주기마다 전 단계의 기능을 통합하거나 정교하게 만드는 멋진 새 옵션이 만들어질 수 있다. 팀원들은 요구사항에 유연함과 확장 능력을 토대로 대응할 수 있었고, 이러한 향상은 계속해서 코드 안에 정제되고 표현되는 예리한 도메인 모델이 있었기에 가능할 수 있다. 도메인에 대한 새로운 통찰력을 얻게되면 모델은 그 깊이를 더해갈 수 있다. 설계는 큰 유지보수 부담을 주는 것이 아닌 변경이나 확장이 점점 쉬워지는 구조로 바뀌게 되었다.

 

아쉽게도 단순히 모델을 중요하게 취급한다고해서 점차 향상되는 선순환에 이르지는 않는다.  개발자 역할을 분담하는데 오류를 범함으로써 모델링과 구현이 단절됐고, 이로써 진행되고 있던 심층적인 분석 내용이 설계에 반영되지 못하는 결과가 초래됐다. 세부적인 업무 객체의 설계는 정교한 애플리케이션에 해당 객체들을 결합시킬 만큼 엄밀하지 못했다. 반복주기는 계속됐지만 코드는 개선되지 않았다. 팀원들은 모델 기반 객체를 만들어내기 위한 비공식적인 형식과 기법을 알지 못했다. 몇달후, 개발 업무는 복잡성이라는 수렁에 빠지게 되었고, 팀우너들은 시스템에 대한 응집력있는 비전을 잃어버렸다. 


복잡성이라는 도전과제

관료주의, 불명확한 목표, 자원 부족 등 다양한 이유로 프로젝트는 궤도에서 이탈한다. 그러나 얼마나 복잡한 소프트웨어를 만들어낼수 있는가를 결정하는 주된 요인은 설계 접근법에 있다. 복잡성을 감당할 수 없다면 개발자는 더는 쉽고 안전하게 변경하거나 확장할 수 있을만큼 소프트웨어를 파악하지 못한다. 반면, 좋은 설계는 이러한 복잡한 특징을 활용할 기회를 만들어 줄 수 있다.

 

수많은 애플리케이션에서 가장 중요한 복잡성은 기술적인 것이 아니다. 그것은 바로 사용자의 활동이나 업무에 해당하는 도메인 자체다. 이러한 도메인의 복잡성을 설계에서 제대로 다루지 않으면 기반 기술을 잘 이해하더라도 무용지물일 것이다. 성공적인 설계라면 틀림없이 소프트웨어의 중심 요소인 도메인을 체계적인 방법으로 다룰 것이다.

  1. 대부분의 소프트웨어 프로젝트에서는 가장 먼저 도메인과 도메인 로직에 집중해야 한다.

  2. 복잡한 도메인 설계는 모델을 기반으로 해야 한다.

 

도메인 주도 설계는 복잡한 도메인을 다뤄야 하는 소프트웨어 프로젝트에 박차를 가하는 것을 목표로 삼는 사고방식이자 우선순위의 모음이다. 이러한 목표를 달성하기 위해 설계 실천법, 기법, 원칙을 폭넓게 인식하는 것이 중요하다.

 

도메인 주도 설계는 많은 양의 지식을 받아들여 모델을 만들어 내는데, 이 모델은 도메인에 대한 깊은 통찰력과 핵심 개념에 집중한 바를 반영한다. 이것은 도메인 전문가와 소프트웨어 개발자 사이에서 일어나는 협업의 결과다. 또한 개발은 반복주기를 토대로 진행되므로 이 같은 협업은 프로젝트의 전체 생명주기 동안 지속적으로 이뤄져야 한다.

 

익스트림 프로그래밍은 설계에 관련된 의사결정의 중요성은 인정하지만 선행 설계는 완강히 반대한다. 대신 의사소통과 프로젝트의 방향을 빠르게 변화시킬 수 있는 능력을 향사시키는 데 굉장한 노력을 기울인다. 개발자들은 이처럼 상황에 대처하는 능력을 갖춰 프로젝트의 어떤 단계에서도 "작동하는 가장 단순한것"을 활용하고 지속적인 리팩토링을 거쳐 수많은 점진적인 설계 개선을 바탕으로 궁극적으로는 고객의 실제 요구사항에 부합하는 설계에 도달한다.

 

지속적인 리팩토링은 작은 재설계가 연속적으로 일어나는 것이다. 즉, 확고한 설계 원칙이 없는 개발자는 이해하거나 변경하기 어려운 코드만을 만들어낼 것이며, 이는 기민함(agility)과는 거리가 멀다. 그리고 예상치 못한 요구사항에 대한 두려움이 종종 과도한 선행 작업으로 이어지기도 하지만, 반대로 지나친 선행 작업을 회피하려는 노력이 또 다른 두려움을 만들어내기도 한다. 설계에 관해 전혀 깊이 있게 생각하지 않는다는 두려움 말이다.

 

사실 XP는 예리한 설계 감각이 있는 개발자에게는 최선의 선택이다. XP 프로세스는 리팩토링을 토대로 설계를 개선하고, 이러한 리팩토링을 자주, 그리고 빠르게 수행한다고 가정한다. 그러나 지금까지의 설계를 선택하는 방식은 리팩토링 자체를 쉽게 만들거나 어렵게 만들기도 한다. XP 프로세스는 팀원 간의 의사소통의 기회를 늘리려 하지만 모델 및 설계의 선택이 의사소통을 명확하게 하거나 혼란스럽게 만들기도 한다.

 

애자일 개발 프로세스 환경하에서 도메인 모델링에 정교하게 접근한다면 개발을 가속화할 수 있을 것이다. 아울러 도메인 개발과 프로세스와의 상호관계를 고려한다면 순수하게 설계만 다루는 것에 비해 이 같은 접근법이 더욱 실용적일 것이다. 

 

"동작하는 도메인 모델"에서는 도메인 주도 설계의 기본적인 목표를 제시한다. 이 목표는 이어 나오는 실천지침의 배경이 된다. 소프트웨어 개발을 위한 접근법은 여러 가지가 있으므로 1부에서 용어를 정의하고, 도메인 모델의 사용이 의사소통과 설계에 어떤 영향을 주는지 개략적으로 설명한다.

 

"모델 주도 설계의 기본 요소"에서는 객체지향 도메인 모델링에서의 우수 실천법의 핵심을 몇가지 기본 요소로 요약한다. 여기서는 모델과 실제로 동작하는 소프트웨어 간의 간극을 메우는 데 초점을 맞춘다. 이처럼 표준화된 패턴을 활용하면 질서정연한 설계가 가능해진다. 팀원들이 서로의 업무를 더 쉽게 이해할 뿐더러 표준화된 패턴을 사용하면 공통 언어에 함께 쓸 수 있는 용어가 마련되어 모든 팀원이 모델과 설계에 관한 의사결정을 내리는 자리에서 이러한 용어를 사용할 수 있다.

 

그러나 여기서는 모델과 구현이 서로 맞물려 돌아가게 조정해서 모델과 구현의 효과를 상호보완하는 의사결정에는 어떤 것이 있는지가 중요하다. 이러한 조정을 위해서는 개별 요소에 세심하게 주의를 기울여야 한다. 이처럼 작은 규모의 요소들을 정교하게 만들어 두면 개발자가 이후에 제시하는 모델링 접근법을 적용할 확고한 토대가 마련될 것이다.

 

"더 심층적인 통찰력을 향한 리팩토링"에서는 기본 요소 수준을 뛰어넘어 이러한 가치를 제공하는 실용적인 모델을 만드는 것과 관련된 도전과제를 다룬다. 난해한 설계 원칙을 바로 적용하는 것이 아니라 발견 과정을 강조한다. 가치있는 모델은 곧바로 나타나지 않는다. 먼제 도메인을 깊이 있게 이해해야 한다.이처럼 도메인을 이해하려면 원시적인 차원의 모델에 기반을 둔 초기 설계 내용을 구현해본 다음 그 구현을 반복해서 변형하는 과정을 거쳐야만한다. 팀원들이 새로운 통찰력을 얻을 때마다 모델은 더욱 풍부한 지식을 나타낼 수 있게 바뀌고, 코드 또한 더 심층적인 모델을 반영하게끔 리팩토링되어 애츨리케이션에 적용하는 것이 가능해 진다. 그러면 이처럼 양파를 벗기듯 진행되는 리팩토링 과정에서 이따금 심오한 설계 변화가 쇄도하면서 훨씬 심층적인 모델로 도약하는 기회로 이어지기도 한다.

 

탐구 과정에는 원래 정답이란게 없지만 그렇다고 아무렇게나 진행할 필요도 없다. 이같은 탐구 과정에서 선택을 돕는 모델링 원칙과 적절한 방향을 제시하는 기법을 자세히 살펴본다.

 

"전략적 설계"에서는 복잡한 시스템, 더 큰 조직, 외부 시스템 및 기존 시스템과의 상호작용에서 발생하는 상황을 다룬다. 컨테스트와 디스틸레이션, 대규모 구조와 같이 시스템에 총괄적으로 적용 가능한 세가지 축을 구성하는 원칙을 살펴본다. 전략적 설계와 관련된 의사결정은 팀단위나 여러 팀에 걸쳐 이뤄진다. 전략적설계는 목표가 더욱 큰 규모, 즉 대형 시스템이나 불규칙하게 뻗어 나가는 기업 차원의 네트워크에 어울리는 애플리케잇녀에서도 실현되게 만들어줄 것이다.

 

중급 개발자가 정교한 모델링과 설계 기법을 실제 문제에 적용하는데 도움을 줄 것이다. 고급 내지는 전문가 수준의 소프트웨어 개발자는 도메인을 다루는 종합적인 틀에 관심이 있을 것이다. 이처럼 설계에 체계적으로 접근한다면 기술 리더가 팀원들을 이러한 방향으로 이끄는데 도움이 될 것이다. 일관된 용어는 이들이 서로 의사소통하는데도 도움될 것이다. 프로젝트 관리자는 팀이 업무 전문가와 사용자에게 의미 있는 소프트웨어를 설계하는데 좀더 효과적으로 접근하고 거기에 집중하게 만드는 데 중점을 둘 것이다. 또한 전략적 설계와 관련된 의사결정은 팀 구성과 업무 방식과 밀접한 관계가 있으므로 이러한 설계 의사결정은 필연적으로 프로젝트 통솔과 관련된 제반사항도 포함하며, 프로젝트 방향에 중요한 영향을 미친다.

 

도메인 주도 설계를 이해한 개발자 개개인도 매우 유익한 설계 기법과 안목을 얻겠지만, 가장 큰 이익은 팀이 합심해서 도메인 주도 설계 접근법을 적용하고 도메인 모델을 프로젝트에서 일어나는 의사소통의 중심에 놓을때 ㅂ라생한다. 이로써 팀원들은 공통 언어를 사용해서 상호 의사소통의 품질을 높이고 의사소통의 결과를 소프트웨어에 반영하게 될 것이다. 팀원들은 모델과 보조를 밪추는 투명한 구현을 만들어 낼 것이고, 이는 애플리케이션 개발에 영향을 줄 것이다. 팀원들은 다른 팀의 설계 산출물과 연관시키는 방법과 관련한 시각을 공유하고 체계적으로 해당 조직에 가장 독특하고 가치있는 기능에 집중할 것이다.

 

도메인 주도 설계는 기술적으로 힘든 도전이지만 대부분의 소프트웨어 프로젝트가 레거시 시스템으로 굳어버리는 것과는 상방되게 크고 열린 기회를 가져다줄 수 있다.


지도는 모델이며, 모든 모델은 중요한 사실이나 사상의 일부 측면을 나타낸다. 모델은 대상을 단순화한 것이다. 즉, 모델은 어떤 사실을 해석한 것으로 볼 수 있고, 당면한 문제를 해결하는 것과 관련된 측면을 추상화하고 그 밖의 중요하지 않은 세부사항에는 주의를 기울이지 않는다.

 

모든 소프트웨어 프로그램은 그 소프트웨어를 사용하는 사용자의 활동이나 관심사와 관련돼 있다. 사용자가 프로그램을 사용하는 대상 영역이 바로 해당 소프트웨어의 도메인(domain)이다. 어떤 도메인에는 물리적인 요소가 수반되기도 하는데, 이를테면 항공권 예약 프로그램의 도메인에는 항공기에 탑승하는 실제 승객이 있다. 반면 어떤 도메인은 실체가 없는데, 회계 프로그램이 그러하며 화폐와 금융이 도메인에 해당한다. 대개 소프트웨어 도메인은 몇가지 예외적인 경우, 가령 소프트웨어 개발 자체가 도메인이 되는 소스 코드 관리 시스템과 같은 부류를 제외하면 컴퓨터와 거의 관련이 없다.

 

모델은 지식을 선택적으로 단순화하고 의식적으로 구조화한 형태다. 적절한 모델을 토대로 정보를 이해하고 문제 자체에 집중할 수 있다. 도메인 모델은 어떤 특정한 다이어그램이 아니라 다이어그램이 전달하고자 하는 아이디어다. 도메인 모델은 해당 지식을 엄격하게 구성하고 선택적으로 추상화한 것이다. 신중하게 작성된 코드나 우리가 쓰는 문장이 그렇듯 우리는 다이어그램을 이용해 모델을 표현하고 전달할 수 있다.

 

도메인 모델링은 가능한 한 "사실적인" 모델을 만드는 문제가 아니다. 현실 세계에 실재하는 사물에 대한 도메인에서도 모델은 인위적 창조물이다. 그리고 단순히 필요한 결과를 내는 소프트웨어 메커니즘을 만드는 것도 아니다. 도메인 모델링은 어떤 목적에 따라 제약에 구애받지 않고 현실을 표현하는 영화 제작에 더 가깝다. 영화 제작자가 자신의 경험 가운데 몇가지 측면을 골라 특유의 방식으로 이야기하고 논지를 펼쳐 나가듯이 도메인 모델러 또한 모델의 유용성에 따라 특정 모델을 선택한다.


도메인 주도 설계에서의 모델의 유용성

도메인 주도 설계에서는 아래의 세가지 기본적인 쓰임새에 따라 모델을 선택한다.

 

1. 모델과 핵심 설계는 서로 영향을 주며 구체화된다.

모델을 의미있게 만들고 모델의 분석이 최종 산출물인 동작하는 프로그램에 적용되게끔 보장하는 것은 다름아닌 모델과 구현 간의 긴밀한 연결이다.이러한 모델과 구현의 연결은 유지보수와 계속되는 기능 개선에도 도움이 되는데, 그 이유는 바로 모델을 이해한 바에 근거해 코드를 해석할 수 있기 때문이다.

 

2. 모델은 모든 팀 구성원이 사용하는 언어의 중추다.

모델과 구현이 서로 연결돼 있으므로 개발자는 이 언어를 토대로 프로그램에 관해 의견을 나눌 수 있다. 그러므로 개발자와 도메인 전문가가 의사소통하는데 별도의 번역 절차가 필요하지 않다. 또한 언어가 모델에 기반을 두므로 우리의 타고난 언어 능력에 힘입어 모델 자체를 정제할 수 있다.

 

3. 모델은 지식의 정수만을 뽑아낸 것이다.

모델은 도메인 지식을 조직화하고 가장 중요한 요소를 구분하는 팀의 합의된 방식이다. 모델에는 우리가 용어를 선택하고, 개념을 분류하며, 분류한 지식을 서로 연관시킬 때 도메인에 관한 우리의 사고방식이 담겨 있다. 개발자와 도메인 전문가는 공유 언어를 바탕으로 갖가지 정보를 모델로 만들어낼 때 효과적으로 협업할 수 있다. 모델과 구현이 연결돼 있으면 초기 버전의 소프트웨어를 통해 얻은 경험을 모델링 프로세스에 피드백으로 활용할 수 있다.

 

모델의 이러한 쓰임에 대해 차례로 각 쓰임의 의미와 가치, 그리고 그것들이 서로 엮이는 방식을 설명한다. 이러한 방식으로 모델을 활용하면 임시방편적인 개발방식에서라면 대규모 투자를 감행하지 않고서는 얻지 못할, 기능이 풍부한 소프트웨어를 개발하는데 이바지할 수 있다.


소프트웨어의 본질

소프트웨어의 본질은 해당 소프트웨어의 사용자를 위해 도메인에 관련된 문제를 해결하는 능력에 있다. 그밖의 매우 중요하다 할 수 있는 기능도 모두 이러한 기본적인 목적을 뒷받침하는데 불과하다. 도메인이 복ㅎ잡하면 이 같은 문제 해결은 유능하고 숙련된 사람의 집중적인 노력이 필요한 어려운 일이 된다. 개발자는 업무 지식을 증진하기 위해 도메인 연구에 몰두해야 한다. 그뿐만 아니라 모델링 기법을 연마해서 도메인 설계에 통달해야 한다.

 

그런데도 이러한 도메인 연구는 대부분의 소프트웨어 프로젝트에서 최우선 과제로 여겨지지 않는다. 대부분의 유능한 개발자는 다뤄야 할 특정 도메인을 학습하는데 관심이 많지 않으며, 더군다나 도메인 모델링 기법을 쌓는데는 더더욱 전념하지 않는다. 기술자들은 자신의 기술력을 훈련할 수 있는 정량적인 문제를 좋아한다. 도메인 업무는 무질서하고 컴퓨터 과학자로서의 능력에 보탬이 될 것 같지 않은 복잡하고 새로운 지식을 많이 요구한다.

 

대신 기술적인 재능이 있는 사람은 정교한 프로엠워크를 만드는 작업에 착수해 기술을 바탕으로 도메인 문제를 해결하려 한다. 도메인을 학습하고 모델링하는 일은 다른 이들의 몫으로 남는다. 소프트웨어의 중심에 있는 복잡성은 정면으로 돌파해야 한다. 그렇지 않으면 도메인과 무관한 소프트웨어를 만들어낼지도 모를 위험을 무릅써야 한다.

 

팀의 리더가 도메인의 중심이 되는 개념을 알고 있어야 해당 도메인의 심층적인 이해를 반영하는 모델 개발이 모르는 사이에 갈피를 잡지 못할때 소프트웨어 프로젝트를 올바른 방향으로 되돌려 놓을 수 있다. 대부분의 소프트웨어 도메인에 존재하는 무질서는 실제로는 흥미진진한 기술적 도전 과제에 해당한다. 사실 여러 과학 분야에서 "복잡성"은 현재 가장 열띤 주제 중 하나이며, 많은 연구자들이 현실 세계의 혼란스러움을 파헤치려는 시도를 하고 있다. 소프트웨어 개발자도 지금까지 단 한번도 일정한 형태를 갖춘 적이 없었던 복잡한 도메인에 직면할 때 그렇게 될 가능성이 있다. 복잡성을 헤쳐나가는 명쾌한 모델을 만들어 내는 것은 흥미진진한 일이다.

 

개발자들이 통찰력을 추구하고 효과적인 모델을 만드는데 활용할 수 있는 체계적인 사고방식과 불규칙하게 뻗어 나가는 소프트웨어 애플리케이션에 질서를 부여할 수 있는 설계 기법이 있다. 이러한 기술을 연마한다면 심지어 처음으로 접하는 익숙지 않은 도메인에서도 여러분은 훨씬 더 가치있는 개발자로 거듭날 것이다.


효과적인 모델링의 요소

1. 모델과 구현의 연계

초기 프로토타입을 토대로 본질적인 연결 고리를 만든 다음, 이어지는 모든 반복 주기 내내 그 연결 고리를 유지했다.

 

2. 모델을 기반으로 하는 언어 정제

프로젝트가 진행되면서 누구라도 모델에서 바로 용어를 끄집어내어 모델의 구조와 일관되게 문장을 구성할 수 있게 됐고 별도의 해석 없이도 문장을 명확히 이해할 수 있었다.

 

3. 풍부한 지식이 담긴 모델 개발

객체는 행위를 지니고 규칙을 이행했다. 모델은 단순히 데이터 스키마가 아니라 복잡한 문제를 해결하는데 필수불가결한 것이었다. 그리고 모델에는 다양한 지식이 포함돼 있었다.

 

4. 모델의 정제

모델이 점차 완전해지면서 중요한 개념이 더해졌으며, 마찬가지로 쓸모없거나 중요하지 ㅇ낳다고 판명된 개념이 제거됐다는 점 또한 중요하다. 불필요한 개념과 필요한 개념이 한데 묶여 있을 겨우 본질과 무관한 개념은 모두 제거할 수 있게 본질적인 개념만을 식별할 수 있는 새로운 모델을 고안해냈다.

 

5. 브레인스토밍과 실험.

스케치를 비롯해 브레인스토밍을 하려는 태도와 결합된 언어를 바탕으로 토의를 모델에 대한 실험실로 변모시켜 수백 가지의 실험용 변종을 연습하고, 시도해 보며, 평가할 수 있었다. 팀에서 시나리오를 검토할 "때 시나리오를 말로 표현해보기만 해도 제안된 모델의 타당성 여부를 재빨리 판단할 수 있었는데, 이는 우리가 뭔가를 듣기만 해도 그러한 표현이 명확하고 쉬운지, 아니면 어색한지 빠르게 감지해낼 수 있었기 때문이다.

 

풍부한 지식이 담긴 모델을 발견하고 그러한 모델의 정제를 가능하케 하는 것은 바로 브레인스토밍과 수차례에 걸친 실험으로 얻는 창의성이다. 이러한 창의성은 모델 기반 언어에서 십분 활용되고, 구현을 통한 피드백 고리로 갈고 닦인다. 이런 식의 지식 탐구는 팀 내 지식을 가치있는 모델로 만든다.


지식 탐구

재무 분석가는 숫자를 면밀히 검토한다. 그들은 숫자의 바탕에 깔린 의미를 알아내려고 숫자를 결합하고 또 결합하며, 그리고 정말로 중요한 것, 말하자면 재무적 판단의 군거가 되는 지식을 드러내는 간결한 표현을 찾으면서 상세한 수치가 적힌 다량의 문서를 면밀히 검토한다.

 

효과적으로 도메인 모델링을 수행하는 사람들도 지식을 면밀히 탐구한다. 그들은 엄청난 양의 정보 속에서 아주 미미한 관련성을 찾아낸다. 그들은 전체를 이해할 수 있는 간결한 관점을 찾아 체계적인 아이디어들을 차례로 시도해본다. 그 과정에서 수많은 모델이 시도/거부/변형된다. 모든 세부사항에 들어맞는 일련의 추상적 개념이 나타나면 비로소 성공에 이른다. 이렇게 해서 뽑아낸 정수는 가장 적절한 것으로 밝혀진 특정 지식을 엄밀하게 표현한 것이다.

 

지식 탐구는 혼자서 하는 활동이 아니다. 개발자와 도메인 전문가로 구성된 팀은 대체로 개발자가 이끄는 가운데 협업한다. 그들은 함께 정보를 받아들여 그것을 유용한 형태로 만든다. 원재료가 되는 지식은 도메인 전문가의 머릿속이나 기존 시스템 사용자, 동일한 도메인에 관련된 레거시 시스템의 기술팀, 혹은 이전의 다른 프로젝트에서 얻은 경험에서 나온다. 이러한 지식은 프로젝트나 업무에 활용할 용도로 작성된 문서의 형태를 띠며, 대화의 형태로 존재할 때가 훨씬 더 많다. 초기 버전이나 프로토타입에서 얻은 경험을 토대로 팀은 이해한 바가 바뀌기도 한다.

 

프로그래머가 리팩토링을 하면서 개발한다면 소프트웨어는 계속 확장이 가능한 말끔한 상태로 유지되겠지만 프로그래머가 도메인에 관심이 없다면 그 이면에 숨겨진 원리는 알지 못한 채 애플리케이션에서 수정해야할 사항만 습득한다. 그러한 과정을 거치지 않아도 유용한 소프트웨어를 만들어낼 수는 있겠지만 프로젝트는 기존 기능의 자연스러운 결과로 새로운 강력한 기능이 나타나는 정도의 수준에는 결코 이르지 못한다.

 

훌륭한 프로그래머라면 애초부터 추상화를 시작해서 더욱 많은 일을 해낼수 있는 모델로 발전시킬 것이다. 하지만 이 같은 과정이 도메인 전문가와의 협업없이 기술적인 측면에서만 일어난다면 개념은 초보적인 수준에 머무를 것이다. 이러한 피상적인 지식은 기초적인 역할만 수행하는 소프트웨어를 만들어 낼 뿐 도메인 전문가의 사고방식과 긴밀하게 연결되지는 않는다.

 

모든 구성원이 함께 모델을 면밀히 만들어 나가면 팀 구성원 간의 상호작용은 그 양상을 달리한다. 도메인 모델의 지속적인 정제를 토대로 개발자는 기능만을 기계적으로 만드는 데 머무르지 않고 자신이 보조하고 있는 업무의 중요 원칙들을 배운다. 도메인 전문가들은 자신이 알고 있는 지식의 정수만을 추출해내야 하므로 스스로 이해하는 바를 자주 정제하고, 그리하여 소프트웨어 프로젝트에서 요구하는 개념적 엄밀함을 이해하게 된다.

 

이러한 모든 과정을 거쳐 팀 구성원은 더욱 유능한 지식 탐구자로 거듭난다. 그들은 모델과 관계없는 것은 가려내고 모델을 더욱 유용한 형태로 고쳐 만든다. 분석가와 프로그래머 모두가 모델을 만들어 나가므로 모델은 명료하게 조직화되고 추상화도리 수 있으며, 구현을 더 용이하게 만들어준다. 도메인 전문가의 지속적인 관여로 모델은 심층적인 업무 지식을 반영하고, 추상화된 개념은 참된 업무 원칙에 해당한다.

 

모델이 점점 향상되면서 모델은 프로젝트 내내 계속해서 흘러가는 정보들을 조직화하는 도구로 자리잡는다. 모델은 요구사항 분석에 초점을 맞춘다. 또한 모델은 프로그래밍과 설계와 밀접한 관계를 맺는다. 그리고 모델은 선순환을 통해 도메인에 대한 팀 구성원의 통찰력을 심화시켜 팀 구성원이 더욱 분명하게 모델을 파악하게 하고, 이는 한층 더 높은 수준으로 정제된 모델로 이어진다. 이러한 모델은 결코 완벽해질 수 없으며, 다만 계속 발전해나갈 뿐이다. 모델은 도메인을 이해하는 데 실용적이고 유용해야 한다. 또한 모델은 쉽게 구현하고 이해하기에 충분할 만큼 엄밀해야 한다.


지속적인 학습

소프트웨어를 작성하기 시작할 때 우리는 충분히 알지 못한 상태에서 시작한다. 해당 프로젝트에서 다룰 지식은 단편적이고, 여러 사람들과 문서에 흩어져 있으며, 다른 정보와 섞여 있어 우리는 어떤 지식이 정말로 필요한지조차 알지 못한다. 기술적으로는 그다지 어려워 보이지 않는 도메인이 사람들을 현혹시키는 경우가 있는데, 우리는 스스로 얼마나 알지 못하는가를 깨닫지 못하는 것이다. 이러한 무지는 잘못된 가정으로 이어진다.

 

동시에 모든 프로젝트에서는 지식이 새기 마련이다. 뭔가를 학습한 사람들은 계속 자리를 옮긴다. 조직 개편으로 팀이 흩어지고 지식도 다시 여기저기로 흩어진다. 중대한 하위 시스템은 외주 제작되어 코드는 전달되지만 지식은 전달되지 않는다. 그리고 전형적인 설계 방법으로는 이렇게 힘겹게 알아낸 지식이 코드와 문서에서 유용한 형태로 표현되지 못하므로 어떠한 이유로든 구두로 전달하기가 어려워지면 지식은 사라진다.

 

생산성이 매우 뛰어난 팀은 지속적인 학습을 바탕으로 의식적으로 지식을 함양한다. 개발자에게는 이것이 일반적인 도메인 모델링 기술과 기술적 지식이 모두 향상된다는 것을 의미한다. 그뿐만 아니라 여기엔 현재 종사하는 특정 도메인에 관해 진지하게 학습하는 것도 포함된다.

 

이처럼 스스로 학습하는 팀원은 가장 핵심적인 부분을 개발하는데 초점을 맞춘 고정 핵심 인력을 형성한다. 이러한 핵심 팀원에게 축적된 지식으로 그들은 더욱 유능한 지식 탐구자가 된다.

 

핵심 모델 요소는 계속 유지됐지만 더 중요한 것은 그다음에 이어지는 작업, 즉 팀 구성원이나 개발자, 도메인 전문가에게서 모두 똑같이 지식을 얻고 의사소통 체계를 공유하며, 구현을 거쳐 피드백 고리를 완성하는 일을 모두 효과적으로 수행하는 지식 탐구 프로세스를 궤도에 올리는 것이었다. 발견을 위한 항해는 어디선가 시작돼야 한다.


풍부한 지식이 담긴 설계

모델에 포작돼 있는 지식은 단순한 "명사 찾기" 이상이다. 도메인에 관련된 엔티티만큼 업무 활동과 규칙도 도메인에 중요한데, 어떤한 도메인에도 다양한 범주의 개념이 존재한다. 지식 탐구는 이러한 통찰력을 반영하는 모델을 만들어낸다. 개발자는 모델의 변경에 맞춰 구현을 리팩토링해서 모델의 변경된 사항을 표현하고, 애플리케이션에서는 그러한 지식을 활용한다.

 

지식 탐구가 열정적으로 이뤄지려면 엔티티와 값을 넘어 이러한 활동이 이뤄져야 하는데, 이는 여러 업무 규칙 간에 실제로 모순되는 부분이 있을 수도 있기 때문이다. 대개 도메인 전문가는 업무 과정에서 모든 업무 규칙을 차례로 확인하고, 모순되는 사항을 조정하며, 상식적인 선에서 규칙의 빈틈을 메울때 자신이 수행하는 지적 작용이 얼마나 복잡한지 알아차리지 못한다. 소프트웨어는 이렇게 할 수가 없다. 규칙을 명확하게 하고, 구체화하며, 조정하거나 고려해야 할 범위 밖으로 배제하는 것은 소프트웨어 전문가와의 긴밀한 협업하에서 진행되는 지식 탐구를 통해 이뤄진다.

 

선박 화물의 운송 예약을 위한 애플리케이션의 기반이 될 매우 간단한 도메인 모델이 있다고 가정한다. 예약 애플리케이션의 책임이 각 Cargo(화물)를 하나의 Voyage(운항)와 연관관계를 맺고, 그것을 기록/관리 하는 것이며, 애플리케이션의 어딘가에는 아래와 같은 메서드가 있을 것이다.

public int makeBooking(Cargo cargo, Voyage voyage) {
    int confirmation = orderConfirmationSequence.next();
    voyage.addCargo(cargo, confirmation);
    return confirmation;
}

항상 마지막 순간에 예약을 취소하는 경우가 있으므로 선박이 운항 중에 나를 수 있는 화물의 최대치보다 예약을 더 받아들이는 것이 해운 산업의 관행이다. 이를 "초과예약(overbooking)"이라 한다. 간혹 용적 대비 110% 예약과 같이 용적을 나타낼때 퍼센트를 쓰기도 한다. 이와 달리 주요 고객이나 특정 종류의 화물에 맞춘 복잡한 초과예약 규칙이 적용되는 경우도 있다.

 

이는 해운 산업에 종사하는 사업가에겐 기초적인 전략이지만 소프트웨어 팀 내에서 기술적 업무를 수행하는 사람들에겐 생소할지도 모른다. 요구사항 문서에는 다음과 같은 "10% 초과예약 허용" 같은 내용이있다.

public int makeBooking(Cargo cargo, Voyage voyage) {
    double maxBooking = voyage.capacity() * 1.1;
    if ((voyage.bookedCargoSize() + cargo.size()) > maxBooking)
        return -1;
    int confirmation = orderConfirmationSequence.next();
    voyage.addCargo(cargo, confirmation);
    return confirmation;
}

이제 중요한 업무 규칙이 애플리케이션 메서드의 보호절(guard clause: 오류를 방지하고자 미리 제약조건을 점검할 용도로 사용하는 절)로 감춰진다. LAYERED ARCHITECTURE라는 원칙을 살펴보게 되면, 초과예약 규칙을 도매인객체로 옮기게 될수 있다. 하지만 지금은 이 지식을 더 명확하게 하고 프로젝트에 관련된 모든 이가 해당 지식을 접하게 하는 방법에만 집중한다. 하지만 현재 코드에는 다음과 같은 문제가 있다.

  1. 코드가 작성된 대로라면 개발자의 도움이 있더라도 업무 전문가가 이 코드를 읽고 규칙을 검증하지는 못할 것이다.

  2. 해당 업무에 종사하지 않고 기술적인 측면만 담당하는 사람은 코드와 요구사항을 결부시키기가 어려울 것이다.

 

규칙이 좀더 복잡했다면 문제가 훨씬 더 심각해질 것이다. 우리는 설계를 변경해서 이 지식을 더 잘 담을 수 있다. 초과예약 규칙은 일종의 정책(policy)이다. 정책이란 잘 알려진 STRATEGY 디자인 패턴의 또 다른 이름이다. 대개 정책은 각종 규칙을 대체할 필요성 때문에 만들어진다. 그러나 지금 담고자 하는 개념은 정책이라는 의미와 잘 맞아 떨어지며, 이러한 정책도 똑같이 도메인 주도 설계의 중요한 동기에 해당한다.

 

코드는 이제 다음처럼 바뀌게 된다.

public int makeBooking(Cargo cargo, Voyage voyage) {
    if (!overbookingPolicy.isAllowed(cargo, voyage)) return -1;
    int confirmation = orderConfirmationSequence.next();
    voyage.addCargo(cargo, confirmation);
    return confirmation;
}

새 Overbooking Policy(초과예약 정책) 클래스에는 아래 메서드가 포함된다.

public boolean isAllowed(Cargo cargo, Voyage voyage) {
    return (cargo.size() + voyage.bookedCargoSize()) <= (voyage.capacity() * 1.1);
}

이렇게 하면 초과예약이 별개의 정책이라는 사실을 모든 이가 분명히 알게 될 것이며, 이 규칙의 구현 또한 명시적으로 드러나고 다른 구현과 분리할 수 있다.

 

도메인의 모든 세부사항에 이러한 정규한 설계를 적용할 필요는 없다. "디스틸레이션"에서는 중요한 것에만 집중하고 나머지는 축소하거나 분리하는 방법을 제안한다. 위 예제의 목적은 지식을 보전하고 공유하는데 도메인 모델과 그에 상응하는 설계를 이용할 수 있다는 사실을 보여주는데 있다. 더 명시적인 설계는 아래와 같은 이점이 있다.

  1. 설계를 이러한 수준까지 끌어오리려면 프로그래머와 그 밖의 관련된 모든 이가 초과예약의 특성을 단순히 불분명한 계산에 불과한 것이 아니라 별개의 중요한 업무 규칙임을 알아야만 할것이다.

  2. 프로그래머는 업무 전문가에게 그들이 이해할 수 있는 수준에서 기술적 산출물, 심지어 코드까지도 보여줄 수 있으며, 이로써 피드백 고리도 완성된다.


심층 모델

유용한 모델은 겉으로 드러나 있는 경우가 거의 없다. 우리는 도메인과 애플리케이션의 요구사항을 이해하기 되면서 대체로 처음에 중요하게 생각했던 피상적인 모델 요소를 버리거나 관점을 바꾼다. 이로써 처음에는 나타나기 힘들지만 문제의 핵심을 관통하는 포착하기 힘든 추상화가 서서히 나타나기 시작한다.

 

위 예제는 컨테이너 해운 시스템에 기반을 둔다. 팀 구성원의 지속적인 학습이 필요한 실제 프로젝트에서 유용하고 명확한 모델을 만들려면 흔히 도메인은 물론이거니와 모델링 기법에도 정교한 솜씨가 필요하다.

 

그 프로젝트에서는 화물을 예약하는 행위로 선적이 시작되므로 우리는 화물, 운송일정 등을 설명해줄 수 있는 모델을 만들었다. 이러한 일들이 모두 필요하고 유용한 것이었는데도 도메인 전문가는 만족스러워하지 않았다. 도메인 전문가가 업무를 바라보는 방식을 놓쳤기 때문이었다.

 

결국 몇달간의 지식 탐구 끝에 화물 취급이나 물리적인 하역 작업, 장소 간 이동과 같은 일은 주로 하도급자나 회사의 운영팀에서 수행한다는 사실을 알게 되었다. 해운 전문가의 관점에서는 각 주체 사이의 갖가지 책임 이동이 존재했다. 바로 해운업자에서 일부 지역 운송업자로, 한 운송업자에서 다른 운송업자로, 마지막으로 화물 인수자까지의 법적 및 실제적인 책임 이동을 관장하는 프로세스 말이다. 종종 중요한 절차가 진행되는 동안 화물은 창고에 보관될 것이고, 또 어떤 경우에는 화물이 해운 회사의 업무 의사결정과는 무관하게 복잡한 물리적 단계를 거칠 것이다. 운송 일정에 대한 세부 계획보다 오히려 더 중요한 역할을 하는 것은 선하증권과 같은 법률 문서와 납입 양도에 이르는 절차와 같은 것이다.

 

해운 업무를 바라보는 시야가 깊어졌다고 운항 일정 객체를 제거하는 것으로 이어진 건 아니지만 모델은 근본적으로 바뀌었다. 해운 업무를 바라보는 시각이 장소 간 컨테이너의 이동에서 엔티티와 엔티티 사이의 화물에 대한 책임 이동으로 바뀐 것이다. 아울러 이러한 책임 이동을 취급하는 것과 관련된 기능이 더는 선적 작업에 부자연스럽게 붙어있는 것이 아니라 작업과 책임 간의 중요한 관계를 토대로 만들어진 모델의 중심에 자리잡았다. 지식 탐구는 탐험과도 같아서 어디서 끝나게 될지 알지 못한다.