Search

CQRS, DDD, GraphQL은 엔터프라이즈 애플리케이션 개발에 어떻게 활용될 수 있는가?

Tags
Architcture
GraphQL
DDD
CQRS
Last edited time
2025/08/10 13:26
2 more properties

1. 서론

1.1. 들어가기에 앞서

이 컨텐츠는 CQRS, DDD, graphql을 함께 사용하여 확장 가능하고 유지보수 가능한 엔터프라이즈 애플리케이션을 구축하는 방법을 설명
graphql은 비즈니스 모델을 풍부하게 노출하는 얇은 계층 역할을 하며, CQRS는 읽기/쓰기 모델을 분리하여 효율적인 데이터 처리를 가능하게 하고, DDD는 복잡한 비즈니스 도메인을 소프트웨어 모델에 효과적으로 반영하도록 도움
이 세 가지 기술의 조합은 특히 대규모 엔터프라이즈 환경에서 클라이언트에게 통합된 비즈니스 모델을 제공하고 스키마 변경에 대한 안정성을 보장하는 데 강력한 시너지를 발휘

1.2. 각 개념의 핵심 역할

클린 아키텍처
애플리케이션을 도메인, 애플리케이션, 인프라, 프레젠테이션 계층으로 분리하여 외부 구성 요소로부터의 독립성과 높은 모듈성을 제공
CQRS (Command Query Responsibility Segregation)
시스템의 읽기(쿼리)와 쓰기(커맨드) 모델을 분리하여 각 작업에 최적화된 처리를 가능하게 함
DDD (Domain-Driven Design)
소프트웨어 모델을 비즈니스 요구사항과 일치시키고, 개발자와 도메인 전문가 간의 공유 언어(유비쿼터스 언어)를 사용하여 복잡한 비즈니스 문제를 해결하는 데 중점을 둠

2. GraphQL의 설계 의도와 엔터프라이즈 애플리케이션의 정의

2.1. GraphQL의 기본 개념과 설계 의도

Facebook(현재 Meta)가 만든 GraphQL은 비즈니스 모델을 노출하는 얇은 계층으로, REST보다 더 풍부한 데이터를 제공하는 것이 목적임.
GraphQL의 핵심은 세 가지 타입: 쿼리(읽기), 뮤테이션(쓰기/변경), 구독(이벤트 알림)임.
쿼리는 부작용 없는 읽기, 뮤테이션은 데이터 변경, 구독은 이벤트에 대한 실시간 알림을 담당함.

2.2. 엔터프라이즈 애플리케이션과 그 구조

엔터프라이즈 애플리케이션은 핵심 비즈니스 프로세스, 판매, 회계, 인사 등 모든 운영 단계를 통합하는 시스템임.
복잡한 시스템을 효율적으로 관리하기 위해 '클린 아키텍처', ' CQRS', '도메인 주도 설계(DDD)'라는 세 가지 패턴이 사용됨.
클린 아키텍처는 관심사의 분리와 모듈화, 외부 시스템(데이터베이스, 프레임워크 등)와의 독립성을 강조함.
계층 구조는 도메인, 애플리케이션, 인프라스트럭처, 프레젠테이션(그래프QL 포함)으로 나뉘며, 외부에서 내부를 참조하는 방향으로 설계됨.

3. 클린 아키텍처의 이해

3.1. 클린 아키텍처의 목적

관심사의 분리(separation of concerns)를 추구하고, 애플리케이션에 명확한 계층화를 도입하여 높은 모듈성을 제공하는 아키텍처 스타일.
외부 구성 요소(프레임워크, 데이터베이스 시스템 등)로부터 독립성을 확보하기 위해 사용됨.
기술적인 요소들은 빠르게 변화하므로, 애플리케이션 수명 주기 동안 교체할 수 있도록 독립성을 유지하는 것이 중요.

3.2. 클린 아키텍처의 계층 구조

도메인 계층: 핵심 비즈니스 모델(엔티티, 리포지토리 등)을 포함하며 변경이 적음.
애플리케이션 계층: 유스케이스를 조율하며, 도메인과 상호작용하는 역할.
인프라스트럭처 계층: 데이터베이스, 메시징 시스템 등 기술적 요소를 담당하며 교체 가능.
프레젠테이션 계층: 사용자 인터페이스 또는 API( GraphQL등)가 위치하며, 외부 계층이 내부를 참조함.

