마이크로 서비스(MSA)를 어떻게 나눌까? II

* 과거에 메모 수준의 관련 글을 남겼는데 이를 보완할만한 경험이 생겨서 조금 더 읽을 만한 글을 씁니다.

두 가지 사례를 소개합니다. 하나는 해당 업무 자체가 갖는 특성에서 출발한 마이크로 서비스 분리 사례입니다. 이를 도메인 주도라고 부르고 싶은데, 비즈니스에 적합한 모양으로 유연성을 구사하는 전략에 대한 실천 사례입니다. 두번째는 다른 이들이 만든 결과물을 참조하여 우리 시스템에 맞게 적용해보는 방식입니다.
두 사례 공유가 여러분이 보다 과감하게 더 나은 코드를 만들 수 있는 자극이 되었으면 하는 마음입니다.

비즈니스에 맞게 나눌 필요가 발생할 때

이미 만들어진 화면 개선사항을 한 동료가 UI 관련 툴로 정의하고 있었습니다. 그 중 한 화면이 아래 그림에서 보이는 Discount Rule Set in Details 입니다. 동료가 UI 개선 사항을 추가하니 전보다 유익해보였습니다. 그런데, 처음에 붙였던 화면 이름이 바뀐 화면을 지칭하는 이름으로는 어울리지 않았습니다. 그리하여 제 머리에는 이런 질문이 떠올랐습니다.
이 이름이 맞나? (처음과 달리 이제는) 할인 규칙을 상세하게 보자는 것이 아니라 이번 행사에 쓰일 상품과 해당 상품에 부여한 할인을 취사 선택하자는 것인데…
그래서 동료가 쓰는 도구안에 의견을 달았습니다. 파란 원으로 표시된 부분이 의견을 담고 있는 심볼입니다.[1]
presentation
경계구분 필요성을 드러낸 화면 정의 사례

동료에게 피드백을 하고 나니 자연스럽게 관련해서 내가 할 일이 떠올랐습니다.[2] 필자의 역할은 서구에서 주로 쓰는 표현인 제품 책임자 혹은 제품 오너 일을 하고 있습니다. 쉽게 말해서 개발자가 구현에 관련하여 질문을 할 때 (코딩 방법을 빼고는) 모든 답을 해줄 사람입니다. 그러한 터라 직접 찾아와 물은 것은 아니지만, 화면 이름과 내용이 다른 부분과 관련한 동료들의 의견을 위 툴에서 보면서 동료들이 헷갈려하는 부분을 포착했습니다.
그래서, 혼동을 막기 위한 조치가 필요하다 판단했습니다. 바로 마이크로 서비스 분리 필요성이 등장하는 상황입니다. 유의해서 보실 점은 당초에 마이크로 서비스를 나누자고 덤벼들거나 마이크로 서비스를 어떻게 나눌까 고민하면서 만난 순간은 아닙니다. 그저 동료들과 함께 우리의 일을 하는 가운데(Domain) 발생(-driven)했을 뿐이죠.

경계를 만드는 가장 쉬운 방법은 DB 분리

