필요한 내용만 추려서 DDD 당장 써먹기

그런 일이 가능할까? DDD 같은 개념서를 다 읽지도 않고, 필요한 내용만 대충 훑어서 써먹는 식 말이다. 못할 이유가 뭐가 있는가? 가능하다. 책을 다 읽는다고 해도 소화한 내용 중에서 당장 응용할만한 부분만 구현에 써먹기 마련이다. 책을 다 읽으나 안 읽으나 어차피 일부만 소화해서 써먹을 수 있다면, 책을 안 읽고 써먹는 방법이 있다면 시도해보지 않을 이유가 없지 않는가? 물론, 그렇다고 책을 읽지 말자고 선동하는 것은 아니고 목적은 내 실력 배양에 있고, 응용을 해야 실력이 는다는 점을 강조하는 것이다.

BoundedContext 혹은 서브 도메인 보자마자 바로 써먹는 1인

요며칠 매일 만나는 한 동료가 실제로 그렇게 용감하게 써먹고 있다. 어느날 나에게 아래와 같은 그림을 보여주며, 내가 설명한 내용을 자신이 제대로 이해했는지 묻는 것이다. 이 글의 주제를 떠나 멋진 모방[1]이다. 프로그램 대상 영역을 덩어리로 나누는 모습을 만나자, 순발력을 발휘해서 최근 자신이 본 DDD 구현 책에서 본 내용을 사진 찍은 후에 자신의 당장의 용도에 쓰기 위해 덧칠한 그림으로 나와의 대화에 써먹었다. 그와 같은 순발력이나 가벼운 응용은 누구나 시도할 법한 일이다. 그가 행한 영역 분할은 요즘 유행하는 마이크로 서비스의 책임 영역을 나눌 때[2] 대부분의 상황에 비슷한 모습으로 별 어려움없이 활용할 수 있다.
presentation
[출처] Implementing Domain-Driven Design p115 그림 2.4

DDD 인지도 모르고 쓰고 있는 현상

한편, 자바 개발자들[3]사이에서 흔히 볼 수 있는 또 다른 현상이 있다. JPA나 ORM 솔루션을 쓰는 사람들은 라이브러리나 프레임워크 API가 제공하는 인터페이스나 애노테이션들을 활용하는 식으로 Entity 혹은 Repository 등의 DDD 구조물Buiding Block을 DDD 개념에 대한 이해 없이도 쓰고 있다. DDD 책을 읽지 않는다고 문제가 될 것은 없다.
하지만, 단순히 다른 사람이 만든 기술에 의존하는 식으로만 기술을 익히면, 암암리에 자기 발전의 한계를 지어버리는 일이 될 수도 있다. 각각 구조물이 어떠한 개념을 바탕으로 발전했는지 안다면 해당 기술(JPA 등)이 제공하는 이점과 한계점 등을 판단하는 힘이 생길 수 있다. 그럴수록 낭비하는 시간이나 오용 확률을 줄인다. 그리고, 개념과 원리를 이해하는 식이라서 다른 기술이나 언어를 접할 때에서 지식과 경험을 재활용하는데 수월하다.
이상에서 소개한 실제로 필자가 본 방법 말고도 DDD 책을 처음부터 읽지 않고, 필요한 내용만 골라서 써먹는 방법에 대해 상상할 수 있다.

DDD 구조물 분류를 빠르게 써먹기

어떤 방법으로 그렇게 할 수 있나? 필자는 여기에서 구현 방법이나 기술 자체를 한정하지 않고 DDD의 구조물 분류를 써먹는 방법을 소개하겠다. 구조 중심으로 프로그램의 일부 덩어리를 구성할 수 있는 힌트를 제공하는 것이 목표다[4]. 요즘 유행하는 마이크로 서비스 아키텍처 혹은 분산 앱 애플리케이션 구축으로 가정하고 예를 들어본다.

Entity 구조물로 마이크로 서비스 하나 만들어보기