4. CQRS와 GraphQL과의 연계

4.1 CQRS의 기본 개념 및 역할

CQRS(Command Query Responsibility Segregation)는 명령(쓰기)과 조회(읽기) 모델을 분리하는 개념.
이 패턴은 애플리케이션 계층에서 비즈니스 사례나 유스케이스를 정의하는 데 사용됨
CQRS를 통해 애플리케이션은 웹샵의 결제와 같은 작업 기반(task-based) 상호작용을 수행할 수 있음
이는 도메인 계층과의 상호작용을 완전히 설명하는 하나의 명령으로 설계될 수 있음

4.2 CQRS와 GraphQL의 연관성

CQRS에서 명령(Commands)은 시스템에 부작용을 일으키는 GraphQL의 뮤테이션(Mutations)에 해당됨.
GraphQL은 CQRS와 동일한 추상화를 가지며, 부작용이 없는 읽기 모델인 쿼리(Queries)와 명령에 밀접하게 관련된 뮤테이션을 포함함.
뮤테이션을 수행하면 시스템에 미치는 영향을 즉시 읽을 수 있어, 클라이언트 애플리케이션이 서버에 추가 왕복(round trip) 없이 변경 사항을 읽고 클라이언트 저장소를 업데이트하기에 좋음.

4.3 CQRS와 GraphQL에서의 최종 일관성

CQRS는 최종 일관성(eventual consistency)을 수용함.
명령이 읽기 모델을 즉시 업데이트하고 변경 효과를 반환할 수도 있지만, 업데이트를 지연시킬 수도 있음.
예를 들어, 더 많은 비용이 드는 비동기 사용자 흐름은 완료하는 데 시간이 걸릴 수 있으며, 이 경우 최종 일관성을 사용하여 읽기 모델을 업데이트함.
GraphQL의 모범 사례는 변경 사항을 즉시 반환하는 것이지만, 다른 패턴도 존재함
뮤테이션 후 변경 사항 대신 트랜잭션 ID를 반환하고, 이벤트 구독을 통해 업데이트를 받을 수 있음
뮤테이션을 먼저 수행한 다음 구독해야 하므로 두 개의 연결이 필요.
이는 전송 계층에서 더 많은 작업을 요구.
최종 일관성은 UI부터 비즈니스 흐름까지 시스템에 복잡성을 더하므로, 필요한 경우에만 사용하는 것이 중요.
GraphQL쿼리는 CQS의 쿼리와 100% 일치하며, 읽기 모델에서 작동.

5. 도메인 주도 설계(DDD)의 핵심 개념과 GraphQL의 역할

5.1. DDD의 목적 및 유비쿼터스 언어

DDD의 정의 및 적용 대상
DDD는 복잡한 애플리케이션을 위한 전략적 설계 접근 방식.
클린 아키텍처, CQRS, DDD를 함께 사용하는 시스템은 장기적으로 유지보수 가능하며, 시간이 지남에 따라 구성 요소를 교체할 수 있도록 구축.
DDD의 핵심 목표: 유비쿼터스 언어(Ubiquitous Language)
DDD는 소프트웨어 모델을 비즈니스 요구사항과 일치시키고, 개발자와 도메인 전문가 간의 공유 언어인 "유비쿼터스 언어"를 사용하여 핵심 비즈니스 문제에 집중하도록 도움.
이 언어는 개발자와 이해관계자가 함께 비즈니스 작동 방식과 소프트웨어로의 전환에 대한 공통 이해를 구축하는 데 사용.
비즈니스를 이해하는 것이 DDD를 프로젝트에 적용하고 성공적인 소프트웨어 애플리케이션을 작성하는 데 핵심.
DDD의 목표는 복잡한 시스템을 단순화하고 이해하기 쉽고 유지보수 가능하게 만드는 것.

5.2. GraphQL 스키마와 DDD의 유비쿼터스 언어

