Files
llm-wiki/raw/interviews/clean-architecture-boundary-enforcement.md
T

105 lines
11 KiB
Markdown

---
title: interview-prep / clean-architecture-boundary-enforcement
source_type: interview-prep
status: raw
related_branches: [feature-architecture-enforcement-rules]
related_projects: [ca-skeleton]
tags: [interview-prep, ca-skeleton, architecture, testing, archunit, clean-architecture, gradle]
created: 2026-05-28
status_label: collecting
---
# interview-prep: clean-architecture-boundary-enforcement
> Layer: `raw/interviews/` — 면접 질문 원본 수집·연구 노트. 다듬어진 답변은 `/interviewize` 후 `wiki/interview/` 에 별도 작성.
## Parent / 부모
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — Clean Architecture 경계를 Gradle + ArchUnit fitness function 으로 강제한 결정 (D1~D10) + 검증 결과.
- [[raw/project-notes/ca-skeleton-operational-contract]] — ca-tmpl skeleton 의 module boundary / operational contract SSOT.
## 질문 / Question
- 질문 원문: Clean Architecture 템플릿에서 계층 경계가 시간이 지나도 깨지지 않도록 어떤 방식으로 자동 검증했나요?
- 출처: 예상 질문 (실제 면접에서 받은 것 아님).
- 받은 날짜·맥락: 아직 없음.
## 질문 의도 추론 / Why this question
- 핵심 평가 대상:
- 아키텍처 원칙을 _문서가 아니라_ 자동 검증으로 연결한 경험.
- Gradle multi-module dependency 와 ArchUnit bytecode rule 의 _역할 분리_ 인식 (각자 잡는 위반 종류가 다름).
- 정적 분석의 _한계_ 인식 (runtime reflection, generated code, Spring Modulith 등 보완 도구의 자리).
- 단순 "Clean Architecture 적용했다" 선언이 아니라 _실제 위반 코드를 넣어 red/green 검증_ 한 경험.
- 함정 / 흔히 빠지는 답변 패턴:
- "Clean Architecture 적용했다" 로 끝내고 controller/repository/JPA entity leak 을 _구체적으로 어떻게 막았는지_ 설명 못함.
- Gradle 과 ArchUnit 의 _역할 차이_ 를 묻지 않고 "둘 다 썼다" 로 뭉뚱그림.
- 한계 (reflection, MapStruct generated path, Spring Modulith 도입 안 함) 를 솔직히 말하지 않고 만능처럼 표현.
- 따라올 만한 후속 질문:
- Gradle dependency rule 과 ArchUnit rule 은 각각 _어떤 위반_ 을 잡나요? 한쪽만으로는 왜 안 되나요?
- ArchUnit 이 잡지 못하는 위반은 무엇이고 어떻게 보완할 건가요?
- sample module 이 production code 로 역수입되는 걸 어떻게 막았나요?
- 빈 anchor module 은 ArchUnit 에서 어떻게 처리했나요?
- Spring Modulith 를 도입하지 않은 이유는 무엇이고, 추후 도입한다면 무엇이 _중복_ 되고 무엇이 _보완_ 인가요?
## 답변 재료 / Raw answer material
> 사실은 branch-note Decision ID 또는 외부 source claim ID 로 근거 같이 인용. 경험은 _내가 직접 한 것_ 만.
- 사실 1 (근거: `feature-architecture-enforcement-rules.md` D2): ca-tmpl 의 module 구조는 `domain-core` + `application-core` + `adapter-{web,persistence,outbound}` + `shared-contract` + `sample-ticket` + `app-bootstrap` 8개. module boundary 가 _1차 강제선_, module 내부 package 가 _2차 책임 분류_.
- 사실 2 (근거: `feature-architecture-enforcement-rules.md` D1 + 외부 `governance-archunit-official.md#AU-OFF-C1`): boundary 강제는 _두 층_ — Gradle `verifyCleanArchitectureDependencies` task 가 declared module coverage + allowed project dependency 매트릭스를 검사하고, ArchUnit `CleanArchitectureTest` 가 bytecode/import 수준의 12 rule 을 검사.
- 사실 3 (근거: `feature-architecture-enforcement-rules.md` D3, D4, D5, D6, D7, D8): ArchUnit 이 잡는 위반 — domain purity (Spring/JPA/HTTP import 금지), application → adapter/bootstrap 의존 금지, adapter 간 직접 의존 금지, web DTO boundary, sample-ticket production 역수입 금지, application `@Transactional` 직접 import 금지, controller direct domain response 금지, mapper boundary, shared-contract package allowlist.
- 사실 4 (근거: `feature-architecture-enforcement-rules.md` Claims to Verify 의 status 표): 위 8개 rule 모두 `actually-implemented` 또는 `locally-verified`. red/green 검증 (임시 위반 코드 → 실패 → 제거 → 통과) 까지 수행. `cd src && ./gradlew :app-bootstrap:test verifyCleanArchitectureDependencies``cd src && ./gradlew test` 모두 통과.
- 사실 5 (근거: `feature-architecture-enforcement-rules.md` D8 + `feature-application-port-usecase-contract.md` D3): application 의 `@Transactional` 금지는 _Spring 공식 권고와 충돌_ 하는 의도적 소수파 결정. 다수파 (`@Transactional` 직접 부착, hexagonal-reflectoring) 가 reasonable 함을 인정하면서, template repository 의 _격리 학습 비용_ 흡수가 이유.
- 내가 직접 한 경험:
- ca-tmpl `src/build.gradle``verifyCleanArchitectureDependencies``src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java` 두 파일을 함께 보강.
- 임시 위반 코드 4종 (`shared.ticket` package, controller domain return, mapper → application 의존, application `@Transactional`, `app-bootstrap → sample-ticket` Gradle dep) 추가 → 실패 확인 → 제거 → 통과.
- 빈 skeleton anchor module 의 ArchUnit empty-should failure 를 `allowEmptyShould(true)`_선별_ 해결 (모든 rule 에 일괄 적용 ≠ 빈 상태가 의도된 rule 에만 적용) — [[raw/errors/archunit-empty-should-anchor-2026-05-27]].
- Codex sandbox 의 read-only `~/.gradle` 권한 때문에 Gradle wrapper lock 실패 → 사용자 승인 escalation 으로 재실행 — [[raw/errors/gradle-wrapper-readonly-cache-2026-05-28]]. _코드 문제와 환경 문제를 구분_ 한 경험.
- 트레이드오프:
- **Gradle vs ArchUnit 분업**: Gradle 은 _module-level project dependency_ 를 컴파일 단계에서 확실히 차단하지만 _method return type_ 이나 _annotation import_ 같은 세부 규칙은 못 봄. ArchUnit 은 bytecode 수준의 import / class structure 를 잡지만 _module 간 build-graph 사이클_ 은 깔끔하게 못 잡음. 둘이 _역할이 다르고 둘 다 필요_.
- **다수파 vs 소수파**: `@Transactional` 직접 부착 (다수파, Spring 공식 권고, boilerplate 최소) vs `TransactionPort` 추상화 (소수파, 격리 우선, boilerplate 증가). ca-tmpl 은 _template repository 라서_ 소수파를 의도적 선택. 단일 DB / 단일 transactionManager 의 작은 팀은 다수파가 reasonable.
- **Spring Modulith 도입 안 함**: named interface 검증은 더 강력하지만 ca-tmpl 의 boundary drift 차단 비용 대비 효용이 _이 시점에서는_ 낮다고 판단. 후속 검토 후보로 둠 (`feature-architecture-enforcement-rules.md` D5 Open Risk).
- 한계 / "이건 안 해봤다":
- runtime lookup / reflection 우회 (`ApplicationContext#getBean` 류) 가 현재 ArchUnit rule 을 false-pass 하는지 _실험 미수행_ (`planned`).
- MapStruct generated mapper exemption 의 build path 가 빌드 도구 설정에 따라 어떻게 달라지는지 확인 미완 (`needs-confirmation`, D9 `UNSUPPORTED_DECISION`).
- prod 운영 검증 없음 — ca-tmpl 은 template repository.
## Sources / 근거
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — 결정 D1~D10, Claims to Verify status 표, Closure 의 `locally-verified` 5항목.
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — 자매 결정 (D1~D8). module 분리 자체의 _왜_.
- [[raw/branch-notes/feature-application-port-usecase-contract]] — `@Transactional` 다수파 vs 소수파 trade-off 의 근거 (D3, D4 비교).
- [[raw/official-docs/archunit-user-guide]] — ArchUnit rule DSL (`ARCHUNIT-UG-C5`, `ARCHUNIT-UG-C6`).
- [[raw/official-docs/governance-archunit-official]] — architecture test 거버넌스 (`AU-OFF-C1`, `AU-OFF-C2`).
- [[raw/official-docs/archunit-conditional-on-property-3-layer-pattern]] — predicate/condition 모델 (`AUCP-C1` ~ `AUCP-C5`).
- [[raw/company-tech-blogs/woowahan-hexagonal-multimodule]] — Domain / Application / Framework / Bootstrap 4-module 격리 (`WW-HEX-C1`).
- [[raw/company-tech-blogs/modulith-kakaobank-techblog-2025]] — Gradle multi-module + Hexagonal + Spring Modulith (`KAKAOBANK-MOD-C4`).
- [[wiki/concepts/clean-architecture-package-layout]] — 정제된 layout 개념 (canonical).
- [[wiki/projects/ca-tmpl/clean-architecture-package-layout]] — ca-tmpl 적용 (canonical, 갱신 필요).
## 미해결 / Unknown
- 모르는 것: ArchUnit 이 reflection 우회를 _얼마나_ 못 잡는지 정량 측정 안 함. Spring `ApplicationContext#getBean` 류의 일반적 우회 패턴을 위반 코드로 넣어 실제 false-pass 확인 필요.
- 모르는 것: MapStruct generated mapper exemption 의 표준 처리 방식. Maven vs Gradle / annotation processor 위치에 따라 달라지는 generated source path 의 일반적 표현.
- 확인 방법: `feature-architecture-enforcement-rules.md` Claims to Verify 의 `planned` / `needs-confirmation` 항목을 후속 PoC branch 에서 실험.
## 답변 경계 / Answer boundary
- 자신 있게 말할 수 있는 범위: ca-tmpl `src/build.gradle``verifyCleanArchitectureDependencies``src/app-bootstrap/.../CleanArchitectureTest.java` 의 12 ArchUnit rule 을 _직접 구현 + red/green 검증_ 한 범위. `./gradlew test` + `verifyCleanArchitectureDependencies` 로컬 통과까지.
- "이 부분은 공식 문서를 다시 보고 답변드리겠습니다" 라고 해야 하는 부분:
- MapStruct generated code exemption 의 빌드 도구별 표준 처리.
- Spring Modulith named interface 의 구체 configuration (Modulith 를 _도입한 적 없음_).
- prod 환경에서 ArchUnit / Gradle dependency rule 이 CI 어떤 단계에서 실패시키는 게 안전한지 (운영 경험 없음).
- **절대 과장하지 말 것**:
- prod 운영 검증인 것처럼 말하지 말 것. ca-tmpl 은 template repository 이고 검증 등급은 _`locally-verified`_.
- 우아한형제들 / 카카오뱅크 사례를 _industry standard_ 처럼 말하지 말 것. _case study_ 다 (`Evidence Strength: company-case-study`).
- `@Transactional` 소수파 결정이 _다수파보다 우월하다_ 는 식의 표현 금지. _이 맥락 (template repository) 에서의 선택_ 까지만.
## Related / 관련
- 관련 면접 질문 (선행/후속): [[raw/interviews/clean-architecture-module-blueprint]] (선행 — module 분리 자체의 _왜_), [[raw/interviews/shared-contract-and-sample-isolation]] (자매 — shared/sample 책임), [[raw/interviews/transaction-port-vs-spring-transactional]] (자매 — `@Transactional` 다수파/소수파 trade-off), [[raw/interviews/post-implementation-knowledge-capture]] (워크플로우 자매).
- 영감을 받은 채용공고: (없음).
- 관련 블로그 글감: [[raw/blog-topics/clean-architecture-boundary-enforcement-2026-05-28]] (같은 경험의 글감), [[raw/blog-topics/clean-architecture-module-blueprint-2026-05-28]] (자매 글감), [[raw/blog-topics/transaction-port-abstraction-over-spring-transactional-2026-05-28]] (`@Transactional` trade-off 글감).
- 답변 derive 후 위치: 생성 전. 생성 시 `wiki/interview/architecture/clean-architecture-boundary-enforcement.md` 후보.