우리 시스템에는 공통으로 사용하는 상품 풀이 있습니다. 공용 데이터베이스에서 API 형태로 상품 정보를 제공하는 식이죠. 그런데, 상품에 대해 두 개의 입장이 존재하는데 오래도록 상품을 마스터 DB 안에 넣어두고 써 온터라 개발자들이 구분해야 할 필요를 못 느낍니다. 그 인식을 만들어줄 필요가 있다는 생각에 그린 그림이 아래 그림입니다.
상단에 간단한 설명을 달고 두 개의 시스템 입장을 브랜드와 衣恋惠选(판매 채널 이름)으로 나눕니다. 우리 실제 사례(도메인)이니독자분들은 둘을 A와 B 정도로 이해하셔도 무방합니다. 다만, 커머스의 맥락이 드러나게 예시를 보여드리는 편이 설명에는 다소 효과적이라 보고 실제 자료를 노출합니다. 타입으로 표현하면 브랜드는 상품 공급 시스템(회사 혹은 서비스)에 해당하고 衣恋惠选이라 표기한 박스는 상품 판매 시스템(회사 혹은 서비스)이라고 할 수 있습니다[3]. 사례의 구체적인 사항보다 여기서 중요한 점은 아래와 같은 구분의 핵심은 상품 DB가 두 개가 된다는 뜻입니다.
presentation
도메인 주도로 경계를 나누는 예시
구체적으로 들어가면 단순히 DB만 나누는 일은 아닙니다. 하지만, DB 분리로 나머지 일들이 쉽게 풀립니다. 적어도 개발자와 소통할 때는 가장 쉽게 말하는 방법입니다. DB를 나누면 자연스럽게 API 를 만들어야 하고, 컨슈머와 프로바이더 코드가 등장하죠. 그리고, 양쪽의 무결성을 지켜주기 위한 프로그래밍을 해야 합니다. 즉, 비즈니스를 완결하기 위한 이벤트나 규칙 등을 순차적으로 정의하고 구현해야 하죠.[4]
구체적으로 우리 비즈니스를 소개할 수는 없지만, 글의 이해를 위해 약간의 부가 설명을 하겠습니다. 상품을 공급하는 입장과 온라인 혹은 오프라인에서 물건을 파는 입장은 다릅니다. 보통은 양자간에 계약에 준하는 행위를 하죠. 대충 아래와 같은 결정들이 오고갈 것으로 추측할 수 있습니다.
  • 판매 수수료를 어떻게 할 것인가? 공급 가격을 어떻게 할 것인가?
  • 재고는 얼마나 확보해줄 수 있는가? 팔고 남은 부분은 누가 책임지는가?
  • 할인이나 마케팅 행사 비용은 누가 부담하는가?
더 많은 질문이 있겠으나 위 질문들만 보아도 두 개의 입장이 있음을 알 수 있습니다. 상품에 관련해서도 자신들의 규칙(어떤 할인을 부착할지 등등)과 판매 수량 등을 설정하는 화면이 필요한데, 입장이 두 개니 화면도 두 개가 필요합니다. 게다가 각자의 입장은 상충할 가능성이 매우 높습니다. 그런 가운데서 서로 정보를 실수로 노출해도 위험하고, 하나의 DB를 사용하면 서로 행위가 상호 간섭하는 일(DB Lock에 따른 대기 시간 등)을 불러 일으킬 수 있습니다.

Bounded Context 구현 방법으로서의 마이크로 서비스

전에 역시 메모 수준으로 Bounded Context라는 표현을 소개한 일이 있습니다. Domain-Driven Design 에서 소개한 개념입니다. 앞에서 설명한 사례 즉, 위에 설명한 이유로 DB를 분리하고 자연스럽게 하나였던 상품 모듈(혹은 마이크로 서비스)을 둘로 나눈 일이 바로 DDD 에서 말하는 Bounded Context 적용 사례의 하나로 볼 수 있습니다. DDD를 마이크로 서비스 수준에서 적용할 수 있습니다. 오래된 책이지만, 복잡한 비즈니스를 다루는 프로그래밍을 하신다면 견고한 구현을 위해 여전히 유효한 책이니 참조하시기 바랍니다.
presentation
모델 일관성을 유지하기 위한 방법들

주문 개선을 하자고 동료가 그린 그림

이번엔 두 번째 사례입니다. 참조 모델 응용 사례죠. 이커머스 경험이 많은 한 동료가 우리 주문 코드 문제를 제기했습니다. 그러면서 아래와 같은 그림을 그려 보여주며 개발자 회의를 소집했습니다. 표기법에 일관성이 없긴 하지만, 설명을 들으니 의도를 대강 짐작할 수 있었습니다. 문제는 이커머스 경험이 적은 동료들은 가뜩이나 생소한 내용인데 표기법조차 통일되지 않은 부분탓에 이야기를 편안하게 듣지 못하는 모습이었습니다. 따라서 대화가 아닌 강의 분위기(?)로 흘러갔습니다. 필자는 어떻게 하면 다수의 청자와 발표자 사이의 간격을 좁혀 생산적인 결론을 낼 수 있을까 고민하며 듣고 있었습니다.
presentation
동료가 그린 자유형식의 도해
시간이 길어질수록 전달되는 부분이 적어지고 있다 확신하자 빠르게 아래와 같은 그림으로 편집해서 화제 전환을 시도했습니다. 그리고, 분위기가 조금은 좋아진 인상을 받았죠.