제일 쉽게 활용할 수 있는 개념은 상대적으로 많은 사람들이 친숙한 엔터티Entity이다. 엔티티Entity는 간단히 말해서 식별번호(ID)를 부여하는 레코드를 의미한다. RDBMS의 엔티티와 같은 것이라고 생각해도 무방하다[5]. 어떤 대상에 식별번호를 부여하는 이유는 구체적인 데이터 내용을 바꾸기 위함이다. 예를 들면, 상품 번호로 추적하는 레코드는 지속적으로 상태가 바뀔 수 있다. 예를 들어, 어떤 상품을 만드는 생산업체는 자기들이 만든 물건이 품질 검사를 통과했는지 알고 싶고, 그래서 창고에는 얼마나 도착했는지, 그후에 인터넷 매장에서는 얼마나 팔렸으며, 반품이 된 상품은 지금 어디에 있는지 등등을 궁금해할 수 있다. 이러한 상태는 보통 데이터로 표현되는데, 그걸 추적하기 위해 식별번호(혹은 관리번호)가 필요하다.
그래서, 내용이 바뀌어도 같은 대상 즉, 엔티티를 지칭할 수 있게 하려고 식별번호를 부여하는 것이다. 사실 전살실이나 기업 정보처리 형태의 프로그램으로 개발을 배운 사람들은 대부분 이런 맥락에 익숙하다. 기업 인트라넷 경험이 많은 분(다른 말로 SI 경험이 있는 분)이라면 아주 익숙하다. 그리고 RDBMS를 쓰면 보통은 정규화를 통해 데이터 중복을 줄이려 하고 자연스럽게 엔티티 하나가 테이블 여러 개로 구현될 수 있다.
다만, 전통적인 전산실형 SI 경험만 갖고 있는 분이 활용하는 엔티티 개념과 DDD 엔터티 개념을 의미있게 써먹는 개발 사이의 가장 큰 차이는 바로 정합성Integrity 구현이나 보장 책임을 어디에 둘 것이냐에 있다. 사실 데이터베이스 인스턴스가 하나라면, DDD 엔터티의 효과가 크다고 할 수 없다. 데이터베이스가 여러 개 존재하도록 복제 DB를 만들고자 할 때 혹은 MSA 환경처럼 데이터베이스가 분산 형태로 응용 프로그램으로 제어될 때 DDD 엔터티 개념의 막강함이 위력을 발휘한다. 정 반대로 프로그램 바깥에서 DB 작업(Job) 이나 프로시저를 활용해 데이터 정합성을 보장하는 상황이라면 DDD 사용따위는 꺼리는 편이 좋다.
그런 의미에서 2016년 초에 Spring Boot와 JPA를 사용하는 간단한 샘플은 구조에 대한 감을 제공하는데 써먹을 만 하다. 그 이유는 엔티티를 RestController로 노출하는 예인지라 엔티티를 시작으로 초간단 마이크로 서비스 만들기 HelloWorld 버전 정도로 볼 수도 있기 때문이다. RestController 뒤에 있는 엔티티(혹은 엔티티와 저장소Repository 조합)가 데이터베이스를 포함한다는 가정으로 책임 경계 혹은 다른 프로그래머와 협업 경계를 나눌 수 있기 때문이다.

presentation

JSON 형태의 데이터 출력
한편, 엔티티를 구현할 때 반드시 RDBMS를 써야 할 이유는 없다. 파일이나 NoSQL로 저장하는 편이 더 나은 경우도 있다.

Aggregate 구조물로 마이크로 서비스 하나 만들어보기

