도메인 주도 설계(Domain-Driven Design) in Real Project — 의존성 관리

Minseok
Cross-Platform Korea
10 min readJul 27, 2019

소프트웨어의 복잡성을 해결하기 위해 가장 중요한 것은 의존성을 관리하는 것입니다. 이를 해결하기 위해 시간이 흘러가면서 개발 방법론(methodology), 아키텍처(architecture) 등 개발의 문제를 해결하기 위해 다양한 방법들이 사용되고 많은 새로운 시도들이 이루어지고 있습니다. 각 패러다임(paradigm)들은 항상 탄생한 이유와 장/단점들을 함께 가지고 있습니다. 완벽한 패러다임은 현재까지 존재하지 않았습니다. 도메인 주도 설계(Domain-Driven Design, 이하 DDD)는 어떨까요?

Domain-Driven Design in Real Project — Dependency

TL;DR

  • 소프트웨어의 복잡성을 줄이기 위해, 가장 중요한 것은 소프트웨어를 구성하는 요소들을 정말 필요한 만큼만 연결하고 일관성을 유지할 수 있어야 합니다. (의존성 관리)
  • 도메인을 정의하고 구성한다는 것은 사용자가 사용하는 영역을 정의하고 설계하는 것을 의미합니다.
  • 도메인은 사용자가 필요로하는 최소한의 요구사항이자, 최대한의 요구사항입니다. 도메인으로 사용자가 사용하는 영역을 한정하고, 연결 관계(의존성)를 제어합니다.
  • DDD도 실제 프로젝트에 도입이 되면, 의존성과 관련된 여러 가지 문제들이 드러나기 시작합니다. 어떤 문제들을 가지고 있고, 그것을 해결하기 위해서는 어떻게 해야할까요?

소프트웨어의 의존성(Dependency)

무엇을 하기 위해 다른 것을 필요로 하는 것을 의존한다라고 합니다. 즉, 무언가와 연결되어 있다는 것은, 의존성을 가지고 있습니다. 소프트웨어에서의 의존 관계는 side-effect를 발생시킬 수 있습니다. 다음은 side-effect의 예시입니다.

  • 요구사항이 변경되면, 해당 요구사항과 관련된 모든 것을 확인해 보고 변경해야 합니다.
  • 기술적 요소가 변경되면, 해당 기술과 관련된 모든 것을 확인해 보고 변경해야 합니다. 필요에 따라 요구사항을 변경하는 경우도 발생합니다.
  • 변경 사항에 따라, 논의를 필요로 할 수 있습니다. 팀으로 이루어지는 프로젝트에서는 개인이 결정하여 진행하기 어려운 상황이 많습니다. 따라서, 변경된 부분과 관련된 담당자들에게 전달하거나 필요에 따라 회의를 진행하여 시간을 소요하게 됩니다.
  • 개발 도구가 변경되면, 소프트웨어와 개발 도구의 관련성 및 소프트웨어의 복잡성이 클 수록 migration에 소요되는 시간은 크게 늘어납니다.
  • 협업을 할 때, 소프트웨어와 관련된 의존 관계가 많을 수록, 인수인계 시간은 크게 늘어납니다.

현대에도 소프트웨어에서 가장 두렵고 시간을 많이 소요하는 작업은 변경입니다. 이는 의존 관계가 많이 있기 때문만이 아니라, 인지하지 못하고 있는 의존 관계들도 존재할 수 있기 때문입니다. 사소한 변경도 소프트웨어 서비스에 문제가 발생할 수 있고, 기업이라면 큰 불이익을 안겨줄 수도 있습니다.

따라서, 소프트웨어의 복잡성(complexity)을 줄이기 위해, 가장 중요한 것은 요소 간의 연결 관계(의존성)을 제어하는 것입니다.

소프트웨어의 복잡성(Complexity)

소프트웨어는 얼마나 복잡할까요? 일반적으로 많은 사람들이 사용하는 소프트웨어는 단시간에 개발되지 않습니다. 수많은 사람들의 요구사항을 충족시켜야하며, 범용성과 편의성을 제공할 수 있어야합니다. 웹 어플리케이션(web application)은 사용자 트래픽(traffic)을 예측 및 제어할 수 있어야 합니다. 또한 이것을 위해 많은 사람들의 의견과 겉으로 보이지 않는 곳에서 개발을 위한 보조 소프트웨어들이 사용되기도 합니다.

