Study

MSA와 DDD

Fkaa 2023. 3. 13. 17:39

1. MSA?

  • Microservice Architecture
    • 비즈니스 도메인을 중심으로 서비스를 모델링하고 구현하는 아키텍처 스타일
    • 도메인 서비스 간의 통신은 네트워크 기반의 HTTP API 또는 비동기 메시징 방식 등으로 이루어짐
    • 각 도메인 서비스는 자체 DB를 가짐
  • (반)Monolithic
    • 하나의 프로젝트 구조 안에서 모든 도메인을 구현하는 방식
  • MSA 전환을 고려해야 하는 시점
    1. 생존을 걱정하던 초기 스타트업에서 벗어나 비즈니스 규모가 어느 정도 궤도에 오르는 시점
    2. Monolithic 구조의 장점보다 단점이 부각되는 시점
      • 하나의 Repository에 코드 베이스가 개개인이 감당할 수 없는 수준으로 커짐
      • 이에 따라 코드 파악과 유지보수가 어려워짐
      • 구현과 테스트, 배포의 속도가 점점 느려지고 정기 배포라는 절차가 생김
      • 모든 측면에서 확장성이 떨어지게 됨
        ⇨ Monolithic의 단점이 부각되는 시점에서 현 상황을 변화시키지 않는다면, 기업 경쟁력은 점차 약화되고 길게 보면 생존하지 못할 수 있음
  • MSA의 장단점
    • 장점
      • 각각의 비즈니스 도메인별로 독립적인 서비스를 운영할 수 있다.
      • 빠른 구현과 배포가 가능해진다.
      • 팀의 책임과 자율성이 극대화된다.
    • 단점
      • 네트워크 기반의 API 호출로 서비스가 구성되기 대문에 프로세스 간 통신에 비해 느리고 복잡하다.
      • 일관된 트랜잭션과 데이터 정합성을 유지하기 어렵다.
      • 테스트와 장애 추적, 모니터링 등이 쉽지 않다.

2. Project Architecture

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

위 내용은 Fastcampus의 The Red 강의 중
The RED : 비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축 by 이희창
을 참고하여 작성한 자료입니다.