--- title: 클린 아키텍처 — 개념·구조·장단점과 실무(대기업) 변형 비교 source_type: interview status: draft confidence: medium tags: [clean-architecture, hexagonal, package-layout, backend] related_projects: [ca-skeleton] last_reviewed: 2026-07-04 --- # 클린 아키텍처 — 개념·구조·장단점과 실무(대기업) 변형 비교 > **이 문서의 성격 (먼저 읽어 주세요)** > - 목적: 면접·개인 이해용으로 클린 아키텍처(Clean Architecture)의 개념/구조/장단점과, 실무·대기업에서 만든 변형이 원전과 무엇이 다른지를 한 곳에 정리한 **토픽 스터디 노트**입니다. > - 근거 등급 주의: 아래 사실은 대부분 **개인 저술(engineering-blog)** 또는 **회사 기술블로그 사례(company-case-study)** 에서 나온 것입니다. Uncle Bob·Cockburn 글조차 표준 기구 문서가 아니라 개인 블로그이며, 이 문서에서 유일한 공식 벤더 문서(official-vendor-doc)는 Microsoft의 ACL 패턴뿐입니다. 따라서 "공식 표준", "업계 best practice"라는 표현은 함부로 붙이지 않습니다. (CLAUDE.md §5) > - 파이프라인 주의: 이 파일은 CLAUDE.md 표준 디렉토리(`wiki/concepts/`·`wiki/interview/` 등)가 **아닌** `wiki/topics-interview/`에 사용자 요청으로 만든 노트입니다. 정식 면접 산출물이 필요하면 §9 "다음 단계"의 canonical 경유 절차를 따르세요. --- ## 0. 30초 요약 (쉬운 설명 먼저) - **클린 아키텍처의 핵심은 딱 한 문장입니다.** "의존성(import·참조)은 바깥에서 안쪽으로만 흐르고, 안쪽(비즈니스 규칙)은 바깥(DB·웹 프레임워크)의 존재를 몰라야 한다." 이걸 **Dependency Rule**(의존성 규칙)이라고 부릅니다. - **구조는 양파 같은 4개의 동심원**입니다. 안쪽부터 Entities → Use Cases → Interface Adapters → Frameworks & Drivers. 안쪽일수록 순수한 비즈니스 규칙, 바깥일수록 기술 세부사항입니다. - **장점**은 "도메인(핵심 업무 로직)을 DB·웹·프레임워크로부터 분리해서, 테스트하기 쉽고 기술 교체가 쉬워진다"는 것입니다. - **단점**은 "코드가 늘고(모델 간 매핑, 포트 인터페이스 폭증), 초기 학습·설계 비용이 크다"는 것입니다. 다만 이 단점을 **수치로 증명한 원전 자료는 거의 없습니다.** - **대기업 변형**(우아한형제들·Allegro 등)은 대부분 클린 아키텍처 그 자체가 아니라 **사촌 격인 Hexagonal / Onion을 자기 방식으로 구현**한 것입니다. 이 둘을 뭉뚱그려 "클린 아키텍처 대기업 사례"라고 말하면 과장입니다. --- ## 🖼 그림으로 보는 진화 — Layered → Hexagonal → Clean > 개념을 텍스트로 읽기 전에, 그림 3장으로 "왜 이런 게 나왔는가"의 흐름을 먼저 잡습니다. (렌더링용 SVG는 `raw/diagrams/clean-architecture-topic/*.svg`, 편집용 원본은 같은 폴더의 `.drawio`) ### (1) 출발점 — 전통적 Layered, 그리고 그 문제 ![[architecture-layered-2026-07-04.svg]] 전통적 계층형 구조는 위에서 아래로만 의존합니다: Presentation → Business → Data Access → DB. 겉보기엔 깔끔하지만 **의존성의 종착지가 DB**라는 게 문제입니다. - 비즈니스 규칙(Business)이 아래의 기술(Data Access·DB)에 의존하므로, **DB나 ORM을 바꾸면 도메인 로직까지 영향**을 받습니다. - 도메인을 테스트하려면 DB가 필요해 **테스트가 느리고 깨지기 쉽습니다.** - `controller/service/repository`로 자르면(package-by-layer) 한 도메인 코드가 세 폴더로 흩어져 **응집도가 떨어집니다.** (근거: [[raw/company-tech-blogs/feature-first-sahibinden-package-by-layer-vs-feature]]) ### (2) 해결 — Hexagonal (Ports & Adapters): 의존성을 뒤집는다 ![[architecture-hexagonal-2026-07-04.svg]] Hexagonal은 이 문제를 **의존성 역전(DIP)** 으로 해결합니다. 도메인(Application Core)을 한가운데 두고, DB·web을 전부 바깥의 adapter로 밀어냅니다. - core는 **port(interface)만 정의**하고, 실제 구현(web/DB adapter)이 그 port에 의존합니다. 즉 그림에서 **화살표가 전부 안쪽(core)을 향합니다.** - 그래서 core는 web·DB의 존재를 모릅니다 → **DB·web 교체가 자유롭고, 실제 장비 없이 격리 테스트가 가능**합니다. > "developed and tested in isolation from its eventual run-time devices and databases" — 출처: [[raw/official-docs/arch-hexagonal-cockburn]] ### (3) Clean Architecture — 같은 규칙, 4개의 링으로 ![[architecture-clean-concentric-2026-07-04.svg]] 클린 아키텍처는 Hexagonal과 **규칙이 같습니다**(의존성은 안쪽으로만). 다만 안쪽을 4개의 동심원으로 더 세분화합니다: Entities → Use Cases → Interface Adapters → Frameworks & Drivers. 핵심은 여전히 **The Dependency Rule** 하나입니다. > "source code dependencies can only point inwards" — 출처: [[raw/official-docs/arch-clean-architecture-uncle-bob]] ### (4) 그래서 새로 생기는 문제 (Clean / Hexagonal 공통) 문제를 해결하면 새 비용이 따라옵니다. 이게 §4에서 자세히 다룰 단점의 요지입니다. - **모델 매핑 비용** — 도메인 모델 ↔ JPA 모델을 분리하니 변환 코드가 늘어납니다. > "...with the cost of having to do mapping between the models" — 출처: [[raw/company-tech-blogs/arhohuttunen-hexagonal-architecture-spring-boot]] - **인터페이스(port) 폭증** — 외부 연계를 전부 port로 두다 보면 outputPort가 대량 생성됩니다. (출처: [[raw/company-tech-blogs/hexagonal-woowahan-techblog-2023]]) - **보일러플레이트·학습 곡선** — 구조가 늘어 초기 진입이 어렵습니다. (단, 정량 수치는 조사된 자료에 없음) - **레이아웃만으로는 규칙이 안 지켜짐** — ArchUnit·빌드 그래프 검사 같은 강제 수단이 없으면 경계가 새어 나갑니다. (출처: [[wiki/concepts/clean-architecture-package-layout]]) - **트랜잭션 경계 모호** — 구조를 나눠도 `@Transactional`을 어디 둘지는 별도 결정이 필요합니다(§5.5). --- ## 1. 클린 아키텍처란 무엇인가 (개념) ### 1.1 한 줄 정의와 핵심 규칙 클린 아키텍처는 Robert C. Martin(Uncle Bob)이 2012년 블로그 글 "The Clean Architecture"에서 정리한 아키텍처 스타일입니다. 핵심은 **Dependency Rule** 하나입니다. > 원문: "source code dependencies can only point inwards" — 소스 코드 의존성은 오직 안쪽으로만 향할 수 있다. > 원문: "Nothing in an inner circle can know anything at all about something in an outer circle" — 안쪽 원의 어떤 것도 바깥쪽 원의 존재(이름·타입·함수)를 전혀 알아서는 안 된다. > > 출처: [[raw/official-docs/arch-clean-architecture-uncle-bob]] (engineering-blog) 즉 "무엇이 무엇을 참조해도 되는가"의 **방향만** 규정하는 원칙입니다. 어떤 레이어가 안쪽인지는 이 한 문장이 정해 주지 않습니다(원전 스스로 명시). ### 1.2 개념적 뿌리 — 사실상 같은 가족 클린 아키텍처는 홀로 나온 게 아니라 그 이전 아키텍처들의 **재정리·통합**에 가깝습니다. 면접에서 이 가족 관계를 아는지 자주 묻습니다. - **Hexagonal Architecture (Ports & Adapters, Alistair Cockburn, 2005)**: "왼쪽/오른쪽"이 아니라 **inside(애플리케이션 코어) / outside(모든 외부)** 의 비대칭 하나로 시스템을 가른다는 발상. 클린 아키텍처의 직접적 뿌리입니다. - 원문: "The asymmetry to exploit is not that between left and right sides of the application but between inside and outside of the application" — 출처: [[raw/official-docs/arch-hexagonal-cockburn]] - **Onion Architecture (Jeffrey Palermo, 2008)**: 의존성이 외부(infra/UI)에서 내부(domain model)로만 향하는 동심원 모델. 규칙은 Hexagonal과 동등. 출처: [[wiki/concepts/clean-architecture-package-layout]] (canonical) - **Screaming Architecture (Uncle Bob, 2011)**: "아키텍처는 framework가 아니라 시스템(도메인)을 외쳐야 한다"는 자매 원칙. 최상위 패키지가 `controller/service/repository`가 아니라 업무 영역이어야 한다는 주장. - 원문: "Your architectures should tell readers about the system, not about the frameworks." — 출처: [[raw/official-docs/feature-first-uncle-bob-screaming-architecture-2011]] - **Anti-Corruption Layer (ACL, Microsoft / DDD Eric Evans 기원)**: 서로 다른 의미체계(semantics)를 가진 두 시스템 사이의 **번역 계층**. 클린 아키텍처의 경계 개념이 시스템 간 통합으로 확장된 형태. - 원문: "Implement a façade or adapter layer between different subsystems that don't share the same semantics. ... This pattern was first described by Eric Evans in Domain-Driven Design." — 출처: [[raw/official-docs/arch-acl-microsoft-pattern]] (이 문서에서 **유일한 공식 벤더 문서**) > **용어 한 줄 풀이** > - **port**: 애플리케이션 코어가 외부와 대화하는 "계약점"(인터페이스). OS의 포트 비유에서 따온 이름입니다. > - **adapter**: 그 port를 실제 기술(DB·HTTP 등)에 연결하는 양방향 변환기. > - **POJO**: Plain Old Java Object. 프레임워크 애노테이션 없는 순수 자바 객체. --- ## 2. 구조 (4개 동심원) 클린 아키텍처의 대표 그림은 4개의 동심원입니다. 안쪽부터: | 원 (안→밖) | 이름 | 무엇을 담나 | 원문 근거 | |---|---|---|---| | 1 (가장 안) | **Entities** | 엔터프라이즈 전역(most general) 비즈니스 규칙 | "Entities encapsulate Enterprise wide business rules" | | 2 | **Use Cases** | 애플리케이션 특화 규칙 + 모든 유스케이스 구현 | "application specific business rules. It encapsulates and implements all of the use cases" | | 3 | **Interface Adapters** | 유스케이스·엔티티에 편한 포맷 ↔ 외부(DB·웹) 포맷 변환 | "set of adapters that convert data from the format most convenient for the use cases and entities" | | 4 (가장 밖) | **Frameworks & Drivers** | DB, 웹 프레임워크 등 기술 세부사항 | "outermost layer is generally composed of frameworks and tools such as the Database, the Web Framework" | 출처: [[raw/official-docs/arch-clean-architecture-uncle-bob]] ### 2.1 경계를 어떻게 넘는가 — 의존성 역전(DIP) 제어 흐름(호출 방향)은 바깥→안으로 들어가지만, **소스 코드 의존성은 그 반대**여야 합니다. 이 모순을 인터페이스와 상속으로 뒤집는 것이 **DIP(Dependency Inversion Principle, 의존성 역전 원칙)** 입니다. > 원문: "we would arrange interfaces and inheritance relationships such that the source code dependencies oppose the flow of control" — 출처: [[raw/official-docs/arch-clean-architecture-uncle-bob]] 주의: 원전은 "인터페이스로 방향을 뒤집는다"는 **원칙만** 말하고, 구체적으로 DI 컨테이너를 쓸지 factory를 쓸지 등 **메커니즘은 지정하지 않습니다.** 그건 프로젝트별 결정입니다. ### 2.2 경계를 넘는 데이터의 형태 > 원문: "isolated, simple, data structures are passed across the boundaries" — 경계를 넘을 때는 고립된, 단순한 데이터 구조를 전달한다. 출처: [[raw/official-docs/arch-clean-architecture-uncle-bob]] 여기서 "ORM 엔티티를 그대로 넘기면 안 된다"는 강한 규칙까지 원전이 못 박은 것은 아닙니다(원전 스스로 그 일반화의 한계를 인정). 실무에서 DTO(Data Transfer Object)로 넘기는 관행은 원칙의 **해석**입니다. ### 2.3 Hexagonal과의 구조 차이 (면접 포인트) - 클린 아키텍처: **4개 동심원**으로 더 세분화. - Hexagonal: **inside/outside 이분법 + ports** 로 더 추상화. 육각형은 6이 중요해서가 아니라 "포트/어댑터를 그려 넣을 자리를 확보하려는 그림"일 뿐입니다. - 원문: "The hexagon is not a hexagon because the number six is important, but rather to allow the people doing the drawing to have room to insert ports and adapters as they need" — 출처: [[raw/official-docs/arch-hexagonal-cockburn]] - 이 둘의 정확한 1:1 매핑은 원전들이 서로 직접 비교한 게 아니라 후대의 종합입니다 (INFERENCE). --- ## 3. 클린 아키텍처의 장점 모두 원전이 직접 주장하거나(인용 있음) 널리 쓰이는 reference가 제시하는 이점입니다. 1. **테스트 격리성** — 실제 DB·웹서버 없이 도메인/유스케이스를 격리해서 테스트할 수 있습니다. Cockburn이 가장 명시적으로 내세운 장점입니다. > "Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases." — 출처: [[raw/official-docs/arch-hexagonal-cockburn]] 2. **도메인의 기술 독립성** — 도메인 코드가 DB나 웹 관심사에 의존하지 않게 만듭니다. > "Develop your domain code independent of database or web concerns." / "Free your domain layer of oppressive dependencies using dependency inversion." — 출처: [[raw/official-docs/hexagonal-thombergs-buckpal-github]] 3. **환경 결정의 지연** — 프레임워크·DB·웹서버 선택을 초기에 확정하지 않아도 됩니다. > "A good software architecture allows decisions about frameworks, databases, web-servers...to be deferred and delayed." — 출처: [[raw/official-docs/feature-first-uncle-bob-screaming-architecture-2011]] 4. **낮은 결합도** — 경계 간 전달이 단순 데이터 구조로 제한되어 레이어 간 결합이 낮아집니다(§2.2). 5. **도메인 가독성** — 최상위 구조만 봐도 "이 시스템이 무슨 업무를 하는지" 드러납니다(Screaming Architecture). --- ## 4. 클린 아키텍처의 단점 / 한계 > **정직한 경고**: "장점"은 원전 근거가 풍부하지만, **"단점"을 원전이 직접·정량적으로 인정한 근거는 매우 희박합니다.** 아래 중 원문이 직접 인정한 비용은 ACL의 latency 하나뿐이고, 나머지는 실무 사례(blog)나 합리적 추론(INFERENCE)입니다. 면접에서 이 구분을 지키는 것 자체가 신뢰도를 높입니다. 1. **모델 간 매핑 비용** — 도메인 모델과 영속성(JPA) 모델을 분리하면 그 사이를 변환하는 코드가 늘어납니다. (저자 직접 인정) > "Here we have a clean separation of those concerns with the cost of having to do mapping between the models." — 출처: [[raw/company-tech-blogs/arhohuttunen-hexagonal-architecture-spring-boot]] 2. **인터페이스(port) 폭증** — 외부 연계를 전부 인터페이스로 두다 보면 outputPort가 대량으로 생깁니다. (실무 사례가 자인) > "수많은 outputPort 인터페이스들이 생겨나게 되었습니다." — 출처: [[raw/company-tech-blogs/hexagonal-woowahan-techblog-2023]] 3. **ACL의 지연(latency)** — 번역 계층을 두면 두 시스템 간 호출에 지연이 더해질 수 있습니다. (**이 문서에서 유일하게 공식 벤더 문서가 직접 인정한 단점**) > "The anti-corruption layer might add latency to calls made between the two systems." — 출처: [[raw/official-docs/arch-acl-microsoft-pattern]] 4. **원칙 선언 ↔ 실행 가이드의 간극** — Screaming Architecture 같은 원전은 철학 선언 수준이라, 실제로 패키지를 어떻게 자를지의 구체적 가이드는 부족합니다. (INFERENCE — raw 문서 작성자 해석) 5. **레이아웃만으로는 경계가 안 지켜짐** — 어떤 레이아웃을 골라도 규칙 위반은 자연히 새어 나갑니다. 별도의 강제 수단(빌드 그래프 검사, ArchUnit 같은 정적 분석 fitness function)이 있어야 build 시점에 막을 수 있습니다. 그마저도 runtime lookup·reflection 우회는 못 잡습니다. 출처: [[wiki/concepts/clean-architecture-package-layout]] (canonical §경계를 강제하는 방법) 6. **정량 비용은 근거 부재** — 보일러플레이트 증가율, 개발 속도 저하 %, 팀 규모별 손익분기점 같은 수치는 조사된 어떤 자료에도 없습니다. "느려진다/코드가 는다"는 정성적으로만 말할 수 있습니다. --- ## 5. 실무·대기업 변형 — 원전과 무엇이 다른가 ### 5.0 먼저 알아야 할 것 (혼용 주의) 조사한 11개 실무 문서 중 **"Clean Architecture(CA)"를 직접 지칭한 것은 3개뿐**입니다(UNIL TransactionPort, wakita CQRS-lite, Buckpal 책 제목). 나머지 8개(우아한형제들 2건, Allegro, Herberto Graça, Reflectoring, Arho Huttunen, Sahibinden, kamilmazurek)는 스스로를 **Hexagonal / Onion / Layered** 로 부릅니다. → 따라서 "이건 A사의 클린 아키텍처다"라고 뭉뚱그리는 것은 대부분 근거 없는 일반화입니다. 정확히는 "**클린 아키텍처 계열(Hexagonal/Onion 포함)의 실무 변형**"입니다. ### 5.1 우아한형제들 — 4-Hexagon 멀티모듈 - **상황(context)**: 비즈니스 요구사항을 빠르게 개발해야 하면서, 기술 선택에 드는 고민 비용을 줄이고 팀 단위 제품 오너십을 강화하려던 상황. (근거: 아래 장점 인용) - **원전과 다른 점**: 헥사곤을 4개(Domain / Application / Framework / Bootstrap)로 정의하고, 각각을 **Gradle 물리 모듈**로 강제합니다. 원문이 "핵사곤(Layer)"이라고 표기하듯, Cockburn의 단일 application core나 Uncle Bob의 4-circle과 명명·경계가 다릅니다. (구조 자체는 사실, 원전과의 대조는 INFERENCE) > "총 4개의 핵사곤(Layer)으로 정의하였습니다. Domain Hexagon, Application Hexagon, Framework Hexagon, Bootstrap Hexagon" - **장점(주장)**: 기술 선택 고민 비용 절감, 팀 결속력/오너십 강화. > "기술 선택에 대한 고민으로 소모되는 비용을 아낄 수 있는..." - **단점(자인)**: 앞서 §4에서 본 **outputPort 인터페이스 폭증**. 또한 이 글은 **트랜잭션 경계 정책을 아예 다루지 않습니다**(모듈 분리만으로 해결 안 됨). - 출처: [[raw/company-tech-blogs/hexagonal-woowahan-techblog-2023]], [[raw/company-tech-blogs/woowahan-hexagonal-multimodule]] (company-case-study) ### 5.2 Allegro — Onion Architecture - **상황(context)**: Hexagonal을 쓰던 저자가 "코드 배치(layout)를 더 구조화된 방식으로 하고 싶다"는 문제의식에서 대안으로 선택한 상황. (근거: "more structured approach to the code layout") - **원전과 다른 점**: 스스로를 Hexagonal의 **"대안(alternative)"** 으로 위치시키고, "더 구조화된 code layout"이라는 차이를 내세웁니다. **우열을 주장하지 않습니다**(alternative ≠ superior). 참고로 이 글은 "Clean Architecture"라는 단어 자체를 쓰지 않습니다. > "It can be successfully used as an alternative to a popular Hexagonal / Ports and Adapters architecture" - **장점(주장)**: 도메인 코드와 HTTP·DB 같은 기술 관심사의 강한 분리. - **단점**: 원문에 명시된 단점 **없음**(확인 안 됨). "layer 안에서 feature를 어떻게 자를지 가이드가 없다"는 지적은 raw 작성자의 추정(INFERENCE)입니다. - 출처: [[raw/company-tech-blogs/onion-allegro-tech-blog-2023]] (company-case-study, 저자 1인) ### 5.3 Herberto Graça — Explicit Architecture (DDD·Hexagonal·Onion·Clean·CQRS 통합) - **상황(context)**: DDD·Hexagonal·Onion·Clean·CQRS를 하나의 프로젝트에 통합하려는 상황(글 제목 자체가 "how I put it all together"). 특히 읽기 경로를 단순화하고 싶은 요구. - **원전과 다른 점**: "모든 요청은 Use Case(Application Service)를 통과한다"는 암묵적 통념에 예외를 둡니다. **CQRS의 읽기(Query) 경로는 Application Service를 우회**해 바로 DTO를 반환할 수 있다고 봅니다. > "The Query object will contain an optimized query that will simply return some raw data to be shown to the user." - **장점(주장)**: 읽기 경로 단순화, 도메인 엔티티를 노출하지 않고 DTO/ViewModel로 반환. - **단점**: 이 패턴을 ArchUnit으로 정적 강제하는 구체적 방법은 원문 발췌 밖(확인 안 됨). - 출처: [[raw/company-tech-blogs/explicit-architecture-ddd-hexagonal-cqrs-hgraca]] (engineering-blog) - **용어 한 줄 풀이 — CQRS**: Command Query Responsibility Segregation. 쓰기(command)와 읽기(query) 경로를 분리하는 패턴. ### 5.4 wakita — CQRS-lite Read-Path Bypass - **상황(context)**: 읽기(조회) 요청이 아무것도 바꾸지 않는데도 완전히 검증된 도메인 객체를 매번 만들었다가 곧바로 DTO로 풀어내는, 즉 읽기 경로의 오버헤드가 큰 상황. - **원전과 다른 점**: 읽기 경로가 도메인 aggregate를 거치는 것을 **"순수 오버헤드(pure overhead)"** 라고 명시적으로 규정하고, 읽기 전용 repository를 application 계층 포트로 두어 도메인을 우회합니다. 물리적 store 분리 없이 **논리적으로만** CQRS를 적용합니다. > "Steps 4 and 5 are pure overhead. ... It just needs data — but it's constructing fully validated domain objects, only to immediately unwrap them into flat DTOs." > "The split is logical, not physical." - **장점(주장)**: 읽기/쓰기 store를 물리적으로 나누지 않고도 CQRS의 이점(읽기 최적화) 확보. - **단점**: 실제 성능 개선 **수치 증거 없음**. 또한 Kotlin+jOOQ 구현이라 Java+Spring Data JPA로 그대로 이식 가능하다고 말하면 안 됩니다. - 출처: [[raw/company-tech-blogs/cqrs-lite-clean-architecture-read-path-bypass-wakita]] (engineering-blog) ### 5.5 Spring `@Transactional` 배치 — 다수파 vs 소수파 트랜잭션 경계를 어디에 두느냐에서 실무가 갈립니다. 면접 단골 주제입니다. - **상황(context)**: Spring 환경에서 use case의 트랜잭션 경계를 정해야 하는데, "도메인·application은 framework-free" 원칙을 지킬 것이냐 vs 실용성(코드 간결)을 택할 것이냐의 갈림. - **다수파: use case에 `@Transactional` 직접 부착** — 코드가 가장 적고 진입 장벽이 낮습니다. Reflectoring 튜토리얼과 Buckpal(별 2,500+의 유명 예제)이 이 방식입니다. > "@Component @Transactional public class SendMoneyService implements SendMoneyUseCase" — 출처: [[raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement]] - 긴장점: application 계층이 `org.springframework...Transactional`을 import → "domain-application은 framework-free"라는 원칙과 어긋납니다(단, 이건 raw 작성자 해석이며 저자 본인의 정당화는 없음). - **소수파: 트랜잭션을 output port로 추상화** — UNIL은 프레임워크 중립 애노테이션을 선호하거나 `runInTransaction(Runnable)` 형태의 포트로 뽑아, presentation 실패가 트랜잭션 롤백을 유발하지 않게 경계를 분리합니다. 이 글은 "CA(Clean Architecture)"를 직접 언급합니다. > "this isolates 'Use Cases' layer from dependency on a framework (design-time), which is prohibited by CA." > "Present result of successful execution of the use case outside transactional boundary." — 출처: [[raw/company-tech-blogs/transaction-port-clean-ddd-spring-medium]] - 단점: `Runnable` 시그니처는 nested transaction/propagation/isolation 표현력이 `@Transactional` 속성보다 빈약합니다(INFERENCE — raw 메모). - Arho Huttunen은 JPA 엔티티와 도메인을 분리하고 application 모듈을 Spring 무의존으로 두면서도, 현재 `@Transactional` 배치가 불충분하다고 **스스로 비판**합니다("we can do better"). 출처: [[raw/company-tech-blogs/arhohuttunen-hexagonal-architecture-spring-boot]] ### 5.6 Package-by-Feature vs Package-by-Layer 최상위 패키지를 무엇으로 자르느냐의 문제입니다. - **상황(context)**: 애플리케이션이 커지면서 계층별(layer) 패키지의 저응집·고결합이 드러나, 최상위 분할축을 기능(feature)으로 바꿀지 검토하는 상황. - **Package-by-Feature**(기능별): 한 기능에 필요한 클래스가 한 패키지에 모여 응집도↑, 패키지 이동 비용↓, `package-private` 가시성으로 캡슐화↑. > "Package by Feature reduces the need to navigate between packages..." / "...set their access modifier package-private instead of public, so it increases encapsulation." - **Package-by-Layer**(계층별, `controller/service/repository`): 서로 관련 없는 클래스가 한 패키지에 모여 **저응집·고결합**, 도메인이 늘수록 패키지 클래스 수가 무한정 증가. > "This method causes low cohesion within packages..." / "the number of classes in each package will increase without bound" - **주의**: 이 자료는 **Layer 방식의 단점만** 열거하고 **Feature 방식 자체의 단점은 말하지 않습니다.** 면접에서 "Feature 방식의 단점은?"이라고 되물으면 이 자료만으로는 답할 수 없습니다(공통 kernel 위치·모델 중복 위험 등은 canonical 문서 참조: [[wiki/concepts/clean-architecture-package-layout]]). - 출처: [[raw/company-tech-blogs/feature-first-sahibinden-package-by-layer-vs-feature]] (company-case-study), [[raw/company-tech-blogs/layer-first-kamilmazurek-github-template]] (저자 self-attestation, 단점 미기재) ### 5.7 Buckpal — 반례(CONTRARY) 증거 - **상황(context)**: 책 예제 프로젝트로서 개념 전달·실용성·간결성을 우선한 상황(getter/setter 보일러플레이트를 줄이려 Lombok 허용, 트랜잭션을 간단히 쓰려 `@Transactional` 직접 부착). - **왜 중요한가**: Buckpal은 Tom Hombergs의 저서 *Get Your Hands Dirty on Clean Architecture*의 공식 예제(별 2,500+)입니다. 그런데 여기서는 도메인 순수성 ArchUnit 규칙이 **Lombok을 명시적으로 허용(allowlist)** 하고, application service에 **`@Transactional`을 직접 부착**합니다. > ArchUnit rule: `...resideOutsideOfPackages("...application.domain.model..", "lombok..", "java..")` - **면접 활용**: "왜 당신의 프로젝트(ca-tmpl)는 Lombok 금지·`@Transactional` 금지처럼 업계 유명 예제보다 더 엄격한 규칙을 택했는가?"에 답할 때, "이게 업계 다수파 best practice가 아니라 **의식적인 소수파 선택**"임을 정직하게 설명하는 근거가 됩니다. - 이 파일 스스로 "`@Transactional` 직접 부착이 Hexagonal의 권장 패턴"이라는 주장은 **UNSUPPORTED_DECISION**(Spring 공식이나 Hexagonal 명세가 그렇게 권장한 적 없음)이라고 못 박습니다. - 출처: [[raw/company-tech-blogs/buckpal-archunit-lombok-allowlist-direct-transactional]] (frontmatter상 personal-blog) --- ## 6. 변형 비교 요약 표 | 변형 | 원전과의 핵심 차이 | 주장 장점 | 인정 단점 | 등급 | |---|---|---|---|---| | 우아한형제들 4-Hexagon | 헥사곤=Layer, Gradle 물리 모듈 강제 | 기술선택 비용↓, 팀 결속력 | outputPort 폭증, 트랜잭션 정책 부재 | company-case-study | | Allegro Onion | Hexagonal의 "대안"으로 자기 위치(우열 주장 X) | 도메인/기술 강한 분리 | 원문에 단점 없음(확인 안 됨) | company-case-study | | Graça Explicit Architecture | CQRS Query가 Application Service 우회 | 읽기 경로 단순화, DTO 반환 | ArchUnit 강제법 미제시 | engineering-blog | | wakita CQRS-lite | 읽기 경로 = "pure overhead", 논리적 분리 | 물리 store 분리 없이 CQRS | 성능 수치 없음, Kotlin/jOOQ 한정 | engineering-blog | | Reflectoring / Buckpal | use case에 `@Transactional` 직접(다수파) | 코드 최소, 진입장벽 낮음 | 명시적 정당화 없음, 원칙과 긴장 | engineering / personal-blog | | UNIL TransactionPort | 트랜잭션을 output port로 추상화(소수파) | presentation을 트랜잭션 밖 분리 | `Runnable` 표현력 빈약(INFERENCE) | company-case-study | | Arho Huttunen | JPA/도메인 분리, application Spring 무의존 | clean separation | 모델 간 매핑 비용(자인) | engineering-blog | | Sahibinden Feature vs Layer | 최상위 분할축(feature vs layer) | feature: 캡슐화/응집↑ | Layer 단점만 기술(Feature 단점 없음) | company-case-study | | kamilmazurek Layer-first | API/Service/Repository/Database 4-layer | Simplicity/Maintainability(자기평가) | 단점 원문 미기재 | engineering-blog | | Buckpal (반례) | domain 규칙에 Lombok 허용 + `@Transactional` 직접 | (장점 옹호 아님 — 반례 목적) | "권장 패턴" 주장은 UNSUPPORTED | personal-blog | --- ## 7. 면접에서 조심할 것 (Overclaim 경고) - ❌ "클린 아키텍처는 공식 표준이다" → Uncle Bob·Cockburn 글은 **개인 블로그**입니다. 표준 기구 문서 아님. - ❌ "우아한형제들/Allegro의 클린 아키텍처" → 이들은 대부분 **Hexagonal/Onion을 자칭**하며 클린 아키텍처를 직접 지칭하지 않습니다. - ❌ "4-Hexagon이 헥사고날 표준" → vendor-specific 해석입니다. - ❌ "outputPort 폭증/팀 결속력 같은 회고를 성과 지표처럼" → 정량 근거 없음. - ❌ "Buckpal이 Hexagonal 공식 권장이니 `@Transactional` 직접이 정답" → 파일 자체가 UNSUPPORTED_DECISION으로 명시. - ⭕ "장점(테스트 격리·도메인 독립)은 원전 근거가 있지만, 단점의 정량 근거는 희박하다" → 이 균형 감각이 오히려 신뢰를 줍니다. --- ## 8. 내가 설명할 수 있어야 하는 것 (셀프 체크) - Dependency Rule 한 문장으로 클린 아키텍처를 정의할 수 있는가? - 4개 동심원의 이름과 각 원이 담는 것을 말할 수 있는가? - 제어 흐름과 소스 의존성 방향이 반대인 이유(DIP)를 설명할 수 있는가? - 클린 아키텍처 / Hexagonal / Onion의 관계(사실상 같은 규칙, 다른 표현)를 설명할 수 있는가? - 장점은 원전 근거로, 단점은 "직접 근거가 희박함"을 함께 말할 수 있는가? - `@Transactional` 배치의 다수파/소수파와 그 트레이드오프를 말할 수 있는가? - "우리 프로젝트가 유명 예제(Buckpal)보다 엄격한 규칙을 택한 것은 의식적 소수파 선택"이라고 정직하게 설명할 수 있는가? --- ## 9. 다음 단계 (정식 파이프라인으로 승격하려면) 이 문서는 `wiki/topics-interview/`에 둔 **비표준(off-pipeline) 스터디 노트**입니다. 만약 이 내용을 정식 면접 산출물(`wiki/interview/`)이나 블로그로 쓰려면 CLAUDE.md §15 순서를 따라야 합니다. 1. `/ingest`로 canonical 개념 문서를 먼저 정비/신설: 기존 [[wiki/concepts/clean-architecture-package-layout]] 보강 + (권고) `wiki/concepts/hexagonal-architecture.md`, `wiki/concepts/anti-corruption-layer.md`, `wiki/concepts/clean-architecture-industry-variants.md` 신설. 2. 사람이 검토해 canonical status를 `reviewed` 이상으로 올림. 3. 그 후 `/interviewize`로 `wiki/interview/`에 파생(원천 status가 `reviewed|verified|published-ready` 미만이면 중단됨). --- ## Sources ### Canonical (검증 보조) - [[wiki/concepts/clean-architecture-package-layout]] — 패키지 레이아웃 5종 비교 + 경계 강제 방법 (status: draft) ### 공식/원전 (raw/official-docs — engineering-blog·official-reference·official-vendor-doc) - [[raw/official-docs/arch-clean-architecture-uncle-bob]] — Uncle Bob, The Clean Architecture (2012) - [[raw/official-docs/feature-first-uncle-bob-screaming-architecture-2011]] — Uncle Bob, Screaming Architecture (2011) - [[raw/official-docs/arch-hexagonal-cockburn]] — Cockburn, Hexagonal (Ports & Adapters) 원문 - [[raw/official-docs/hexagonal-cockburn-wikipedia-summary]] — Hexagonal 정리 (Wikipedia) - [[raw/official-docs/hexagonal-thombergs-buckpal-github]] — Thombergs BuckPal reference impl - [[raw/official-docs/arch-acl-microsoft-pattern]] — Microsoft ACL 패턴 (유일한 official-vendor-doc) - [[raw/official-docs/layer-first-baeldung-clean-architecture-spring-boot]] — Baeldung (needs-confirmation, 사실 인용 금지) ### 실무·대기업 사례 (raw/company-tech-blogs — company-case-study·engineering-blog·personal-blog) - [[raw/company-tech-blogs/hexagonal-woowahan-techblog-2023]] — 우아한형제들 4-Hexagon - [[raw/company-tech-blogs/woowahan-hexagonal-multimodule]] — 우아한형제들 멀티모듈 상세 - [[raw/company-tech-blogs/onion-allegro-tech-blog-2023]] — Allegro Onion - [[raw/company-tech-blogs/explicit-architecture-ddd-hexagonal-cqrs-hgraca]] — Herberto Graça Explicit Architecture - [[raw/company-tech-blogs/cqrs-lite-clean-architecture-read-path-bypass-wakita]] — wakita CQRS-lite - [[raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement]] — Reflectoring @Transactional baseline - [[raw/company-tech-blogs/arhohuttunen-hexagonal-architecture-spring-boot]] — Arho Huttunen Spring Hexagonal - [[raw/company-tech-blogs/feature-first-sahibinden-package-by-layer-vs-feature]] — Sahibinden feature vs layer - [[raw/company-tech-blogs/layer-first-kamilmazurek-github-template]] — kamilmazurek layer-first template - [[raw/company-tech-blogs/transaction-port-clean-ddd-spring-medium]] — UNIL TransactionPort (CA 직접 언급) - [[raw/company-tech-blogs/buckpal-archunit-lombok-allowlist-direct-transactional]] — Buckpal 반례(CONTRARY) 증거