엔티티 사이에 연관관계가 있고, 관련 규칙이 있을 경우 이를 묶어 두는 일은 객체지향의 캡슐화 이점을 활용하는 좋은 방법이다. 인터넷에서 판매를 수행하는 물품의 경우 제조업자가 부착한 식별번호와 이커머스 사이트가 부여한 식별번호 모두를 갖는 경우가 흔히 있다. 만일 여러분이 작성하는 프로그램이 이커머스 사이트의 엔터티라면 이커머스 판매자용 식별번호를 기준으로 데이터를 관리한다. 이 경우 참조할 필드로 제조업자가 부탁한 식별번호를 쓸 수도 있다. 이 경우는 그저 이름이나 가격과 같은 하나의 데이터일 뿐이고, 보조적인 식별자 역할을 할 수는 있지만 그 범주에서는 엔티티의 식별값은 아니다. 만일 여러분이 짜는 프로그램이 제조업자의 시스템이라도 정반대다. 이와 같이 엔터티 사이에 연관성이 있을 때 복수의 엔티티를 묶은 구조물을 조립물Aggregate이라고 한다.
기본적으로 조립물도 복합적인 엔티티일 뿐이기 때문에 조립물 단위로 하나의 마이크로 서비스 혹은 RestController[6]를 구현할 수 있다. 필자의 동료가 쓴 기사에 있던 그림을 보면 대충 상상해 볼 수 있다.

presentation

마이크로 서비스 소통의 도구로 쓸 수 있는 값 객체

같은 동료가 썼던 DDD 값 객체와 마이크로서비스에서 다뤄진 내용이다. 흔히 값 객체Value Object를 말할 때 대표적으로 주소 데이터를 예로 들지만, 마이크로 서비스 환경에 어울리는 값 객체는 특정 시점의 데이터를 보관하는 스냅샷 자체일 수 있다. 동료의 기사에서 관련 내용을 발췌해보자.
주문 업무의 특징 중 하나는 주문 당시 데이터(상품, 쿠폰, 결제, 회원, 배송지 등 - 이하 스냅샷Snapshot)를 기준으로 주문 처리를 한다는 것이다. 이러한 스냅샷 데이터를 모두 엔터티로 설계한다면 도메인 모델은 매우 복잡해질 것이다.
이 경우 보통 JSON 문자열로 구현하는 객체를 값 객체로 볼 수 있다. 값 객체의 중요한 특징이 수정할 수 없다는 뜻의 Immutability 인데, 스냅샷이란 말도 같은 특징을 강조하는 말이다. 그런데 이 스냅샷을 저장하는 객체와 구현 방식은 여러 가지를 상상할 수 있다.  어떤 마이크로 서비스가 호출을 하며, 스냅샷 데이터를 보내주는 주체는 어떤 프로그램이냐에 따라서 말이다.
그러한 다양한 방식 중에서 한 가지를 앞선 글의 필자가 암시하는 내용이 있다. 인용한 아래 그림에서 하나의 원통으로 표현한 뭔가(채널)가 다른 여러 개 서비스와 연결되어 있다. 구현 기술에 대한 부분을 특정하지 않고 보면, 하나의 스냅샷을 여러 곳에 전달해야 한다는 상황이라 할 수 있다.
presentation
값 객체 대신 도메인 이벤트를 적용해보기
이와 같은 경우에 스냅샷을 하나의 도메인 이벤트Domain Event라는 또 다른 DDD 구조물로 정의할 수 있다. 이벤트란 우리 말로 사건을 말하는데, 프로그램 개발을 하는 우리의 영역안에서 의미있게 보는 사건이 바로 도메인 이벤트다. 해당 사건에 대한 정보를 수정되지 않는 값으로 전달하면, 여러 개의 서로 다른 프로그램에 전달하는 상황에서 유리한 점들이 생긴다. 예를 들면, 모두 전달되었는지를 한 곳에서 감시하고 통제하는 일을 분산시킬 수 있고, 네트워크 불안으로 설사 전달이 되지 않은 경우가 발생하면 어차피 수정되지 않는 값이기 때문에 다시 전달하는 부담도 적다.

설정 파일에서 읽어올 정보가 있다면 Factory 적용 후보