GraphQL 스키마의 역할
GraphQL에서도 유비쿼터스 언어는 스키마
이는 비즈니스 모델을 사용자에게 노출하는 방식
풍부한 스키마를 통한 비즈니스 모델 표현
GraphQL 스키마는 비즈니스의 모든 측면을 설명하는 풍부한 정보를 담고 있음
예를 들어, removeProductStock 뮤테이션을 통해 제품 재고를 제거하는 비즈니스 로직을 표현할 수 있음
뮤테이션 실행 시 반환되는 제품 정보나 오류를 통해 어떤 도메인 오류가 발생할 수 있는지 정확히 확인할 수 있음
이러한 뮤테이션을 작성하고 비즈니스 모델에 대해 추론하는 것이 매우 유용
스키마 변경에 대한 유연한 대응
미래에 모델이 변경되어 새로운 예외나 도메인 오류가 도입될 경우에도 GraphQL의 뮤테이션 컨벤션 패턴을 통해 알려지지 않은 오류를 처리할 수 있음

5.3. 애그리게이트와 바운디드 컨텍스트(경계 컨텍스트)

애그리게이트는 관련 엔티티와 값 객체를 하나의 단위로 묶은 것임.
바운디드 컨텍스트는 특정 비즈니스 영역(예: 주문, 상품, 사용자)을 독립적으로 설계하는 개념임.
GraphQL에서는 각각의 바운디드 컨텍스트를 서브그래프로 구현하고, 이를 통합하는 '통합 스키마'로 관리함.
여러 바운디드 컨텍스트(서브그래프)는 각각 독립된 GraphQL서버 또는 스키마임.
이들을 하나의 '통합 스키마'로 묶는 게이트웨이(Orchestrator)가 있으며, Netflix는 4,000개 서브그래프를 운영하며 초당 600만 요청을 처리함.
클라이언트는 단일 통합 스키마를 통해 여러 비즈니스 영역에 접근하며, 내부 구현은 숨김.

6. DDDD의 이벤트와 GraphQL Subscription

6.1. DDD의 이벤트 종류

도메인 이벤트(Domain Events)
애그리거트(aggregate)와 엔티티(entity) 사이, 즉 바운디드 컨텍스트 내에서 발생하는 이벤트
이를 통해 엔티티를 격리하여 설계하고, 유스케이스 내에서 함께 상호작용하도록 조율할 수 있음
통합 이벤트(Integration Events)
다른 바운디드 컨텍스트의 엔티티 간에 발생하는 이벤트
메시징 시스템을 통해 설계될 수 있으며, 도메인 이벤트를 통합 이벤트로 변환하여 엔티티들이 상호작용하도록 함

6.2. GraphQL의 이벤트 시스템: 구독(Subscriptions)

GraphQL에도 이벤트 시스템이 있지만, 이는 주로 외부 세계, 즉 GraphQL 엔드포인트의 소비자들을 위한 것
"구독"이라고 불리며, 사용자가 구독하여 시스템에 변경이 발생할 때 쿼리를 실행하고 클라이언트 스토어를 업데이트하는 등 상호작용적인 경험을 제공함

7. DDD 도입의 장점과 고려사항

7.1. DDD 도입의 장점

소프트웨어와 비즈니스 요구사항 간의 정렬
소프트웨어 엔지니어들이 비즈니스 도메인을 깊이 이해하게 되며, 이해관계자와 개발자가 함께 시스템을 구축하여 시스템에 대한 더 깊은 이해를 얻음
유연성
구성 요소를 교체하거나 새로운 구성 요소를 도입할 수 있는 유연성을 제공
확장성
초당 6백만 건의 요청을 처리하는 시스템과 같은 대규모 확장성을 달성할 수 있는 기반을 제공
모든 어려운 결정을 지금 당장 내릴 필요는 없지만, DDD와 같은 패턴과 구조적 접근 방식은 필요할 때 시스템을 해당 수준으로 확장할 수 있게 해줌

7.2. DDD 도입의 문제점 및 고려사항

복잡성
적절한 DDD를 수행하려면 비즈니스를 깊이 이해하고, 여러 사람을 모아 비즈니스에 대한 공통 이해를 구축해야 함
그러나 엔지니어들이 비즈니스를 이해하는 것은 바람직한 문제임
시간 소모
새로운 프로젝트를 시작하거나 기존 프로젝트를 DDD 방식으로 리팩토링할 때 높은 초기 투자가 필요함
개발자들의 기술을 향상시키는 데도 시간이 걸리지만, 그만한 가치가 있음

