11 KiB
11 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 / transaction-port-vs-spring-transactional | interview-prep | raw |
|
|
|
2026-05-28 | collecting |
interview-prep: transaction-port-vs-spring-transactional
Layer:
raw/interviews/— 면접 질문 원본 수집·연구 노트. 다듬어진 답변은/interviewize후wiki/interview/에 별도 작성.
Parent / 부모
- raw/branch-notes/feature-application-port-usecase-contract — application 계층이 Spring
@Transactional을 직접 import 하지 않도록TransactionPort를 도입한 실 구현 (D3, Decisions 2026-05-28). - raw/project-notes/ca-skeleton-operational-contract — ca-tmpl skeleton-wide operational contract.
질문 / Question
- 질문 원문: Spring 프로젝트에서 application 계층이
@Transactional을 직접 부착하지 않고TransactionPort같은 추상화로 감싸는 선택의 trade-off 를 설명해 보세요. - 출처: 예상 질문 (실 면접 아님).
- 받은 날짜·맥락: 아직 없음. Clean Architecture / Hexagonal 패턴 경험 검증용 질문 후보.
질문 의도 추론 / Why this question
- 핵심 평가 대상:
- Clean Architecture / Hexagonal 을 했다는 선언이 framework leakage 차단 수준까지 갔는지 변별.
@Transactional의 self-invocation 함정 인지.- 다수파 (
@Transactional직접) vs 소수파 (TransactionPort) 의 둘 다 합리적 임을 인식하는지. - 추상이 enforce 되는 형태 (ArchUnit fitness function) 가 함께 있어야 의미가 있다는 점을 알고 있는지.
- 함정 / 흔히 빠지는 답변 패턴:
- "Clean Architecture 라서 추상화" 만 답하고 구체 이득 (testability, self-invocation 회피, Spring 의존 surface 축소) 을 설명 못함.
- "boilerplate 가 늘어서 안 쓰는 게 낫다" 만 답하고 다수파의 proxy leak / self-invocation 위험 인식 못함.
- "TransactionPort 가 더 좋다" 같이 한쪽을 우월 로 표현 — 실제로는 맥락 의존 결정.
- 따라올 만한 후속 질문:
- 다수파 (
@Transactional직접) 입장이 왜 reasonable 한가요? TransactionPort가REQUIRES_NEW/noRollbackFor/timeout까지 표현 가능해야 한다면 API 가 어떻게 커지나요?TransactionTemplate기반 구현과@TransactionalAOP proxy 기반 구현 중 어느 쪽이 self-invocation 함정 에서 자유롭나요? 왜요?TransactionPort가 없으면 application 단위 테스트에서 transaction 동작을 어떻게 모킹 / fake 합니까?application-core의 Gradle 에서spring-tx를 제거 했는데, 왜요?
- 다수파 (
답변 재료 / Raw answer material
- 사실 1 (근거:
feature-application-port-usecase-contract.mdD3 + raw/company-tech-blogs/transaction-port-clean-ddd-spring-mediumUNIL-TX-C1+ raw/company-tech-blogs/transaction-port-vassilis-soum-github-readmeVSOUM-TX-C1): application 계층은 outbound port (TransactionPort) 만 호출하고, Spring@Transactional의 직접 import 는 forbidden. Spring 의존은 infrastructure 어댑터 (SpringTransactionPort) 에 격리. - 사실 2 (근거: raw/official-docs/at-transactional-spring-official
AT-TX-C5): Spring@TransactionalAOP proxy 의 self-invocation 함정 — 같은 클래스의 메서드가this.otherMethod()형태로 호출되면 proxy 를 우회해서 transaction 이 적용되지 않음.TransactionTemplate기반 추상화는 proxy 가 아니므로 영향 없음. - 사실 3 (근거: raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement
HEX-REFL-C1,HEX-REFL-C5): Hexagonal 표준 다수파 는@Transactional을 application service 에 직접 부착. 이유는 boilerplate 최소화 + Spring 공식 권고 (AT-TX-C1) 정합성. 다만HEX-REFL-C5는 negative claim — 저자가 자기 결정에 대한 명시적 정당화 없이 단순 채택. - 사실 4 (근거: raw/official-docs/spring-tx-management-reference
SPRING-TX-MGR-C6):readOnly = true는 REQUIRED / REQUIRES_NEW propagation 에 한정 해서 적용. ca-tmpl 의TransactionPort.inRead도 이 제약을 따라 REQUIRED + readOnly 로 구현. - 사실 5 (근거:
feature-application-port-usecase-contract.mdDecisions 2026-05-28):application-core의 Gradle 에서spring-tx를 제거 해서@Transactional어노테이션이 컴파일 classpath 자체에서 reach 불가능. ArchUnit rule 과 belt+suspenders. - 사실 6 (근거: 동일 branch-note Decisions 2026-05-28 + 구현 결과):
SpringTransactionPort는 mode 별로 미리 빌드된TransactionTemplate인스턴스 3개 (writeTemplate,readTemplate,requiresNewTemplate) 를 보관해서 호출 시점의 mutation 없이 동시성 안전 보장. - 사실 7 (근거: 동일 branch-note Claims to Verify "application package의 ArchUnit rule" 행 →
actually-implemented):noClasses().that().resideInAPackage("..application..").should().dependOnClassesThat().haveFullyQualifiedName("org.springframework.transaction.annotation.Transactional")로 application 의@Transactionalimport 자동 차단. - 내가 직접 한 경험:
- ca-tmpl 의
application-core에TransactionPort인터페이스 + 3 메서드 +TransactionMode/Isolationenum 정의. adapter-persistence에SpringTransactionPort를TransactionTemplate기반으로 구현 + 4 unit test (SpringTransactionPortTest) — propagation / isolation / readOnly / rollback-on-exception.sample-ticket의 aggregate Service (UserService / PostService) 의 모든@Transactional을tx.inRead/tx.inWrite로 일괄 치환. 동작 동등 + Spring 의존 surface 감소.- ArchUnit rule 추가 후
app-bootstraptest classpath 가sample-ticket을 못 보아 vacuously 통과한 사례를testImplementation project(':sample-ticket')로 해결 — raw/errors/archunit-test-scope-sample-ticket-inclusion-2026-05-28.
- ca-tmpl 의
- 트레이드오프:
- TransactionPort 추상의 진짜 이득 은 testability 가 아니라 (
@Transactional메서드도@SpringBootTest로 테스트 가능) Spring 의존을 단일 진입점 (SpringTransactionPort) 으로 좁히는 것. Spring 업그레이드 / multi-tenant / multi-DB 시나리오에서 transaction 정책 변경 진입점이 한 클래스. - boilerplate 증가는 사실 — 메서드마다
tx.inWrite(() -> { ... })한 단 추가. 작은 팀 / 단일 DB / 단일 transactionManager 환경에서는 다수파 (@Transactional직접) 가 reasonable. - 소수파 결정의 정당화 는 abstraction 자체의 testability 이득 이 아니라 enforce 되는 추상 이 함께 있을 때만 성립. ArchUnit fitness function 없이
TransactionPort만 두면 컨벤션이고, fitness function 이@Transactionalimport 를 실패시키면 drift 방지 메커니즘. TransactionTemplatevs@TransactionalAOP proxy: 후자는AT-TX-C5의 self-invocation 함정. 전자는 proxy 가 없어서 self-invocation 영향 없음. ca-tmpl 은 후자의 함정을 피하려고 전자 선택.
- TransactionPort 추상의 진짜 이득 은 testability 가 아니라 (
- 한계 / "이건 안 해봤다":
REQUIRES_NEW의 실 outbox / audit row 동작 통합 검증 미수행 —feature-domain-event-outbox-contract로 위임.TransactionPort가noRollbackFor/timeout/transactionManager(multi-DB) 표현 불가능 — 의도적 한정. 필요 시 API 확장 결정.- Hibernate session statistics 로
readOnlyflush-mode 측정 PoC 미수행 — Testcontainers 환경 후. - prod 운영 검증 없음 — ca-tmpl 은 template repository.
Sources / 근거
- raw/branch-notes/feature-application-port-usecase-contract — 결정 D1~D10 + 2026-05-28 구현 결과 + Claims to Verify status.
- raw/official-docs/at-transactional-spring-official — Spring
@Transactional공식 + self-invocation 함정 (AT-TX-C1,AT-TX-C5). - raw/official-docs/spring-tx-management-reference — Spring transaction abstraction (
SPRING-TX-MGR-C3,SPRING-TX-MGR-C6). - raw/official-docs/transaction-template-spring-official —
TransactionTemplate공식 (TX-TMPL-C1~TX-TMPL-C4). - raw/company-tech-blogs/transaction-port-clean-ddd-spring-medium — UNIL TransactionPort 진화 (
UNIL-TX-C1,UNIL-TX-C2). - raw/company-tech-blogs/transaction-port-vassilis-soum-github-readme — Vassilis Soum 참고 구현 (
VSOUM-TX-C1~VSOUM-TX-C4). - raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement —
@Transactional직접 부착 다수파 (HEX-REFL-C1,HEX-REFL-C5). - wiki/concepts/transaction-boundary-abstraction — 정제된 trade-off 개념 (canonical 후보, 아직 미생성).
미해결 / Unknown
- 모르는 것:
TransactionPort가noRollbackFor/timeout까지 표현 해야 하는 시점은 언제인가. 현재는 의도적 한정이지만, 실 사업 도메인 들어오면 필요할 수 있음. - 모르는 것:
TransactionTemplate기반 구현이 완전히 self-invocation 함정에서 자유로운지의 PoC (port 메서드가 다른 port 메서드 호출 시). - 모르는 것: multi-DB / multi-tenant 시
TransactionPort가transactionManager선택을 어떻게 표현할지. - 확인 방법:
feature-domain-event-outbox-contract(outbox / REQUIRES_NEW), self-invocation PoC, multi-DB 시나리오 추가 branch.
답변 경계 / Answer boundary
- 자신 있게 말할 수 있는 범위:
- ca-tmpl
application-core의TransactionPort인터페이스 정의 +adapter-persistence의SpringTransactionPort구현 + 4 unit test + sample-ticket 마이그레이션의 직접 수행 범위. - 다수파 vs 소수파 trade-off 의 양쪽 근거 — 다수파의 boilerplate 이득, 소수파의 Spring 의존 surface 축소.
@TransactionalAOP proxy 의 self-invocation 함정 vsTransactionTemplate의 직접 호출 차이.- ArchUnit fitness function + Gradle
spring-tx제거의 belt+suspenders 패턴.
- ca-tmpl
- "이 부분은 공식 문서를 다시 보고 답변드리겠습니다" 라고 해야 하는 부분:
- Spring
TransactionInterceptor/TransactionAttributeSource의 내부 동작 (안 깊이 봄). - multi-DB 시
PlatformTransactionManager선택의 운영 best practice (안 해봄). - Hibernate session 의
readOnlyflush-mode 변경 구체 동작 (needs-confirmation, Testcontainers PoC 후).
- Spring
- 절대 과장하지 말 것:
TransactionPort가 다수파보다 우월 하다는 식 금지 — 이 맥락 (template repository, 격리 우선) 까지만.- prod 운영 검증 없음 —
locally-verified등급. REQUIRES_NEW가 실 outbox 시나리오에서 동작 검증됐다고 표현 금지 — 단위 테스트의PROPAGATION_REQUIRES_NEW설정만 확인.
Related / 관련
- 관련 면접 질문 (선행/후속): raw/interviews/clean-architecture-boundary-enforcement (자매 — ArchUnit 의 자동 검증 측면), raw/interviews/clean-architecture-module-blueprint (선행 — module 분리 자체).
- 영감을 받은 채용공고: (없음).
- 관련 블로그 글감: raw/blog-topics/transaction-port-abstraction-over-spring-transactional-2026-05-28 (같은 주제의 글감).
- 답변 derive 후 위치: 생성 전. 후보
wiki/interview/architecture/transaction-port-vs-spring-transactional.md.