소프트웨어 복잡성서로 다른 위치에 존재한 것들이 서로 얼마나 많이 연결되어 있는가로 말할 수 있습니다.

소프트웨어의 복잡성을 줄이기 위해서는 소프트웨어를 구성하는 요소들을 정말 필요한 만큼만 연결하고 일관성을 유지할 수 있어야 합니다.

하지만 소프트웨어의 범위는 사실상 무한히 증가할 수 있습니다. 단순히 변수(variable) 하나에서부터, 팀의 구성, 사용자 수 등 소프트웨어는 지속적인 성장의 과정을 거칠 수 있습니다. 이 때, 사람이 통제하는 것은 다음과 같은 한계를 지닙니다.

  • 모든 것을 기억할 수 없습니다.
  • 모든 것을 전달할 수 없습니다.
  • 무언가를 찾는 데 시간이 소요됩니다.
  • 모든 것은 완벽하지 않습니다. Ex) 자동화를 한다면? -> 자동화를 한 부분에서 문제가 발생한다면?

이에 따라 소프트웨어를 구성하는 요소들의 연결은 계속 증가하고, 결국, 그 연결들을 제어할 수 없는 순간들과 마주칩니다. 이를 해결할 수 있는 방법이 있을까요? 사람을 더 고용해야 할까요? 보조 소프트웨어를 더 사용해야 할까요?

인터페이스(Interface)

사용자가 소프트웨어의 범위와 비교하면, 사실, 바라보는 영역은 대부분 극히 일부에 지나지 않습니다. 우리는 그 영역을 사용자 인터페이스(User Interface, UI)라고 말합니다. 일반적으로 UI는 소프트웨어의 화면을 의미하고 UI 디자이너 디자인하여 기획자나 개발자에게 공유하게 됩니다. UI를 더 넓은 범위에서 바라보면, UI는 그래픽 인터페이스(Graphic UI, 이하 GUI)가 될 수도 있고, API(Application Programming Interface)라고 불리는 사용자에게 공유하는 프로그램 간의 데이터 전달 규칙이 될 수도 있습니다.

그렇다면 사용자 인터페이스(User Interface)의 역할은 무엇일까요? 간단하게는 사용자에게 그것을 사용하는 방법을 제공합니다. 이보다 더 중요한 역할은, 사용자가 사용하는 영역을 한정시킨다는 것입니다. 사용의 범위를 한정시키는 것은 사용자의 자유를 제한한다는 점에서 부정적이게 보일 수도 있지만, 한편으로는 그 인터페이스가 원하는 것을 할 수 있다는 것을 보장한다 것을 말합니다. 다시 말하면, 의존성 관리 사용자에게 공유하기 위한 인터페이스를 정의하고 설계하는 것을 의미합니다.

이를 위해 UX(User eXperience)를 생각할 수 있습니다. UX는 사용자가 생각하는 방식, 환경, 경험, 편의 등 사용자와 관련된 모든 것을 고려하게 됩니다. 즉, 사용자에게 정말 필요로 하는 UI를 추출하고 그것을 사용하기 위한 최적의 방법을 제공할 수 있도록합니다. 따라서, 연결 관계(dependency)를 제어하기 위해서는 UX를 얼마나 고려했느냐에 달려있습니다. 이는 생각보다 단순하지 않습니다. 일반적으로 소프트웨어의 GUI는 UX 디자이너라고 불리는 분들에게 달려있습니다. API는 어떨까요? 일반적으로는 반드시 개발자가 관여해야 합니다. 안타깝게도 겸업을 하지 않는 한, 개발자는 UX 지식과는 거리가 있습니다. 당장 무언가를 개발해야하는 데, 너무 많은 것을 생각해야하는 것 같습니다. UX를 공부해야 하는 것일까요?

이를 해결하는 방법은 상황에 따라 여러 가지가 있습니다. 예를 들면 다음과 같습니다. 이 중에서는 이론을 공부해서 알 수 있는 것들도 있고, 실무 경험을 통해 알 수 있는 것들도 있습니다.

  • 사용자(UX 디자이너, 다른 개발자, 기획자, 고객 등)가 요구하는대로 개발합니다.
  • 사용자와 논의를 통해 UX를 해결해 나갑니다.
  • Open source 또는 다른 개발들과의 협업 경험을 통해 익힌 관습적인 인터페이스를 사용합니다.
  • 기술적인 anti-pattern 등을 인지하고 인터페이스 작성을 고려합니다.
  • 문서에 기록하고 공유하여 사용자가 직접 익히도록 합니다.

