DDD와 MSA 기반으로 좋은 서비스 개발하기
컬리의 서비스 개발 원칙
제가 컬리호에 탑승한지도 벌써 5개월차가 되고 있습니다. 커머스 플랫폼 전반을 MSA와 DDD 기반으로 전환하고 있는데요, 서비스 개발 원칙에 대해 말씀드리려고 합니다.
MSA를 탄생시킨 도메인 주도 개발(DDD)이란?
MSA를 말씀드리기에 앞서, 먼저 DDD부터 말씀드리는게 순서여서, DDD부터 말씀드리겠습니다.
DDD(Domain-Driven Development)는 2003년 에릭 에반스가 Domain-Driven Design이라는 책을 처음 출간하면서 소개한 개발 방법론으로, "훌륭한 소프트웨어를 개발하고 싶다면 서비스 도메인에 귀를 기울여라"라는 슬로건으로부터 시작되었고, 현재는 서비스 개발에 가장 큰 주류를 이루고 있는 개발 방법입니다.
오늘날 가장 보편화된 시스템 아키텍처인 MSA(Micro Service Architecture)를 구현하는 필수 개념들은 DDD로부터 왔는데, DDD에서 좋은 서비스를 개발하기 위한 핵심 기본 요소인 Loose Coupling(느슨한 결합)과 High Cohesion(높은 응집)은 MSA를 설계할 때 꼭 기억해야 할 설계 원칙입니다.
DDD의 주요 설계 원칙: Loose Coupling(느슨한 결합)과 High Cohesion(높은 응집)
그럼 무엇을 Loose Coupling하고 무엇을 High Cohesion 해야 할까요? 바로 도메인입니다. 도메인들 간에는 Loose Coupling하고 도메인 내에서는 High Cohesion 해야 합니다. 도메인은 소프트웨어로 해결하고자 하는 문제의 영역, 즉 개발하고자 하는 전체 서비스를 잘라낸 단위를 가리키는데요, 도메인을 잘못 나누면 DDD나 MSA 입장에서는 많은 혼란이 가중됩니다. 왜냐하면, Loose Coupling 해야 하는 연동 인터페이스를 High Cohesion 하게 되어 시스템 복잡도를 높이거나, High Cohesion 해야 할 서비스들 간을 Loose Coupling 해서 예상하지 못한 시스템 문제를 야기할 수 있기 때문입니다.
따라서, 도메인을 잘게 나누는 것, 즉 Loose Coupling 시키는 것만이 능사가 아니라, 어떤 서비스들을 하나의 도메인으로 잘 묶어서 High Cohesion 하게 할지 설계하는 것까지가 DDD나 MSA가 추구하는 지향점이 되어야 합니다. 즉, 도메인을 Loose Coupling과 High Cohesion 관점에서 잘 나누는 것이 DDD와 MSA에서 가장 중요하다 할 수 있습니다. 비즈니스 문제를 잘 투영한 서비스 도메인을 잘 나누는 것에서부터 시작하며, 각 도메인 서비스들이 Loose Coupling과 High Cohesion 각각을 지원할 수 있는 기술적 또는 아키텍처적 설계 원칙을 준수하는 것이 좋은 서비스 시스템을 개발하는 기본 원칙입니다.
Loose Coupling과 High Cohesion 설계 원칙이 잘 적용된 서비스 도메인을 도식화하면 다음과 같습니다.
DDD로 MSA를 해석하기
MSA는 DDD를 기반으로 아키텍처 패턴을 정의한 것인데요. 위 DDD의 설계 원칙(Loose Coupling과 High Cohesion)을 MSA에 적용하면, 도메인 내 마이크로서비스와 도메인 외부 마이크로서비스로 구분될 것이고, 내부 인터페이스인지 외부 인터페이스인지에 따라 마이크로서비스들 간의 커뮤니케이션 방식, 즉 설계 원칙이 달라질 것입니다.
즉, 위 그림의 예를 들면, Domain A 내 마이크로서비스들은 API 기반의 Sync Call이나 같은 DB를 바라 볼 수 있으며, Domain A에 있는 마이크로서비스가 Domain B의 마이크로서비스들과 커뮤니케이션 하기 위해서는 Async 방식의 메시지 기반 통신을 수행하고 DB도 분리되어야 할 것입니다.
MSA 설계 원칙
마틴 파울러가 정의한 MSA의 핵심 이점 3가지를 Loose Coupling과 High Cohesion 원칙으로 해석하여 정리하면 다음과 같습니다. (참고: 마이크로서비스의 장단점을 설명한 글)
1. Strong Module Boundaries (명확한 모듈 경계)
MSA 구조에서 마이크로서비스의 가장 큰 장점은 모듈 경계가 명확하다는 것입니다. 즉, 시스템 변경 사항이 발생하면, 변경할 특정 도메인 내 마이크로서비스 단위만 이해하고 처리하면 된다는 것입니다. 만약, 제대로 된 경계를 가지지 못한다면, MSA로 인한 마이크로서비스로의 분리는 장점이 아닌 큰 핸디캡이 될 수 있습니다.
MSA가 제공하는 가장 기본적인 장점을 얻기 위해서, 앞서 말씀드린 도메인을 잘 나누는 것이 얼마나 중요한지 생각해 보실 수 있습니다.
2. Independent Deployment (독립적 배포)
MSA는 앞서 말씀드린 대로 Loose Coupling이나 High Cohesion와 같은 의존성 관계를 고려하여 시스템을 설계, 구축함으로, 각각의 마이크로서비스를 독립적으로 배포하는 것을 용이하게 합니다. 최근 DevOps 환경에서 CI/CD가 자동화되고 강화될 수 있었던 것은 MSA의 힘이 크다고 생각하며, 이는 MSA가 배포 단위까지 고려해서 설계하기 때문입니다. 개인적으로, MSA가 SOA(Service-Oriented Architecture)보다 진화한 대표적인 것이 바로 배포를 고려한 설계라고 생각합니다.
3. Technology Diversity (기술 다양성)
각각의 마이크로서비스의 독립성이 강화되면서, 마이크로서비스 내의 기술 선택이 자유로워졌습니다. 도메인 내 마이크로서비스들은 High Cohesion의 원칙에 따라 최대한 유사한 기술 스택을 가져가야 하지만, 도메인 밖의 마이크로서비스들은 Loose Coupling의 원칙에 따라 해당 서비스 도메인의 문제를 더 잘 해결할 수 있는 기술 스택을 가져갈 수 있게 된 것입니다.
다만, 너무 다양한 기술의 도입은 복잡성이나 비효율을 초래할 수 있어, 조직 성숙도에 따라 잘 조절해야 하며, 기술 다양성이 강화되면 강화될수록 다른 서비스 도메인 간의 연동 인터페이스를 설계하는 원칙을 보다 면밀히 검토해야 합니다.