Files
llm-wiki/raw/interviews/clean-architecture-module-blueprint.md

10 KiB

title, source_type, status, related_branches, related_projects, tags, created, status_label
title source_type status related_branches related_projects tags created status_label
interview-prep / clean-architecture-module-blueprint interview-prep raw
feature-skeleton-package-blueprint-contract
ca-skeleton
interview-prep
ca-skeleton
architecture
gradle
clean-architecture
hexagonal
multi-module
2026-05-28 collecting

interview-prep: clean-architecture-module-blueprint

Layer: raw/interviews/ — 면접 질문 원본 수집·연구 노트. 다듬어진 답변은 /interviewizewiki/interview/ 에 별도 작성.

Parent / 부모

질문 / 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-coreshared-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-coredomain-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 + BlogApplicationCaSkeletonApplication + 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 / 근거

미해결 / 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 사실을 숨기지 않음.