04장 도메인의 격리
소프트웨어 구현을 건전한 상태로 유지하고 모델과의 밀접한 관계를 유지하려면 모델링과 설계의 우수 실천법을 적용해야 한다.
어떤 종류의 의사결정은 모델과 구현이 서로 정합된 상태를 유지해서 서로의 효과를 상호 보완하게 한다.
이 책에서 제시하는 방법은 거의 책임 주도 설계의 원칙 / 계약에 의한 설계를 따른다.
규모와는 관계없이 프로젝트가 난관에 부딪치면 개발자들은 자신들이 그와 같은 원칙을 적용할 수 없는 상황에 놓여 있다는 사실을 알게 될지도 모른다.
도메인 주도 설계 과정을 탄력성 있게 만들려면 개발자들은 잘 알려진 근본 원리들이 어떻게 MODEL-DRIVEN-DESIGN을 뒷받침하는지 이해해야 하며, 이를 통해 실패를 극복하고 난관을 헤쳐나갈 수 있다.
모델의 개발 요소를 실제로 설계하고 구현하는 일은 비교적 체계적으로 이뤄질 수 있다.
소프트웨어 시스템에서 도메인 설계 외의 수많은 관심사로부터 도메인 설계를 격리하면 모델과 설계의 관계가 훨씬 분명해질 것이다.
- 일정한 구분법에 따라 모델 요소를 정의하면 그러한 모델 요소의 의미가 더욱 명확해질 것이다.
- 정교한 모델은 가장 근본적인 사항에 관심을 가질 때만 비로소 복잡성을 헤쳐나갈 수 있으며, 이는 팀에서 확신을 갖고 결합할 수 있는 상세 요소라는 결과로 나타난다.
도메인에서 발생하는 문제를 해결하는 소프트웨어의 각 요소는 그것의 중요성에 어울리지 않게 대개 전체 소프트웨어 시스템의 극히 작은 부분을 구성한다.
- 우리는 여러 객체가 혼재돼 있는 훨씬 더 넓은 곳에서 그 객체들을 하나하나 구분하려 해서는 안된다.
- 우리는 시스템에서 도메인과 관련이 적은 기능으로부터 도메인 객체를 분리할 필요가 있으며, 그렇게 해서 도메인 개념을 다른 소프트웨어 기술에만 관련된 개념과 혼동하거나, 또는 시스템이라는 하나의 큰 덩어리 안에서 도메인을 전혀 바라보지 못하는 문제를 방지할 수 있다.
도메인 모델링 원칙을 성공적으로 적용하려면 이 기법이 매우 중요하므로 도메인 주도 관점에서 간략하게나마 반드시 검토해봐야 한다.
LAYERED ARCHITECTURE (계층형 아키텍처)
소프트웨어 프로그램에는 갖가지 작업을 수행하는 설계와 코드가 포함된다.
소프트웨어 프로그램은 사용자 입력을 받아들이고 업무 로직을 수행하며, 데이터베이스에 접근하고, 네트워크상으로 통신하며, 사용자에게 정보를 보여주는 등의 일을 수행한다.
객체지향 프로그램에서는 종종 사용자 인터페이스(UI)와 데이터베이스, 기타 보조적인 성격의 코드를 비즈니스 객체 안에 직접 작성하기도 한다.
- 부가적인 업무 로직은 UI 위젯과 데이터베이스 스크립트에 들어간다.
- 이런 일이 발생하는 까닭은 단기적으로는 이렇게 하는것이 뭔가를 동작하게 하는 가장 쉬운 방법이기 때문이다.
도메인에 관련된 코드가 상당한 양의 도메인과 관련이 없는 다른 코드를 통해 널리 확산될 경우 도메인에 관련된 코드를 확인하고 추론하기가 굉장히 힘들어진다.
- UI를 표면적으로 변경하는 것이 실질적으로 업무 로직을 변경하는 것으로 이어질 수 있다.
- 업무 규칙을 변경하고자 UI 코드나 데이터베이스 코드, 또는 다른 프로그램 요소를 세심하게 추적해야 할지도 모른다.
- 응집력 있고, 모델 주도적인 객체를 구현하는 것이 비현실적인 이야기가 돼버리고 자동화 테스트가 어려워진다.
- 기술과 로직이 모두 각 활동에 포함돼 있다면 프로그램을 매우 단순하게 유지해야 하며, 그렇지 않으면 프로그램을 이해하기가 불가능해진다.
매우 복잡한 작업을 처리하는 소프트웨어를 만들 경우 관심사의 분리가 필요하다.
- 격리된 상태에 있는 각 설계 요소에 집중할 수 있다.
- 동시에 시스템 내의 정교한 상호작용은 그러한 분리와는 상관없이 유지돼야 한다.
계층형 아키텍처라는 몇 개의 일반화된 계층이 널리 받아들여지고 있다,
계층화의 핵심 원칙은 한 계층의 모든 요소는 오직 같은 계층에 존재하는 다른 요소나 계층상 ‘아래’에 위치한 요소에만 의존한다는 것이다.
계층화의 가치는 각 계층에서 컴퓨터 프로그램의 특정 측면만을 전문적으로 다룬다는 데 있다.
경험과 관례를 바탕으로 널리 받아들여지는 계층화가 어느 정도 정해졌다.
사용자 인터페이스(또는 표현 계층)
- 사용자에게 정보를 보여주고 사용자의 명령을 해석하는 일을 책임진다. 간혹 사람이 아닌 다른 컴퓨터 시스템이 외부 행위자가 되기도 한다.
응용 계층
- 소프트웨어가 수행할 작업을 정의하고 표현력 있는 도메인 객체가 문제를 해결하게 한다.
- 이 계층에서 책임지는 작업은 업무상 중요하거나 다른 시스템의 응용 계층과 상호작용하는 데 필요한 것들이다.
- 업무 규칙이나 지식이 포함되지 않으며, 오직 작업을 조정하고 아래에 위치한 계층에 포함된 도메인 객체의 협력자에게 작업을 위임한다.
- 작업에 대한 진행상황을 반영하는 상태를 가질 수는 있다.
도메인 계층 ( 핵심 계층 )
- 업무 개념과 업무 상황에 관한 정보, 업무 규칙을 표현하는 일을 책임진다.
- 업무 상황을 반영하는 상태를 제어하고 사용하며, 그와 같은 상태 저장과 관련된 기술적인 세부사항은 인프라스트럭처에 위임한다.
인프라스트럭처 계층
- 상위 계층을 지원하는 일반화된 기술적 기능을 제공한다.
- 메시지 전송, 도메인 영속화, UI에 위젯을 그리는 것 등이 있다.
- 아키텍처 프레임워크를 통해 네 가지 계층에 대한 상호작용 패턴을 지원할 수도 있다.
MODEL-DRIVEN DESIGN을 가능케 하는 것은 결정적으로 도메인 계층을 분리하는데 있다.
복잡한 프로그램을 여러 개의 계층으로 나눠라.
- 응집력 있고 오직 아래에 위치한 계층에만 의존하는 각 계층에서 설계를 발전시켜라.
- 표준 아키텍처 패턴에 따라 상위 계층과의 결합을 느슨하게 유지하라.
- 도메인 모델과 관련된 코드는 모두 한 계층에 모으고 사용자 인터페이스 코드나 애플리케이션 코드, 인프라스트럭처 코드와 격리하라.
- 도메인 객체는 도메인 모델을 표현하는 것에만 집중할 수 있다.
- 이로써 모델은 진화를 거듭해 본질적인 업무 지식을 포착해서 해당 업무 지식이 효과를 발휘할 수 있을 만큼 풍부하고 명확해질 것이다.
인프라스트럭처 계층과 사용자 인터페이스 계층에서 도메인 계층을 분리하면 각 계층을 훨씬 더 명료하게 설계할 수 있다.
계층 간 관계 설정
각 계층은 서로 연결돼야 한다. 분리의 이점을 잃지 않으면서 각 계층을 서로 연결하는 것이야말로 각종 패턴이 존재하는 이유다.
설계 의존성을 오직 한 방향으로만 둬서 느슨하게 결합된다.
- 상위 계층은 하위 계층의 공개 인터페이스를 호출하고 하위 계층에 대한 참조를 가진다
- 일반적으로 관례적인 상호작용 수단을 이용해 하위 계층의 구성요소를 직접적으로 사용하거나 조작할 수 있다.
응용 계층과 도메인 계층에 UI를 연결하는 패턴은 MODEL-VIEW-CONTROLLER에서 유래한다.
APPLICATION COORDINATOR 패턴은 애플리케이션 계층을 연결하는 접근법 가운데 하나다.
보통 인프라스트럭처 계층에서는 도메인 계층에서 어떤 활동이 일어나게 하지 않는다.
인프라스트럭처 계층은 도메인 계층의 아래에 있으므로 해당 인프라스트럭처 계층이 보조하는 도메인의 구체적인 지식을 가져서는 안 된다.
응용 계층과 도메인 계층에서는 인프라스트럭처 계층에서 제공하는 SERVICE를 요청한다.
SERVICE의 범위와 인터페이스를 적절히 선정하고 설계한다면 호출하는 측은 SERVICE 인터페이스에서 캡슐화하는 정교한 행위를 바탕으로 느슨하게 결합되고 단순해질 수 있다.
아키텍처 프레임워크
수많은 인프라스트럭처의 요구사항을 통합하는 프레임워크는 종종 다른 계층이 매우 특수한 방식으로 구현되기를 요구한다.
- 프레임워크 클래스의 하위 클래스가 돼야 한다거나 일정한 메서드 서명을 지정해야 한다.
- 가장 바람직한 아키텍처 프레임워크라면 도메인 개발자가 모델을 표현하는 것에만 집중하게 해서 복잡한 기술적 난제를 해결한다.
일반적으로 어떤 형태로든 아키텍처 프레임워크와 같은 것은 필요하다.
프레임워크의 목적
- 도메인 모델을 표현하고 해당 도메인 모델을 이용해 중요한 문제를 해결하는 구현을 만들어내는 데 있다.
프레임워크는 가장 유용한 기능만 분별력 있게 적용한다면 구현과 프레임워크간의 결합이 줄어들어 차후 설계 의사결정을 더욱 유연하게 내릴 수 있을 것이다.
도메인 계층은 모델이 살아가는 곳
도메인 주도 설계에서는 오직 한 가지 특정한 계층만이 존재할 것을 요구한다.
- 도메인 모델은 일련의 개념을 모아놓은 것이다.
- 도메인 계층은 그러한 모델과 설계 요소에 직접적으로 관계돼 있는 모든 것들을 명시한 것이다.
- 도메인 계층은 업무 로직에 대한 설계와 구현으로 구성된다.
- MODEL-DRIVEN DESIGN에서는 도메인 계층의 소프트웨어 구성물이 모델의 개념을 반영한다.
- 도메인 주도 설계의 전제 조건은 도메인 구현을 격리하는 것이다.
SMART UI(지능형 UI) “안티 패턴”
이 패턴은 하나의 대안에 불과하며, 도메인 주도 설계 접근법과는 서로 양립할 수 없는 상호배타적인 길에 놓인 접근법이다.
- 프로젝트 경험이 많지 않은 팀에서 단순한 프로젝트에 계층형 아키텍처와 MODEL DRIVEN DESIGN을 적용한다면 험악한 학습곡선에 직면할 것이다.
- 팀원들은 복잡한 신기술을 통달해야 하고 객체 모델링을 학습하는 과정에서 차질을 빚게 될 것이다.
- 그러므로 여건이 된다면 모든 업무 로직을 사용자 인터페이스에 넣고, 애플리케이션을 작은 기능으로 잘게 나눈다.
- 나눈 기능을 각기 분리된 사용자 인터페이스로 구현해서 업무 규칙을 분리된 사용자 인터페이스에 들어가게 하라.
- 관계형 데이터베이스를 데이터의 공유 저장소로 사용하고 이용 가능한 최대한 자동화된 UI 구축 도구와 시각적인 프로그래밍 도구를 사용하라.
장점
- 애플리케이션이 단순한 경우 생산성이 높고 효과가 즉각적이다.
- 요구사항 분석 단계에서 결함이 발생하더라도 사용자에게 프로토타입을 배포한 후 요구에 맞게 제품을 변경해서 문제를 해결할 수 있다.
- 관계형 데이터베이스와 잘 어울린다.
단점
- 데이터베이스를 이용하는 방식 말고는 여러 애플리케이션을 통합하기가 수월하지 않다.
- 행위를 재사용하지 않으며 업무 문제에 대한 추상화가 이뤄지지 않는다.
- 복잡성에 금방 압도된다.
아키텍처에서 응집력 있는 도메인 설계가 시스템의 다른 부분과 느슨하게 결합될 수 있게 도메인 관련 코드를 격리한다면 아마 그러한 아키텍처는 도메인 주도 설계를 지원할 수 있을 것이다.
도메인 설계를 분리하는 데 실패한다면 이것은 실제로 어떤 상황에서는 재앙이 될 수 있다.
다른 종류의 격리
- 갖가지 이유로 여러분의 모델은 불분명해지고 모델의 효용성을 잃어버리게 될 수도 있다.
- 정말로 복잡한 도메인 모델은 그 자체로도 매우 다루기 어려워질 수 있다.
- 우선 효과적인 도메인 모델과 표현력 있는 구현이 함께 발전해 나가는 것과 관련된 기본적인 사항을 살펴보자.
- 결국 도메인을 격리할 때의 가장 좋은 점은 부수적인 것을 배제하고 도메인 설계에만 집중할 수 있다는 것이다.