Files
llm-wiki/vault/20-evidence/company-tech-blogs/buckpal-archunit-lombok-allowlist-direct-transactional.md
T

169 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: personal-blog / Buckpal — ArchUnit Lombok allowlist + direct @Transactional (CONTRARY EVIDENCE to ca-tmpl D3/D1)
source_type: personal-blog
url: https://github.com/thombergs/buckpal
related_branches:
- feature-architecture-enforcement-rules
- feature-application-port-usecase-contract
related_projects: [ca-skeleton]
tags: [personal-blog, ca-skeleton, architecture, archunit, lombok, transaction, hexagonal, domain-purity]
status: raw
confidence: medium
created: 2026-05-28
---
# personal-blog / Buckpal — ArchUnit Lombok allowlist + direct @Transactional (CONTRARY EVIDENCE to ca-tmpl D3/D1)
> Layer: `raw/company-tech-blogs/` — 외부 자료(개인 블로그·책 공식 예제 코드) 원문 발췌·출처 기록.
> **CONTRARY EVIDENCE 노트**: ca-tmpl 의 결정 D3 (domain-core Lombok 금지) 와 D1 (@Transactional 직접 import 금지) 과 **반대 방향**인 OSS 선례를 기록한다.
> 이 자료는 ca-tmpl 결정을 reject 하기 위한 것이 아니라, ca-tmpl 이 "OSS 다수파 best practice" 가 아닌 **ca-tmpl 자체 stricter stance** 임을 솔직히 명시하기 위한 근거다.
---
## Parent / 활용 branch (필수, 최소 1개+)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| [[raw/branch-notes/feature-architecture-enforcement-rules]] | D3 CONTRARY evidence — Buckpal domain purity ArchUnit rule 이 `lombok..` 패키지를 명시적으로 allowlist 함으로써, "domain-core Lombok 금지" 가 OSS 공통 표준이 아니라 ca-tmpl 자체 stricter stance 임을 뒷받침 |
| [[raw/branch-notes/feature-application-port-usecase-contract]] | D1 CONTRARY evidence — Buckpal application service 가 `@Transactional` 을 직접 클래스에 부착함으로써, "Spring @Transactional 직접 import 금지" 가 OSS 다수파가 아닌 ca-tmpl 소수파 결정임을 뒷받침 |
---
## 출처 / Source
- 원본 URL (repo): https://github.com/thombergs/buckpal
- DependencyRuleTests.java: https://raw.githubusercontent.com/thombergs/buckpal/master/src/test/java/io/reflectoring/buckpal/DependencyRuleTests.java
- SendMoneyService.java: https://raw.githubusercontent.com/thombergs/buckpal/master/src/main/java/io/reflectoring/buckpal/application/domain/service/SendMoneyService.java
- UseCase.java: https://raw.githubusercontent.com/thombergs/buckpal/master/src/main/java/io/reflectoring/buckpal/common/UseCase.java
- 아카이브 URL: (미등록 — GitHub raw 직접 링크)
- 저자: Tom Hombergs (Reflectoring.io, "Get Your Hands Dirty on Clean Architecture" 저자)
- 자료 성격: 개인 블로그(reflectoring.io) + 책("Get Your Hands Dirty on Clean Architecture") 공식 예제 코드
- repo star: ≥2,500 (2026-05-28 확인 시점 기준, Hexagonal Architecture Java OSS 중 가장 영향력 있는 reference)
- single-module 여부: repo root 에 `build.gradle` 1개, `settings.gradle` 부재 → 단일 Gradle 모듈 확인 (GitHub API tree 검증)
- 마지막 확인일: 2026-05-28
---
## 왜 저장했는지 / Why archived
Buckpal 은 Hexagonal Architecture Java 구현의 사실상 가장 영향력 있는 OSS 예제다. 그런데 ca-tmpl 의 두 핵심 결정 — (1) domain-core 에서 Lombok annotation 금지, (2) application layer 에서 Spring `@Transactional` 직접 import 금지 — 과 **정반대 방향**을 택하고 있다. ca-tmpl 결정 문서에서 "우리가 OSS 다수파와 다르다" 는 사실을 솔직히 기록하기 위해 보관한다. 이 자료가 ca-tmpl 결정을 부정하는 것이 아니라, 결정이 "stricter / 소수파" 임을 명시하는 CONTRARY evidence 로 기능한다.
---
## 핵심 인용 / Key quotes (verbatim, self-grep 통과)
> [DependencyRuleTests.java §domainModelDoesNotDependOnOutside] "void domainModelDoesNotDependOnOutside() { noClasses() .that() .resideInAPackage(\"io.reflectoring.buckpal.application.domain.model..\") .should() .dependOnClassesThat() .resideOutsideOfPackages( \"io.reflectoring.buckpal.application.domain.model..\", \"lombok..\", \"java..\" ) .check(new ClassFileImporter() .importPackages(\"io.reflectoring.buckpal..\")); }"
>
> — Source: DependencyRuleTests.java line 3346. domain model 이 의존할 수 있는 외부 패키지를 `lombok..` 와 `java..` 로 명시적 allowlist 함.
> [DependencyRuleTests.java §import] "import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;"
>
> — Source: DependencyRuleTests.java line 7. ArchUnit `noClasses()` DSL 직접 사용 확인.
> [SendMoneyService.java §class-declaration] "@RequiredArgsConstructor @UseCase @Transactional public class SendMoneyService implements SendMoneyUseCase {"
>
> — Source: SendMoneyService.java line 1619. application service 에 `@UseCase` (= `@Component` meta-annotation) + `@Transactional` 직접 클래스 레벨 부착. Spring DI + transaction boundary 를 추상화 없이 직접 선언.
> [SendMoneyService.java §import] "import jakarta.transaction.Transactional;"
>
> — Source: SendMoneyService.java line 13. `jakarta.transaction.Transactional` 직접 import. `org.springframework.transaction.annotation.Transactional` 이 아닌 Jakarta EE 표준 어노테이션 사용 (Spring 은 양쪽 모두 지원).
> [UseCase.java §meta-annotation] "@Component public @interface UseCase { @AliasFor(annotation = Component.class) String value() default \"\"; }"
>
> — Source: UseCase.java line 1419 (핵심 부분). `@UseCase` 는 `@Component` 의 meta-annotation. 즉 SendMoneyService 는 사실상 `@Component @Transactional` 직접 부착.
---
## Claims Extracted / 추출된 주장
> 이 자료가 **직접 말하는 것만** claim 으로 분리한다. ca-tmpl 에 적용한 해석은 여기 쓰지 않는다.
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| BUCKPAL-LOMBOK-C1 | Buckpal domain purity ArchUnit rule 은 domain model 이 `lombok..` 패키지에 의존하는 것을 **허용** (resideOutsideOfPackages allowlist 에 `"lombok.."` 포함) | [DependencyRuleTests.java §domainModelDoesNotDependOnOutside] `"lombok.."` (line 41 of fetched file) | `engineering-blog` (개인 블로그 + 책 예제 — Spring/ArchUnit 공식 아님) | Java Hexagonal Architecture 에서 domain-core 가 Lombok 에 의존하는 것이 기술적으로 가능하며 저명한 예제에서 채택됨을 보여주는 선례 | Lombok 사용이 "옳다" 또는 "권장된다" 는 것. 단지 "Buckpal 은 그렇게 결정했다" 만 증명. ca-tmpl 의 금지 결정을 부정하지 않음 |
| BUCKPAL-LOMBOK-C2 | domain model 이 Lombok annotation 을 사용해도 domain purity ArchUnit rule 을 통과하도록 설계 가능하다 (rule 자체가 Lombok 을 외부 침해로 간주하지 않음) | [DependencyRuleTests.java §domainModelDoesNotDependOnOutside] `"lombok.."``resideOutsideOfPackages` 의 허용 목록에 포함됨 (line 41) | `engineering-blog` | Buckpal 설계 기준에서 Lombok = domain 내부 허용 도구. 이 선택이 책 시장에서 ≥2.5k star OSS 예제로 수용된 사실 | Lombok 이 "domain purity 에 영향을 주지 않는다" 는 일반 원칙. Buckpal 이 Lombok 사용의 장단점을 공식 분석했음을 증명하지 않음 |
| BUCKPAL-TX-C1 | Buckpal SendMoneyService 는 `@Transactional` 어노테이션을 클래스 레벨에 직접 부착하여 transaction boundary 를 선언 | [SendMoneyService.java §class-declaration] `"@UseCase @Transactional public class SendMoneyService implements SendMoneyUseCase {"` (line 1619) | `engineering-blog` | Hexagonal Architecture Java 에서 application service 가 Spring/Jakarta `@Transactional` 직접 선언하는 패턴의 저명한 구현 선례 | `@Transactional` 직접 부착이 "Hexagonal Architecture 의 표준" 이거나 "best practice" 임. 단지 "Buckpal 은 그렇게 구현했다" 만 증명 |
| BUCKPAL-TX-C2 | Buckpal 에는 `TransactionPort` / `TransactionRunner` / `UnitOfWork` 같은 transaction abstraction 이 존재하지 않음 — Spring `@Transactional` 직접 사용 | [SendMoneyService.java §import] `"import jakarta.transaction.Transactional;"` (line 13) + class declaration (line 1619). 별도 transaction port interface 파일 부재 (GitHub API tree 검증) | `engineering-blog` | Buckpal 설계에서 transaction abstraction layer 는 선택이 아닌 생략. 이 생략이 책 예제로 수용된 사실 | transaction abstraction 이 불필요하다는 일반 원칙. ca-tmpl 의 `TransactionPort` 결정이 잘못됐음을 증명하지 않음 |
### Strength 허용값 참고
- 본 자료의 모든 claim: `engineering-blog` — Tom Hombergs 개인 블로그 + 책 예제. Spring 공식/ArchUnit 공식 아님.
- `company-case-study` 로 분류하지 않은 이유: Buckpal 은 기업 엔지니어링 블로그 출처가 아닌 개인 저자(Tom Hombergs)의 책 예제.
---
## Usage Boundaries / 적용 경계
### 이 자료가 직접 증명하는 것
- `BUCKPAL-LOMBOK-C1`: Buckpal 이 domain purity rule 에서 `lombok..` 를 명시적으로 allowlist 한다는 코드 사실
- `BUCKPAL-LOMBOK-C2`: domain-core + Lombok 공존 설계가 저명한 OSS 예제에서 실제로 구현됨
- `BUCKPAL-TX-C1`: Buckpal 이 `@Transactional` 을 application service 클래스 레벨에 직접 부착함
- `BUCKPAL-TX-C2`: Buckpal 에 transaction abstraction 계층이 없음
### 이 자료가 증명하지 않는 것
- Lombok 사용이 domain purity 원칙과 양립 가능하다는 일반 원칙 (단지 Buckpal 의 구현 결정)
- `@Transactional` 직접 부착이 Hexagonal Architecture 의 "공식" 또는 "권장" 방식 (Spring 공식 문서는 `@Transactional` 지원을 명시하지만 Hexagonal Architecture 특정 배치 지침은 제공하지 않음)
- ca-tmpl 의 D3 (Lombok 금지) 또는 D1 (`@Transactional` 금지) 결정이 잘못됐음
- Buckpal 패턴이 다른 프로젝트에 직접 이식 가능함 (Buckpal 은 single-module, ca-tmpl 은 multi-module)
### ca-tmpl 에 적용하려면 추가 확인이 필요한 것
- 이 자료는 CONTRARY evidence 로만 사용한다. ca-tmpl 결정 D3/D1 을 변경하려면 별도 Decision Review 필요
- Buckpal 의 single-module 구조 vs ca-tmpl 의 multi-module Gradle 구조 차이 — module boundary 가 강한 격리를 제공하는 multi-module 환경에서 Lombok classpath 포함 여부는 별도 평가 필요
---
## 메모 / Notes
- Buckpal 은 단일 Gradle 모듈 (`build.gradle` 1개, `settings.gradle` 부재). ca-tmpl 과 module 구조가 근본적으로 다름. domain purity rule 의 의미가 다를 수 있음.
- Buckpal 의 `@Transactional``jakarta.transaction.Transactional` (Jakarta EE 표준). ca-tmpl 금지 대상인 `org.springframework.transaction.annotation.Transactional` 과 다른 import path — 하지만 Spring 은 양쪽 모두 처리하고, ca-tmpl ArchUnit rule 은 `jakarta.transaction.Transactional` 도 별도 금지 검토 대상으로 볼 수 있음. 이 세부 사항은 `feature-architecture-enforcement-rules` branch 에서 확인 필요.
- `@UseCase``@Component` meta-annotation (UseCase.java 원문 확인). 즉 SendMoneyService 에서 `@UseCase @Transactional` = `@Component @Transactional`. ca-tmpl 은 `@Component`/`@Service` 를 application-core 에서 허용(D13)하고 `@Transactional` 만 금지. 이 분리는 Buckpal 과 다름.
- 추가로 봐야 할 Buckpal 관련 자료: [[raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement]] — 이미 보관된 Hombergs 블로그 글이 `@Transactional` 배치를 직접 다룸. BUCKPAL-TX-C1/C2 와 함께 읽으면 Hombergs 의 입장이 더 명확해짐.
---
## Decision Evidence Map / 결정-근거 매핑
> 이 raw source 가 각 parent branch 의 어떤 Decision ID 를 뒷받침(또는 반박)하는지 명시한다.
> `CONTRARY` = 결정과 반대 방향의 evidence (결정 자체를 reject 하지 않음 — 결정이 소수파임을 기록).
> `UNSUPPORTED_DECISION` = 이 자료만으로는 증명 불충분.
### Parent: feature-architecture-enforcement-rules
| Decision ID | Decision (요약) | This source's role | Supporting Claim IDs | Evidence Strength | Notes |
|---|---|---|---|---|---|
| D3 | `domain-core` forbidden import rule (Lombok 포함) | **CONTRARY** — Buckpal 은 domain purity rule 에서 `lombok..` 를 allowlist. ca-tmpl 금지 결정과 반대 방향 | `BUCKPAL-LOMBOK-C1`, `BUCKPAL-LOMBOK-C2` | `engineering-blog` | D3 결정 자체를 override 하지 않음. "ca-tmpl D3 가 OSS 공통 표준이 아닌 자체 stricter stance" 임을 입증하는 CONTRARY evidence 로만 사용 |
| D8 | application `@Transactional` 직접 import 금지 | **CONTRARY** (보조) — Buckpal application service 가 `@Transactional` 직접 부착. `feature-architecture-enforcement-rules` D8 이 `feature-application-port-usecase-contract` 를 근거로 인용하므로 간접 CONTRARY | `BUCKPAL-TX-C1`, `BUCKPAL-TX-C2` | `engineering-blog` | D8 원 근거는 `feature-application-port-usecase-contract`. 본 자료는 보조 CONTRARY evidence. D8 결정을 override 하지 않음 |
| D1, D2, D4~D7, D9~D12 | 기타 결정 | **NOT APPLICABLE** — 이 자료는 ArchUnit DSL 사용 사실(Q3), domain purity allowlist(Q1/Q2) 만 증명. 나머지 결정(Gradle module boundary, shared-contract scope, sample-ticket 금지, ArchUnit fail mode 등)에 대한 직접 claim 없음 | — | — | UNSUPPORTED_DECISION 아님 — 이 자료의 범위 밖 결정들. 기존 cited sources 가 별도로 지원 |
### Parent: feature-application-port-usecase-contract
| Decision ID | Decision (요약) | This source's role | Supporting Claim IDs | Evidence Strength | Notes |
|---|---|---|---|---|---|
| D3 | application use case 가 transaction boundary owner — but Spring `@Transactional` 직접 import 금지, `TransactionPort` 사용 | **CONTRARY** — Buckpal 은 `TransactionPort` abstraction 없이 `@Transactional` 직접 부착. 이 자료는 "다수파" 가 어떻게 구현하는지를 구체적 OSS 코드로 뒷받침 | `BUCKPAL-TX-C1`, `BUCKPAL-TX-C2` | `engineering-blog` | D3 자체는 `UNIL-TX-C1/C2`, `VSOUM-TX-C1/C2` 로 지원됨 (`company-case-study`). 이 자료는 그 결정이 소수파임을 보강하는 CONTRARY evidence. D3 를 UNSUPPORTED_DECISION 으로 격하하지 않음 |
| D4 | `@Transactional` 직접 부착이 hexagonal 표준 다수파임을 인정 | **SUPPORTING (CONTRARY direction)** — D4 는 ca-tmpl 이 이미 인정한 "다수파" 사실. 이 자료의 BUCKPAL-TX-C1/C2 는 그 다수파의 구체적 저명 OSS 선례를 제공 | `BUCKPAL-TX-C1`, `BUCKPAL-TX-C2` | `engineering-blog` | D4 는 이미 `AT-TX-C1`, `HEX-REFL-C1/C5` 로 지원됨. 이 자료는 추가 corroborating evidence |
| D1, D2, D5~D14 | 기타 결정 | **NOT APPLICABLE** — 이 자료는 Buckpal 의 `@Transactional` 직접 사용 패턴만 증명. naming convention, CQS 분리, TransactionTemplate, Arrow Kt, AOP interceptor, pool sizing, KEYED freeze 등에 대한 직접 claim 없음 | — | — | UNSUPPORTED_DECISION 아님 — 이 자료의 범위 밖 결정들 |
### UNSUPPORTED_DECISION 목록 (이 자료 기준)
이 raw source 단독으로 아래 진술을 지지하면 UNSUPPORTED_DECISION:
| 진술 | 판정 | 이유 |
|---|---|---|
| "Lombok 사용이 domain purity 에 문제없다" | UNSUPPORTED_DECISION | BUCKPAL-LOMBOK-C1/C2 는 Buckpal 의 설계 결정만 증명. 일반 원칙으로 확대 불가 |
| "`@Transactional` 직접 부착이 Hexagonal Architecture 의 권장 패턴이다" | UNSUPPORTED_DECISION | BUCKPAL-TX-C1/C2 는 Buckpal 선례만 증명. Spring 공식 또는 Hexagonal Architecture 명세가 이 배치를 "권장" 한다고 말하지 않음 |
| "ca-tmpl D3 (Lombok 금지) 결정이 잘못됐다" | UNSUPPORTED_DECISION | 이 자료는 CONTRARY evidence. override 의도 아님. D3 변경은 별도 Decision Review 필요 |
| "ca-tmpl D3 (TransactionPort) 결정이 잘못됐다" | UNSUPPORTED_DECISION | 동일 — CONTRARY evidence. `UNIL-TX-C1/C2`, `VSOUM-TX-C1/C2` 가 TransactionPort 선택 근거로 별도 지원됨 |
---
## Related / 관련
- [[raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement]] — 동일 저자(Tom Hombergs)의 `@Transactional` 위치에 관한 블로그 글. BUCKPAL-TX-C1 의 맥락 보완
- [[raw/official-docs/at-transactional-spring-official]] — `@Transactional` 직접 부착의 Spring 공식 지원 근거. BUCKPAL-TX-C1 와 함께 "다수파" 를 구성하는 공식 근거
- [[raw/official-docs/lombok-builder-data-features-official]] — ca-tmpl D3 의 Lombok 금지 근거. BUCKPAL-LOMBOK-C1 의 반대 방향 공식 문서
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — D3 결정 원문. BUCKPAL-LOMBOK-C1/C2 가 CONTRARY evidence 로 기재되어야 하는 Decision Evidence Map 위치
- [[raw/branch-notes/feature-application-port-usecase-contract]] — D1/D3/D4 결정 원문. BUCKPAL-TX-C1/C2 가 CONTRARY evidence 로 기재되어야 하는 Decision Evidence Map 위치