이 모든 것들은 시간, 장소, 사람과의 관계, 업무 등 당장 해야하는 목적 이외의 다른 무언가와 반드시 trade-off 해야 합니다. 눈 앞의 목적을 달성하기 위해 trade-off를 최소화하려면 어떻게 해야할까요?

의존성 관리

의존성 관리는 소프트웨어 복잡성 해결을 위한 가장 중요한 목표입니다. 앞에서 서술한 내용처럼, 의존성 관리는 단순히 프로그래밍 코드를 작성하는 것에 국한되는 것이 아닙니다. 이를 해결하기 위해 수많은 패러다임이 나타났습니다. 애자일(agile)/폭포수(waterfall) 개발 방법론(methodology) 등 프로세스를 효율화하기 위한 것, 절차 지향 프로그래밍(Procedural Programming)/객체 지향 프로그래밍(Object-Oriented Programming)/함수형 프로그래밍(Functional Programming) 등 프로그래밍 패러다임, Monolitic Architecture/SOA(Service-Oriented Architecture)/MSA(Microservice Architecture) 등 아키텍처 패러다임 등, 많은 소프트웨어 프로젝트들은 단순한 개발이 아니라 이러한 패러다임 속에서 탄생합니다.

DDD도 그 중 하나입니다. DDD는 도메인(domain)을 이용하여, 인터페이스를 정의하고 구성합니다. 도메인은 사용자가 사용하는 것을 의미합니다. 인터페이스는 사용자가 바라보는 영역입니다. 즉, 도메인을 정의하고 구성한다는 것은 사용자가 사용하는 영역을 정의하고 설계하는 것을 의미합니다. 도메인으로 그 영역을 한정하고, 연결 관계(의존성)를 제어합니다.

도메인을 이용하는 것과 그렇지 않은 것의 차이는 사용자가 생각하고 바라보는 것 그대로 인터페이스로 표현하느냐(DDD), 내가 표현하는 인터페이스를 사용자가 생각하고 바라보게 하느냐(다른 패러다임들)로 말할 수 있습니다.

도메인 주도 설계(Domain-Driven Design) in Real Project — 도메인에서 DDD는 사고방식이라고 하였습니다. 사용자가 무엇을 필요로 하는지 먼저 생각하고, 사용자가 알 필요가 없는 부분은 사용자에게 공유하지 않음으로써, 의존성을 관리합니다. 모든 것은 이 도메인을 중심으로 이루어집니다. 도메인은 사용자가 필요로하는 최소한의 요구사항이자, 최대한의 요구사항입니다. 모든 연결은 사용자가 필요로 하는 것들과 관련되어 있습니다.

그리고, 도메인은 소프트웨어 전체를 관통합니다. 이는 Self-documenting code를 가능하게 할 뿐만 아니라, 요구사항 수집부터 소프트웨어가 배포되고 사용자에게 공유되기까지 모든 것을 도메인으로 일관성 있게 유지할 수 있습니다. 더 나아가서, 도메인(보편 언어)을 통해, 모두가 인지할 수 있는 범위 안에서 효율적으로 협업이 이루어질 수 있도록 합니다.

따라서, 각 도메인을 통한 영역의 한정은, 불필요한 연결 관계를 제거하고, 그 개념들과 관계성을 사용자/도메인 전문가/개발자들이 명확하게 인지하고 사용자들을 위해 더 많은 것을 생각할 수 있는 길을 제공합니다.

이제 도메인만 이해하고 꽃길만 걸으면 되는 것일까요?

아쉽지만, 앞에서 언급한 다양한 패러다임들은 각각의 이유와 장단점을 가지고 있습니다. DDD도 실제 프로젝트에 도입이 되면, 의존성과 관련된 여러 가지 문제들이 드러나기 시작합니다. 어떤 문제들을 가지고 있고, 그것을 해결하기 위해서는 어떻게 해야할까요?

--

--