108 lines
10 KiB
Markdown
108 lines
10 KiB
Markdown
---
|
|
title: interview-prep / clean-architecture-module-blueprint
|
|
source_type: interview-prep
|
|
status: raw
|
|
related_branches: [feature-skeleton-package-blueprint-contract]
|
|
related_projects: [ca-skeleton]
|
|
tags: [interview-prep, ca-skeleton, architecture, gradle, clean-architecture, hexagonal, multi-module]
|
|
created: 2026-05-28
|
|
status_label: collecting
|
|
---
|
|
|
|
# interview-prep: clean-architecture-module-blueprint
|
|
|
|
> Layer: `raw/interviews/` — 면접 질문 원본 수집·연구 노트. 다듬어진 답변은 `/interviewize` 후 `wiki/interview/` 에 별도 작성.
|
|
|
|
## Parent / 부모
|
|
|
|
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — single-module feature-first 결정 (2026-05-22) 을 Gradle multi-module + Hexagonal (2026-05-27) 로 _명시적으로 수정_ 한 결정 (D1~D8 + Default Module Blueprint tree + Module Dependency Rule 표).
|
|
- [[raw/project-notes/ca-skeleton-operational-contract]] — ca-tmpl skeleton-wide operational contract SSOT.
|
|
|
|
## 질문 / Question
|
|
|
|
- 질문 원문: Clean Architecture 템플릿에서 왜 단일 모듈 package 구조가 아니라 Gradle multi-module 구조를 선택했나요? 그리고 처음부터 그렇게 결정한 건가요?
|
|
- 출처: 예상 질문.
|
|
- 받은 날짜·맥락: 아직 실제 면접 질문으로 받은 것은 아님.
|
|
|
|
## 질문 의도 추론 / Why this question
|
|
|
|
- 핵심 평가 대상:
|
|
- Clean Architecture 원칙을 _물리적 module boundary_ 로 옮긴 _왜_.
|
|
- package convention 과 build-graph enforcement 의 _차이_ 인식.
|
|
- small project vs template repository 의 trade-off 인식.
|
|
- _첫 결정을 뒤집은 경험_ (case study 검토 후 의사결정 reversion) — 정직함과 evidence-based 사고.
|
|
- 함정 / 흔히 빠지는 답변 패턴:
|
|
- "멀티모듈이 더 깔끔해서" — 비용 / 단점 / trade-off 언급 없음.
|
|
- "처음부터 멀티모듈이 답이라고 생각했다" — 의사결정의 _과정_ 을 숨김.
|
|
- 우아한형제들 / 카카오뱅크 사례를 _industry standard_ 처럼 인용 (실제로는 _case study_).
|
|
- 따라올 만한 후속 질문:
|
|
- small project 에서는 single-module 이 더 낫지 않나요? 어떤 기준으로 multi-module 을 선택해야 하나요?
|
|
- Gradle dependency rule 과 ArchUnit rule 은 각각 _무엇을 보장_ 하나요? 한쪽만으로는 왜 안 되나요?
|
|
- `domain-core` 가 `shared-contract` 를 참조하는 건 Clean Architecture 위반 아닌가요?
|
|
- Spring Modulith 가 multi-module 대체가 될 수 있나요?
|
|
- 새 사업 도메인이 추가되면 어느 module 에 어떻게 들어가나요? `adapter-messaging` 같은 새 adapter 가 필요해지면?
|
|
|
|
## 답변 재료 / Raw answer material
|
|
|
|
- 사실 1 (근거: `feature-skeleton-package-blueprint-contract.md` D1, §결정 사항 2026-05-22 / 2026-05-27): 초기 결정은 single-module feature-first package layout 이었다. 2026-05-27 에 우아한형제들 / 카카오뱅크 사례 검토 후 Gradle multi-module + Clean Architecture / Hexagonal 로 _명시적으로 수정_. 의사결정의 reversion 자체가 evidence.
|
|
- 사실 2 (근거: `feature-skeleton-package-blueprint-contract.md` §Default Module Blueprint + Module Dependency Rule 표): ca-tmpl 의 8 module — `app-bootstrap`, `domain-core`, `application-core`, `adapter-web`, `adapter-persistence`, `adapter-outbound`, `shared-contract`, `sample-ticket`. dependency direction 매트릭스로 _허용/금지_ 가 매 module 별로 명시.
|
|
- 사실 3 (근거: `feature-skeleton-package-blueprint-contract.md` D2, D3): `domain-core` 는 framework-neutral POJO (Spring/JPA/HTTP 모름), `application-core` 는 `domain-core` + `shared-contract` 에만 의존. adapter 구현체는 adapter module 밖으로 안 새어 나옴.
|
|
- 사실 4 (근거: `feature-skeleton-package-blueprint-contract.md` D6): `shared-contract` 는 response envelope / error code / header / MDC / metric / registry / annotation 같은 _skeleton-wide operational contract_ 만. business / domain concept 는 금지.
|
|
- 사실 5 (근거: `feature-skeleton-package-blueprint-contract.md` D7 + `feature-architecture-enforcement-rules.md` D7): `sample-ticket` 은 fixture/sample consumer 이며 production module 이 import / dependency 선언 시 _Gradle + ArchUnit 양쪽_ 에서 실패.
|
|
- 사실 6 (근거: `feature-skeleton-package-blueprint-contract.md` Closure §`locally-verified`): `./gradlew verifyCleanArchitectureDependencies` + `./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest'` + `./gradlew :adapter-web:test --tests '*SettingsTest'` + `./gradlew test` 모두 통과. 로컬 검증 완료.
|
|
- 내가 직접 한 경험:
|
|
- 기존 reference code (blog domain) 를 production module 에서 `sample-ticket/src/main/java/dev/caskeleton/sample/ticket/...` 로 격리. production module 은 anchor + `package-info.java` 중심으로 정리.
|
|
- production package root `dev.caskeleton` 으로 rename + `BlogApplication` → `CaSkeletonApplication` + `blog.*` 설정 prefix → `ca-skeleton.*`.
|
|
- 빈 anchor module 의 ArchUnit empty-should failure 를 `allowEmptyShould(true)` 로 선별 해결 — [[raw/errors/archunit-empty-should-anchor-2026-05-27]].
|
|
- sample-ticket 격리 후 `InvalidBearerTokenException` compile error → `spring-boot-starter-oauth2-resource-server` 명시 추가 — [[raw/errors/sample-ticket-oauth2-resource-server-dependency-2026-05-27]].
|
|
- 트레이드오프:
|
|
- **single-module 의 장점**: build 설정 단순, IDE 탐색 빠름, 처음 학습 비용 낮음. _작은 프로젝트_ 에는 합리적.
|
|
- **multi-module 의 장점**: module boundary 가 _컴파일 단계_ 에서 위반을 차단. template 의 _재사용성_ (다음 프로젝트에서 import 해도 경계가 살아 있음).
|
|
- ca-tmpl 이 multi-module 을 택한 _이유_: template repository 라서 _새 프로젝트 시작 시점에 경계가 흐트러지지 않도록 학습 비용을 미리 흡수_ — `feature-skeleton-package-blueprint-contract.md` D8 Open Risk 와 일치.
|
|
- **case study 의 한계**: 우아한형제들 / 카카오뱅크 사례는 `company-case-study` 등급. _공식 표준이 아님_. ca-tmpl 채택의 _부분 정당화_ 까지만.
|
|
- 한계 / "이건 안 해봤다":
|
|
- Spring Modulith named interface 검증은 _기본값으로 도입하지 않음_ (`feature-skeleton-package-blueprint-contract.md` D5 Open Risk).
|
|
- 실제 사업 도메인 (e.g., 결제 / 알림 / 인증) 이 들어왔을 때 module 분할 / 새 adapter 추가가 자연스러운지 _검증 안 함_.
|
|
- 운영 배포 검증 없음 — `feature-skeleton-package-blueprint-contract.md` Closure §`prod-verified: 없음`.
|
|
|
|
## Sources / 근거
|
|
|
|
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — D1~D8, Default Module Blueprint, Module Dependency Rule.
|
|
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — 자매 결정 (boundary 강제). 본 module 분리의 _자동 검증 메커니즘_.
|
|
- [[raw/branch-notes/feature-application-port-usecase-contract]] — `application-core` 내부 패키지 구조의 후속 (D1: `*UseCase` / `*Port` naming). canonical 정제 시 통합.
|
|
- [[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 + Modulith 사례 (`KAKAOBANK-MOD-C4`).
|
|
- [[raw/official-docs/hexagonal-cockburn-wikipedia-summary]] — Ports & Adapters 원형 (`HEX-WIKI-C5`).
|
|
- [[raw/official-docs/arch-clean-architecture-uncle-bob]] — Dependency Rule 의 클래식 근거.
|
|
- [[raw/official-docs/layer-first-baeldung-clean-architecture-spring-boot]] — _대안 1: layer-first_ 입문형 사례.
|
|
- [[wiki/concepts/clean-architecture-package-layout]] — Clean Architecture package/module layout 개념.
|
|
- [[wiki/projects/ca-tmpl/clean-architecture-package-layout]] — ca-tmpl 적용 (canonical, 갱신 필요).
|
|
|
|
## 미해결 / Unknown
|
|
|
|
- 모르는 것: Spring Modulith 를 후속 도입했을 때 Gradle multi-module + ArchUnit 과의 _중복/대체_ 관계.
|
|
- 모르는 것: 실제 사업 도메인 추가 시 module 분할 패턴 (e.g., 결제 추가 시 `domain-core` 가 결제 / 사용자 / 주문 등 sub-package 로 비대해지는 시점은 어디인가).
|
|
- 확인 방법: `feature-application-port-usecase-contract`, `feature-domain-event-outbox-contract`, `feature-business-rule-validation-contract` 후속 branch 적용 결과 관찰.
|
|
|
|
## 답변 경계 / Answer boundary
|
|
|
|
- 자신 있게 말할 수 있는 범위:
|
|
- ca-tmpl 에서 module rename / package anchor / Gradle dependency verifier / ArchUnit rule / full local test 까지 _직접 수행_ 한 범위.
|
|
- 초기 single-module 결정을 multi-module 로 _뒤집은 의사결정 과정_ 과 근거 (case study 검토).
|
|
- `domain-core` / `application-core` / `adapter-{web,persistence,outbound}` / `shared-contract` / `sample-ticket` / `app-bootstrap` 의 _책임과 forbidden import_.
|
|
- "이 부분은 공식 문서를 다시 보고 답변드리겠습니다" 라고 해야 하는 부분:
|
|
- Spring Modulith named interface 의 구체 configuration (도입한 적 없음).
|
|
- 회사별 shared kernel / common module 운영 표준 (ca-tmpl 의 결정은 _이 맥락_ 까지만).
|
|
- module 수 (4 vs 8 vs 12) 의 최적값 (case study 가 사례별로 다름).
|
|
- **절대 과장하지 말 것**:
|
|
- 운영 배포 경험인 것처럼 말하지 말 것. ca-tmpl 은 _template repository_ 이고 검증 등급은 `locally-verified`.
|
|
- 우아한형제들 / 카카오뱅크 사례를 _업계 표준_ 처럼 표현 금지 — 둘 다 _case study_ (`company-case-study` 등급).
|
|
- "처음부터 multi-module 이 답이라고 알았다" 식의 표현 금지 — 결정의 _reversion_ 사실을 숨기지 않음.
|
|
|
|
## Related / 관련
|
|
|
|
- 관련 면접 질문 (선행/후속): [[raw/interviews/shared-contract-and-sample-isolation]] (자매 — shared/sample 책임), [[raw/interviews/clean-architecture-boundary-enforcement]] (후속 — 자동 검증), [[raw/interviews/transaction-port-vs-spring-transactional]] (자매 — application 의 framework 격리).
|
|
- 영감을 받은 채용공고: (없음).
|
|
- 관련 블로그 글감: [[raw/blog-topics/clean-architecture-module-blueprint-2026-05-28]] (같은 경험의 글감), [[raw/blog-topics/clean-architecture-boundary-enforcement-2026-05-28]].
|
|
- 답변 derive 후 위치: 생성 전. 생성 시 `wiki/interview/architecture/clean-architecture-module-blueprint.md` 후보.
|