8. GraphQL을 통한 엔터프라이즈 애플리케이션의 실현

8.1. 비즈니스 계층 위의 얇은 계층

GraphQL의 핵심 역할: 비즈니스 계층 위의 얇은 계층
GraphQL은 비즈니스 계층 위에 얇은 계층으로 설계됨
1.
제품 작업(product operations)과 같은 GraphQL 리졸버(resolver)는 매우 얇은 함수 또는 메서드로, 비즈니스 로직을 직접 포함하지 않음
리졸버는 단순히 미디에이터(mediator)를 주입하고 실행하여 결과를 반환함
쿼리 코드 또한 매우 간단하며, 데이터 요청 방식만 기술하고 실제 데이터 획득 구현(프레임워크 등)은 인프라스트럭처 계층의 데이터 로더(data loader)에 위임
데이터 로더는 데이터베이스에서 데이터를 가져오는 방법을 정의하며, 매핑, 정렬, 프로젝션, 페이징 등의 구현이 포함
이러한 구현은 교체 가능하며, 코드가 작고 이해하기 쉬워 추론하기 용이

8.2. 느슨한 결합 및 효율적인 데이터 페칭

GraphQL은 도메인 모델 간의 느슨한 결합을 가능하게 함
예를 들어, 브랜드와 제품 간의 관계는 도메인 계층에서 브랜드 ID를 통해 느슨하게 연결됨
데이터 로더를 통한 관계 해결
GraphQL 타입에서 브랜드 타입을 확장하고, products와 같은 추가 필드를 제공하여 다른 엔티티를 통합할 수 있음
이때 리졸버는 다시 미디에이터를 사용하여 브랜드별 제품을 가져오는 명령을 보냄
리졸버는 작동에 필요한 최소한의 데이터(예: 브랜드 ID)를 정의하고, 이를 통해 프로젝션(projection)을 수행할 수 있음
이러한 코드는 작고 반복적일 수 있지만, GraphQL 계층 없이도 독립적으로 테스트할 수 있어 유지보수성이 높음
인프라스트럭처 계층의 데이터 로더는 복잡한 배치(batching) 및 페이지네이션(pagination) 로직을 처리하여, 여러 브랜드 ID에 대한 제품 목록을 한 번에 가져오는 등 효율적인 데이터베이스 쿼리를 가능하게 함
간단한 GraphQL 계층
GraphQL 계층은 매우 평면적이고 간단하며, 대부분의 로직은 읽기 모델에서 추론되어 작동

8.3. 스키마 진화와 버전 관리

단일 스키마 접근
GraphQL의 복합 스키마는 모든 바운디드 컨텍스트를 하나의 스키마로 통합하여 모든 클라이언트가 접근할 수 있도록 함
클라이언트 파손 방지
GraphQL은 스키마 진화(schema evolution) 스토리가 REST보다 훨씬 뛰어나 클라이언트가 깨지는 것을 방지
스키마 레지스트리(Schema Registry)
Nitro와 같은 스키마 레지스트리는 게이트웨이와 하위 서비스(바운디드 컨텍스트)를 관리하고, GraphQL 서버를 사용하는 클라이언트들을 추적
개발 시 클라이언트는 쿼리를 작성하고 필요한 데이터를 정의
프로덕션 배포 시 빌드 프로세스는 클라이언트에서 쿼리를 제거하고, 이를 해시(hash)로 대체하여 스키마 및 클라이언트 레지스트리에 업로드
이후 애플리케이션은 REST 애플리케이션처럼 작동
GraphQL 서버는 클라이언트가 보낸 암호화된 해시를 스키마 레지스트리에 질의하여 해당 쿼리 정보를 얻고 처리

9. 결론 및 요약

GraphQL은 비즈니스 모델을 명확히 표현하고, 유연성과 확장성을 갖춘 엔터프라이즈 애플리케이션개발에 적합함.
DDD, CQRS, 클린 아키텍처와 결합하면, 유지보수성과 확장성을 높이면서도, 클라이언트와 서버 간의 안정적인 통신이 가능함.