Study
MSA와 DDD
Fkaa
2023. 3. 13. 17:39
1. MSA?
- Microservice Architecture
- 비즈니스 도메인을 중심으로 서비스를 모델링하고 구현하는 아키텍처 스타일
- 도메인 서비스 간의 통신은 네트워크 기반의 HTTP API 또는 비동기 메시징 방식 등으로 이루어짐
- 각 도메인 서비스는 자체 DB를 가짐
- (반)Monolithic
- 하나의 프로젝트 구조 안에서 모든 도메인을 구현하는 방식
- MSA 전환을 고려해야 하는 시점
- 생존을 걱정하던 초기 스타트업에서 벗어나 비즈니스 규모가 어느 정도 궤도에 오르는 시점
- Monolithic 구조의 장점보다 단점이 부각되는 시점
- 하나의 Repository에 코드 베이스가 개개인이 감당할 수 없는 수준으로 커짐
- 이에 따라 코드 파악과 유지보수가 어려워짐
- 구현과 테스트, 배포의 속도가 점점 느려지고 정기 배포라는 절차가 생김
- 모든 측면에서 확장성이 떨어지게 됨
⇨ Monolithic의 단점이 부각되는 시점에서 현 상황을 변화시키지 않는다면, 기업 경쟁력은 점차 약화되고 길게 보면 생존하지 못할 수 있음
- MSA의 장단점
- 장점
- 각각의 비즈니스 도메인별로 독립적인 서비스를 운영할 수 있다.
- 빠른 구현과 배포가 가능해진다.
- 팀의 책임과 자율성이 극대화된다.
- 단점
- 네트워크 기반의 API 호출로 서비스가 구성되기 대문에 프로세스 간 통신에 비해 느리고 복잡하다.
- 일관된 트랜잭션과 데이터 정합성을 유지하기 어렵다.
- 테스트와 장애 추적, 모니터링 등이 쉽지 않다.
- 장점
2. Project Architecture
- 좋은 구현이란?
- 비즈니스 가치를 명확히 충족해야 한다.
- 유저의 경험과 회사의 목표보다 본인이 사용하게 될 기술스택에만 높은 관심을 가져서는 안 된다.
- 기술은 도구일 뿐
- 도구에 익숙해지고 보다 좋은 도구를 리서치하는 것은 결국 비즈니스 목표 달성을 위한 것
- 잘 읽혀야 한다(= 가독성이 좋아야 한다.)
- 도메인 로직을 설명하는 별도의 문서보다는 코드 자체로 파악할 수 있어야 한다.
- 코드로 표현할 수 없는 시스템 전체 아키텍처, 데이터 Flow 등은 문서로 기술되어야 하지만, 코드 레벨의 도메인 설명은 충분히 코드로 파악할 수 있도록 작성되어야 한다.
- 도메인 로직을 설명하는 별도의 문서보다는 코드 자체로 파악할 수 있어야 한다.
- 테스트 코드 작성이 쉬워야 한다.
- 테스트 코드는 지속적인 기능 런칭과 리펙토링을 가능하게 해주는 안전장치
- 코드 간의 의존성이 많다면 테스트 코드 자가성이 어려움
- 테스트 코드 작성이 쉬운 코드는 대체적으로 코드 품질이 좋다.
- 변경에 유연해야 한다.
- 요구사항은 언제든지 변경될 수 있고, 이는 당연한 것이다.
- 코드 구현과 설계는 요구사항 변경에 유연하게 작성되어야 한다.
- 객체지향 SOLID
- 단일 책임 원칙(SRP)
- 개방 폐쇄 원칙(OCP)
- 리스코프 치환 원칙(LSP)
- 의존관계 역전 원칙(DIP)
- 인터페이스 분리 원칙(ISP)
- 객체지향 SOLID
- 도메인 주도 설계(DDD)
- MSA Architecture의 컨셉을 생각하면 비즈니스 중심으로 서비스를 모델링하고 구현하는 것이 중요
- 도메인 주도 설계
- 각각의 복잡한 도메인을 모델링하고 표현력 있게 설계하는 것을 도메인 주도 설계(DDD: Domain Driven Development)
- 비즈니스 가치를 명확히 충족해야 한다.
- Project Archetecture
- 도메인 주도 설계에서 말하는 일반적인 엔터프라이즈 애플리케이션 레이어 구성을 참고
- 레이어 간의 참조 관계에서는 단방향 의존을 유지하고 계층 간 호출에는 인터페이스를 통해 호출되도록 한다.
- Layer별 특징과 역할
Layer Description 사용자 인터페이스
(Interface)사용자에게 정보를 보여주고 사용자의 명령을 해석하는 책임을 진다. 응용 계층
(Application)수행할 작업을 정의하고 표현력 있는 도메인 객체가 문제를 해결하게 된다.
이 계층에서 책임지는 작업은 업무상 중요하거나 다른 시스템의 응용 계층과 상호작용하는 데 필요한 것들이다.
이 계층은 얇게 유지되고, 오직 작업을 조정하고 아래에 위치한 계층에 포함된 도메인 객체의 협력자에게 작업을 위임한다.도메인 계층
(Domain)업무 개념과 업무 상황에 대한 정보, 업무 규칙을 표현하는 일을 책임진다.
이 계층에서는 업무 상황을 반영하는 상태를 제어하고 사용하며, 그와 같은 상태 저장과 관련된 기술적인 세부사항은 인프라 스트럭쳐에 위임한다.
이 계층이 업무용 소프트웨어의 핵심이다.인프라 스트럭쳐 계층
(Infrastructure)상위 계층을 지원하는 일반화된 기술적 기능을 제공한다.
이러한 기능에는 애플리케이션에 대한 메시지 전송, 도메인 영속화, UI에 위젯을 그리는 것 등이 있다.- Layer간 참조 관계
- Layer간의 참조 관계에서 Application과 Infrastructure는 Domain Layer를 바라보게 하고 양방향 참조는 허용하지 않는다.
- Domain Layer는 low level의 기술에 상관없이 독립적으로 존재해야 한다.
- 이를 위해 대부분의 주요 로직은 추상화되고, runtime시에는 DIP개념을 활용하여 실제 구현체가 동작하게 한다.
- 의존관계 확인을 위해서는 package와 import를 확인
- Layer 별 구현 상세
- Domain Layer
- Domain Layer의 역할
- 업무 개념과 업무 상황에 대한 정보, 업무 규칙을 표현하는 일을 책임진다.
- 이 계층에서는 업무 상황을 반영하는 상태를 제어하고 사용하며 그와 같은 상태 저장과 관련된 기술적인 세부사항은 Infrastructure에 위임한다.
- 이 계층이 업무용 소프트웨어의 핵심이다.
DDD의 목표는 기술보다는 도메인에 대한 모델에 집중해 더 나은 소프트웨어를 만들어 내는 것이다.
- 도메인 주도 개발 154p
- DDD에서 도메인 모델을 정의하고 구현하는 layer는 domain layer이기 때문에 DDD에서는 Domain Layer가 핵심이다.
- Domain Layer는 높은 추상화 레벨을 가져야 한다.
- Domain 로직에서는 어떤 기술을 사용했는지 보다 어떤 순서로 처리했는지가 더욱 큰 관심사이다.
- Doamin 업무는 추상화되고, 실제 구현은 다른 Layer로 위임(Infrastructure Layer, Application Layer)
- 효과
- 추상화된 Service 메서드를 읽기만 해도 업무 도메인의 흐름을 대략적으로 파악할 수 있다.
- 추상회된 실제 구현 기술은 요구사항 변경, 튜닝 등의 이유로 언제든지 교체가 가능해진다.
- 권장사항
- Domain을 대표하는 하나의 Service에는
@Service
를 사용하고, 하위레벨의 Service class에는@Component
를 붙여 Entry Point를 명확하게 한다.
- Domain을 대표하는 하나의 Service에는
- Domain Layer의 역할
- Infrastructure Layer
- Infrastructure의 역할
- 상위 계층을 지원하는 일반화된 기술적 기능을 제공한다.
- Domain Layer에 선언되고 사용되는 추상화된 interface를 실제로 구현하여 runtime시에 실제 로직이 작동되도록 한다.
- 세부 기술 스택을 활용하여 Domain의 추상화된 interface를 구현하는 것이므로 비교적 구현에서의 자유도를 높게 가져갈 수 있다.
- Domain Layer의 Service와 달리 Infrastructure에서는 구현체 간에는 참조 관계를 허용
- 다만, 순환참조가 발생하지 않도록 적절한 상하관계를 정의해야 한다.
@Component
의 사용- Domain Layer의 내용 참고
- Infrastructure의 역할
- Application Layer
- Application Layer의 역할
- 수행할 작업을 정의한다.
- 도메인 객체가 문제를 해결하도록 지시한다.
- 다른 애플리케이션 계층과의 상호 작용을 한다.
- 비즈니스 규칙은 포함하지 않으며, 작업을 조정하고, 다음 하위 계층에서 도메인 객체의 협력을 위해 업무를 위임한다.
- 해당 Layer는 얇게 유지한다.
- 작업을 조정하기만 하고 도메인 상태를 가지면 안 된다.
- Application Layer의 역할
- Interface Layer
- Interface Layer의 역할
- 사용자에게 정보를 보여주고, 사용자의 명령을 해석하는 책임을 진다.
- API를 설계할 때 없어도 되는 Request Parameter는 제거하고, 외부에 리턴하는 Response도 최소한으로 유지한다.
- API는 한번 외부에 오픈하면 바꿀 수 없는 것이라고 가정하고, 처음부터 제한적으로 설계하고 구현해야 한다.
- http, gRPC, 비동기 메시징과 같은 서비스 간 통신 기술은 Interface Layer에서만 사용되도록 제한한다.
- 외부 통신 기술의 교체로 인해 Domain Layer의 로직까지 변경되는 상황을 방지하기 위함
- Interface Layer의 역할
- Domain Layer
위 내용은 Fastcampus의 The Red 강의 중
The RED : 비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축 by 이희창
을 참고하여 작성한 자료입니다.