presentation
마이크로 서비스 단위의 책임 할당 예시
상세 설명 대신에 위에서 굵은 선으로 묶은 부분은 관련성이 높은 것들을 묶자는 제안입니다. 소프트웨어 공학 표현을 쓰면 응집도cohesion을 높이는 구조 변경 제안이죠. 그리고 모듈이라고 쓴 부분은 가장 작은 기능 단위를 마이크로 서비스로 분류한 것입니다. 그런데, 이들 모듈과는 성격이 다른 녀석이 등장했습니다. 우리는 이를 Aggregate로 분류했는데, DDD에 나온 패턴 명을 (명확한 개념 정의 없이 편의상)차용한 말입니다. 그리고 Aggreate라고 분류한 코드 내부에도 성격이 다른 코드를 분류할 수 있어 필자가 편한 말로 App와 Front Service, State Machine 등의 표현을 쓴 후에 동료들에게 의도를 설명했습니다.

암묵적 참조 모델 사용

회의가 끝난 후에 내가 그린 그림이 어디서 본 것과 비슷하다는 생각이 들어 찾아봤습니다. 팝잇에 썼던 글에 흔적을 남겨두어 쉽게 찾을 수 있었습니다. 아래 그림을 필자가 그대로 모방한 것은 아니지만, 생각의 기저에서는 참조하지 않았을까 추측해봅니다.
presentation
thoughtworks 글 참조하기

맺음말

마이크로 서비스 아키텍처를 적용한 분들이 ‘어떻게 나눠야 할까?’를 놓고 고민하는 모습을 인터넷 상의 글에서 볼 수 있었습니다. 조금이라도 도움이 될 수 있을까 싶은 마음에 글을 써서 공유합니다.
마지막으로, 강조하고 싶은 한가지는 앞서 소개할 두 사례 모두 사전에 기준을 만들어 나눈 것이 아니란 점입니다. 일단, 비즈니스가 희망하는 속도에 최대한 맞춰 구현한 이후에 구조 개선을 실천하는 과정의 일부입니다. 즉, 사전에 굳이 무리하게 힘을 들일 필요가 없이 만들고 유지하는 과정에서 경계가 드러나기 쉽다는 경험을 말씀드립니다.
한 가지 덧붙이면, 우리나라 기성 조직에서는 참조모델이나 베스트 프랙티스를 먼저 찾고 이를 접목하는 경향을 많이 봅니다. 쓸 만한 방법이긴 하지만, 참조 모델 자체보다는 우리 실정에 맞게 구현하는 부분이 훨씬 중요하다는  사실을 잊어서는 안됩니다.[5]

주석

[1] 소개한 도구는 moqups 입니다 – https://app.moqups.com/
[2] 직전 글에서 다양한 사례로 언급했던 시너지의 또 다른 예시로 볼 수 있습니다.
[3] 별칭으로 업계에서 쓰이는 벤더나 채널 같은 말을 쓰기도 합니다.
[4] 혹자는 여기서 DB Link를 떠올리거나 분산 트랜젝션을 떠올릴 수 있는데, 둘은 통짜구조monolithic의 수호자라 할 만한 낙후 기술로 필자는 이들을 제거 대상으로만 볼 뿐 기술적으로 이들을 고려해서는 안된다고 확신합니다.
[5] 전에 오픈소스에 대한 미신과 배움의 비밀이란 글에서 솔루션부터 찾으면 100% 실패한다고 주장한 바 있습니다. 대략 살펴보면 비슷한 문제처럼 보여 이미 검증된 해결책을 가져다 댈 수는 있지만, 실제 적용하는 과정에서 문제의 초점 자체가 바뀌기 마련입니다. 아마도 그 이유는 우리 모두가 개성과 주체성을 띈 사람이고, 일을 하는 시간과 공간 역시 각자의 삶을 영위하는 시공간의 교차점이기 때문이 아닐까 추측해봅니다.