86 lines
8.4 KiB
Markdown
86 lines
8.4 KiB
Markdown
---
|
|
title: company-tech-blog / Explicit Architecture — DDD, Hexagonal, Onion, Clean, CQRS 통합 (Herberto Graça)
|
|
source_type: company-tech-blog
|
|
url: https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/
|
|
archive_url:
|
|
related_branches: [feature-application-query-bypass-contract]
|
|
related_projects: [ca-skeleton]
|
|
tags: [architecture, hexagonal, cqrs, query-handler, read-model, application-service, ddd, clean-architecture, ca-skeleton]
|
|
created: 2026-06-04
|
|
last_reviewed: 2026-06-04
|
|
---
|
|
|
|
# Explicit Architecture — DDD, Hexagonal, Onion, Clean, CQRS 통합 (Herberto Graça)
|
|
|
|
> Layer: `raw/company-tech-blogs/` — Herberto Graça 의 "DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together" (2017-11-16) 발췌. hexagonal 아키텍처에서 CQRS query handler 가 Application Service (Use Case) 를 어떻게 다루는지의 대표적 설명.
|
|
>
|
|
> **출처 신뢰도**: `engineering-blog` 등급 — 저자의 개인 기술 블로그. 공식 표준 아님. 그러나 DDD/hexagonal/CQRS 통합 설명에서 커뮤니티에서 자주 인용되는 article.
|
|
|
|
## Parent / 활용 branch (필수)
|
|
|
|
| Branch | 이 자료가 정당화하는 결정 |
|
|
|---|---|
|
|
| [[raw/branch-notes/feature-application-query-bypass-contract]] | D2 (use-case layer ceremony 의 bypass — CQRS query handler 가 Application Service 를 거치지 않고 직접 optimized query 를 실행하는 패턴) 의 architectural reference. query side 가 "optimized query that will simply return some raw data" 로 작동하는 설계 근거 |
|
|
|
|
## 출처 / Source
|
|
|
|
- 원본 URL: https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/
|
|
- 아카이브 URL:
|
|
- 저자 / 조직: Herberto Graça — 개인 기술 블로그 (hgraca.com)
|
|
- 발행일: 2017-11-16
|
|
- 마지막 확인일: 2026-06-04
|
|
|
|
## 왜 저장했는지 / Why archived
|
|
|
|
ca-tmpl 의 alternative 3 (CQRS query handler pattern) 의 architectural reference. Graça 는 hexagonal + CQRS 통합 설명에서 query handler 가 Application Service 와 다른 역할을 한다는 것을 명시적으로 설명. 특히 "The Query object will contain an optimized query that will simply return some raw data" 는 query side 가 domain aggregate 로딩 없이 직접 DTO 반환이 가능함을 시사.
|
|
|
|
## 핵심 인용 / Key quotes (verbatim)
|
|
|
|
> [§CQRS query side — query object] "The Query object will contain an optimized query that will simply return some raw data to be shown to the user."
|
|
|
|
> [§Application Services — role definition] "Application Services (also known as workflow services, use cases, or interactors) are used to orchestrate the steps required to fulfill the commands imposed by the client."
|
|
|
|
> [§Application Services — typical steps] "1. use a repository to find one or several entities; 2. tell those entities to do some domain logic; 3. and use the repository to persist the entities again."
|
|
|
|
> [§Command/Query Bus without separate bus] "Controllers can depend on Query objects [directly], distinct from Application Services."
|
|
|
|
> [§DTO for view] "That data will be returned in a DTO which will be injected into a ViewModel."
|
|
|
|
## Claims Extracted / 추출된 주장
|
|
|
|
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|
|
|---|---|---|---|---|---|
|
|
| HGRACA-CQRS-C1 | CQRS query side 에서 Query object 는 **optimized query** 를 담고 user 에게 보여줄 **raw data** 를 반환하도록 설계됨 — 도메인 aggregate 조작 없이 단순 데이터 반환 | [§CQRS query side] "The Query object will contain an optimized query that will simply return some raw data to be shown to the user." | `engineering-blog` | CQRS query side 설계 — query handler 가 Application Service 를 거치지 않는 패턴 | "모든 읽기가 Use Case Application Service 를 거칠 필요 없다" 는 공식 표준이 아님 — engineering-blog 등급의 저자 설계 의견 |
|
|
| HGRACA-CQRS-C2 | Application Service (Use Case, Interactor) 의 역할은 **command 를 오케스트레이션** — entity 를 repository 로 find, domain logic 실행, repository 로 persist 하는 3단계 | [§Application Services] "Application Services...are used to orchestrate the steps required to fulfill the commands imposed by the client." + "1. use a repository to find one or several entities; 2. tell those entities to do some domain logic; 3. and use the repository to persist the entities again." | `engineering-blog` | command side (write path) 의 Application Service 역할 정의 | **query side** 에도 Application Service 가 필요하다는 주장의 근거는 아님 — 이 3단계는 command 를 대상으로 명시 |
|
|
| HGRACA-CQRS-C3 | query side 에서 반환되는 데이터는 **DTO** 형태로 ViewModel 에 주입됨 | [§DTO for view] "That data will be returned in a DTO which will be injected into a ViewModel." | `engineering-blog` | CQRS query side 반환 타입 — application layer 가 JPA entity 를 직접 반환하지 않음 | DTO 가 반드시 별도 record/class 여야 한다는 강제는 아님 — interface projection 도 DTO 패턴의 변형으로 간주 가능 |
|
|
| HGRACA-CQRS-C4 | Query Bus 없는 구조에서 **Controller 가 Query object 에 직접 의존** 하는 패턴이 제시됨 — Application Service 를 거치지 않는 thin read path 의 구조적 근거 | [§Without Command/Query Bus] "Controllers can depend on Query objects [directly], distinct from Application Services." | `engineering-blog` | Command/Query Bus 를 별도 도입하지 않는 단순 CQRS 구현 | Controller 가 Query object 에 직접 의존해도 hexagonal 의 **transport 타입이 application layer 에 leak 해선 안 된다** 는 제약은 본 인용이 직접 다루지 않음 |
|
|
|
|
## Usage Boundaries / 적용 경계
|
|
|
|
- 이 자료가 직접 증명하는 것:
|
|
- `HGRACA-CQRS-C1`: query side 가 "optimized query + raw data return" 으로 작동할 수 있다는 설계 제안
|
|
- `HGRACA-CQRS-C2`: Application Service 의 3단계 오케스트레이션은 **command path** 에 명시적으로 귀속
|
|
- `HGRACA-CQRS-C3`: query side 반환 타입은 DTO (domain entity 가 아님)
|
|
- `HGRACA-CQRS-C4`: Controller → Query object 직접 의존 패턴 (bus 없는 CQRS)
|
|
- 이 자료가 증명하지 않는 것:
|
|
- hexagonal 아키텍처에서 "thin read path" 에도 transport type (HTTP, gRPC) 이 application layer 에 leak 하지 않아야 한다는 설계 제약 — Graça 의 diagram 은 이 경계를 명시하지만 본 발췌 인용에는 포함되지 않음
|
|
- Query object 또는 query handler 를 ArchUnit 으로 정적 강제하는 방법
|
|
- Spring Boot 환경에서 query handler 를 어느 Gradle module 에 배치하는지
|
|
- transaction 없는 thin read path 의 Hibernate session 동작
|
|
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
|
|
- ca-tmpl 의 thin read path 에서 `@Controller` (org.springframework.web) 타입이 application port 에 노출되지 않도록 query service / read port 를 어느 layer 에 배치할지 결정 (D1 의 핵심)
|
|
- ca-tmpl 의 ArchUnit rule 이 Controller → QueryService 직접 의존을 허용할지, 또는 QueryUseCase (인터페이스) 를 항상 중간에 두도록 강제할지
|
|
|
|
## 메모 / Notes
|
|
|
|
- Graça 의 글은 2017년 작성이지만 hexagonal + CQRS 통합에서 가장 자주 인용되는 레퍼런스 중 하나. 한국어 번역본도 존재.
|
|
- HGRACA-CQRS-C1 의 핵심 의미: query 는 domain 오케스트레이션 없이 read-optimized path 로 처리 가능 → Application Service (Use Case) 를 무조건 통과할 필요가 없음을 지지. 단 engineering-blog 등급이므로 official-vendor-doc 이나 official-standard 대비 낮은 신뢰도.
|
|
- HGRACA-CQRS-C4 에서 "Controller 가 Query object 에 직접 의존" 한다는 설명은 ca-tmpl 의 hexagonal rule (web adapter 가 application layer 를 거쳐야 함) 과 충돌처럼 보이나, Query object 가 application layer 에 위치하면 interface dependency 는 여전히 inward pointing — hexagonal violation 아님
|
|
|
|
## Related / 관련
|
|
|
|
- [[raw/official-docs/cqrs-fowler-bliki]] — CQRS 정의 상위 문서
|
|
- [[raw/company-tech-blogs/domain-event-sourcing-vs-cqrs-greg-young]] — CQRS 원작자 Greg Young 의 정의
|
|
- [[raw/official-docs/spring-data-jpa-projections-spring-official]] — projection (DTO) 의 Spring 공식 mechanism
|
|
- [[raw/branch-notes/feature-application-port-usecase-contract]] — QueryUseCase 선행 계약
|