Spring 프레임워크 내부 코드를 보면 팩토리Factory 구현체가 다수 존재한다. SaaS 형태로 기업용 서비스를 구축하는 우리 경우에도 태넌트 유형별로 화면 구성이나 기능 구성이 달라져야 하기 때문에 설정 파일을 읽어서 돌아가는 프로그램 구성을 달라지게 하기 위해 Factory 패턴을 쓰자고 제안한 일이 있다. 보통 설정 파일으로 런타임 작동 방식을 변경하려고 할 때 팩토리는 유용한 구조물이다.

데이터나 콘텐츠가 아닌 서비스

가장 축적하기 어려운 구조물이 서비스Service가 아닌가 싶다. 서비스는 레코드 저장이나 디지털 형태의 콘텐츠를 관리하는 수준 이상의 부가적인 응용 프로그램 로직을 담을 때 명실상부해진다. 과거에 MVC 패턴 보급 초기에 자바 진영의 경우 웹 혹은 표현 계층의 클래스 이름 뒷부분에 Controller를 붙이고, 데이터베이스 접근하는 DAO(혹은 Repository) 앞 부분에 대개는 단순히 DAO를 호출하는 부분을 계층으로 두고 Service로 끝나도록 작명 규칙이 쓰여지고는 했는데 빈약한 서비스 구현의 전형이다. 아직 해당 도메인의 서비스를 구조물로 식별해내고 코드로 구현할만큼 시간과 인식이 쌓이기 어려웠던 시절이었다. 지금은 어떤가? 기업마다 천차만별이지만, 다른 구조물에 비해 창의적이고 디지털화 한 기업에서 식별하고 구현 가능한 부분임에는 틀림없다.

결론

나는 DDD 책을 매우 좋아한다. 여기 써놓은 내용처럼 구체적으로 뭔가를 써먹고 아니고 수준이 아니고, 내가 하고 있는 소프트웨어 개발에 대해 진지하게 생각하게 이끌어 복잡한 소프트웨어를 함께 만드는 일이 무엇인지 맥락을 알려준 책이다. 하지만, 그런 개인적 감상은 나의 것일 뿐이다. 당장 실용적으로 무언가를 써먹을 수도 있다는 생각에 배경지식없이 무턱대고 책을 읽다가 내려놓을 분들을 한 사람이라도 줄일 수 있을까 하여 이 글을 썼다.

주석

[1] 원본에 레이어를 하나 입혀서 내 생각을 대응을 해보는 방식은 아주 빠르고 적은 노력으로 학습할 수 있는 일이다. 언젠가 나의 학습 노하우를 공개하는 글을 쓸 생각인데, 그게 현실로 이뤄지면 그때 다시 다뤄보자.
[2] 내가 주로 한국 SI 현장에서 일할 때 보면, 데이터베이스 전문가와 응용 개발자 사이에는 보이지 않는 단단한 벽이 있는데, DB 모델러들이 주제영역 나누는 내용이 마이크로 서비스 분할의 기준과 거의 같은 내용이다. 물론, DB 모델러는 주제영역에 따라 물리적으로 데이터베이스 인스턴스를 나누겠다고 하면 기겁하는 사람들이 많을 것으로 추정된다.
[3] 자바 개발자 사이에서만 나타나지는 않을 듯하지만, 다른 개발자 커뮤니티는 잘 모른다.
[4] 완전한 따라하기 튜토리얼을 원한다면 이 글이 큰 도움을 줄 수 없다.
[5] 물론, 데이터 저장 구조체가 아니라 객체를 대상으로 하니 DDD 엔터티와 RDBMS의 엔티티가 정확하게 같지는 않다. 하지만, 코딩을 통해 몸으로 익힌다고 가정하면, 개념에 대한 이해를 처음부터 아주 정교하게 이해하지 않아도 괜찮다.
[6] 마이크로 서비스 혹은 RestController라고 썼다고 해서 마이크로 서비스와 RestController를 같은 의미로 쓴 것은 아니다. RestController를 구현하는 일이 간단한 마이크로 서비스의 뼈대 정도를 설명할 수 있다고 생각하며 글을 쓴다.