--- title: company-tech-blog / Hexagonal Architecture With Spring Boot — Arho Huttunen source_type: company-tech-blog url: https://www.arhohuttunen.com/hexagonal-architecture-spring-boot/ archive_url: related_branches: [feature-persistence-auditing-contract] related_projects: [ca-tmpl] tags: [company-tech-blog, ca-tmpl, architecture, spring-boot, hexagonal, clean-architecture, domain-purity] created: 2026-06-10 --- # company-tech-blog / Hexagonal Architecture With Spring Boot — Arho Huttunen > Layer: `raw/` — 외부 자료(전문가 기술 블로그)의 **원문 발췌·출처 기록**. > 검증된 요약은 `/ingest` 후 `wiki/concepts/`에 `source-summary-template` 형식으로 별도 작성. 원본은 raw에 영구 보관. ## Parent / 활용 branch (필수) | Branch | 이 자료가 정당화하는 결정 | |---|---| | [[raw/branch-notes/feature-persistence-auditing-contract]] | D2 (core mandate): Hexagonal / Clean Architecture 에서 JPA Entity 및 persistence 관심사는 persistence adapter 안에만 존재하고 domain model 과 분리해야 한다 — 따라서 audit 메타데이터(created_at / updated_at / created_by / updated_by)는 persistence-adapter JPA entity 또는 @MappedSuperclass 에 속하며, domain-core aggregate 를 오염시켜서는 안 된다. | ## 출처 / Source - 원본 URL: https://www.arhohuttunen.com/hexagonal-architecture-spring-boot/ - 아카이브 URL: (미제공) - 저자 / 조직: Arho Huttunen (개인 전문가 블로그) - 발행일: 미확인 (URL에 날짜 없음) - 마지막 확인일: 2026-06-10 ## 왜 저장했는지 / Why archived Hexagonal Architecture 에서 JPA Entity 를 domain model 과 분리해야 한다는 구체적 설계 패턴과 근거를 담고 있다. 특히 `OrderEntity` (JPA) vs `Order` (domain) 분리 패턴 및 persistence adapter 가 두 모델 사이의 mapping 을 전담한다는 내용은 `feature-persistence-auditing-contract` 의 D2 결정 — audit 메타데이터를 JPA entity 에만 두고 domain aggregate 를 오염시키지 않는다 — 을 직접 정당화한다. ## 핵심 인용 / Key quotes (verbatim, 3~5문장) > [§Persistence Adapter / Secondary Adapters] "The `OrderEntity` itself holds the `jakarta.persistence` annotations for ORM." > [§Persistence Adapter / Secondary Adapters] "A lot of applications pollute the domain model with such annotations. Here we have a clean separation of those concerns with the cost of having to do mapping between the models." > [§Persistence Adapter / Secondary Adapters] "The `OrdersJpaAdapter` takes care of the translation between the domain and the JPA entities." > [§Module Structure / Application Module] "the `coffeeshop-application` holds all the business logic and use cases of the application and does not depend on Spring Boot at all. In fact, the only dependencies it has are JUnit 5 and AssertJ." > [§Transaction Management] "if we truly want to keep frameworks out of the application core, we can do better." ## Claims Extracted / 추출된 주장 | Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove | |---|---|---|---|---|---| | C1 | JPA (`jakarta.persistence`) annotation 은 JPA entity class 에만 달고, domain model class 에는 달지 않는 것이 hexagonal architecture 의 관심사 분리 방식이다 | [§Secondary Adapters] "The `OrderEntity` itself holds the `jakarta.persistence` annotations for ORM." | `engineering-blog` | Spring Boot + JPA 기반 Hexagonal Architecture | JPA 이외의 persistence 기술(MongoDB, R2DBC 등)에서의 적용 방식 / Spring Data JPA 의 공식 권고 사항 | | C2 | Domain model 에 JPA annotation 을 추가하는 것은 관심사 오염이며, 올바른 분리는 domain ↔ JPA entity 매핑 비용을 수반한다 | [§Secondary Adapters] "A lot of applications pollute the domain model with such annotations. Here we have a clean separation of those concerns with the cost of having to do mapping between the models." | `engineering-blog` | persistence 관심사를 domain model 과 분리하려는 모든 아키텍처 | 매핑 비용의 구체적 수치 / 도메인 오염이 실제 프로젝트에서 야기하는 장애 | | C3 | Persistence adapter 가 domain 객체와 JPA entity 사이의 변환(translation)을 전담한다 | [§Secondary Adapters] "The `OrdersJpaAdapter` takes care of the translation between the domain and the JPA entities." | `engineering-blog` | Hexagonal Architecture 의 secondary adapter 구현 | MapStruct 등 특정 매핑 라이브러리의 사용 필수 여부 / 성능 특성 | | C4 | Application (domain) 모듈은 Spring Boot 에 전혀 의존하지 않는 것이 가능하다 — 테스트 라이브러리 외 프레임워크 의존성 zero | [§Module Structure] "the `coffeeshop-application` holds all the business logic and use cases of the application and does not depend on Spring Boot at all. In fact, the only dependencies it has are JUnit 5 and AssertJ." | `engineering-blog` | Gradle multi-module 기반 Hexagonal Architecture | 모든 Spring Boot 프로젝트에서 이 모듈 분리가 강제된다는 것 / 성능·빌드 시간 영향 | | C5 | @Transactional 과 같은 Spring 프레임워크 annotation 을 domain core 에 두는 것은 프레임워크 오염이며, 더 나은 방법(AOP aspect 활용 등)이 존재한다 | [§Transaction Management] "if we truly want to keep frameworks out of the application core, we can do better." | `engineering-blog` | Spring @Transactional 을 domain use case 에서 제거하고자 하는 설계 | Spring AOP aspect 방식이 모든 트랜잭션 경계 시나리오에서 동일하게 동작한다는 보장 | ## Usage Boundaries / 적용 경계 - 이 자료가 직접 증명하는 것: - `C1–C3`: Spring Boot + JPA 조합에서 JPA entity 와 domain model 을 분리하고 adapter 가 매핑을 담당하는 구체적 구현 패턴 (저자의 예제 코드 기반) - `C4`: Gradle multi-module 분리로 application module 의 Spring Boot 무의존성이 달성 가능함 - `C5`: @Transactional 을 domain core 밖으로 이동하는 방향성 - 이 자료가 증명하지 않는 것: - 이 패턴이 Spring 공식 권고 또는 best practice 임을 증명하지 않는다 (개인 블로그 — `engineering-blog` 등급) - audit 메타데이터(`created_at`, `updated_by` 등)를 JPA entity 에 두어야 한다는 것을 직접 언급하지 않는다 (D2 결론은 C1–C3 를 도메인에 적용한 추론) - `@MappedSuperclass` 또는 Spring Data JPA `@EnableJpaAuditing` 의 구체적 설정 - 내 프로젝트에 적용하려면 추가 확인이 필요한 것: - ca-tmpl 에서 audit entity (`AuditableEntity` 또는 `BaseEntity`) 가 실제로 JPA layer 에만 존재하는지 코드 grep 으로 검증 필요 - domain aggregate(`Order`, `Member` 등)에 JPA annotation 이 없는지 ArchUnit rule 으로 강제 여부 확인 ## 메모 / Notes - 이 블로그는 저자(Arho Huttunen)의 개인 전문가 블로그로, 대기업 엔지니어링 블로그가 아니다. 사용자가 `company-tech-blog`로 지정했으나, claim strength 는 `engineering-blog` 로 분류했다 — `company-case-study` 보다 낮은 등급. - 기술 블로그 단독으로는 "공식 best practice"로 인용 불가. D2 결정의 근거로 쓰되, Spring Data JPA 공식 문서(`official-vendor-doc` 등급)와 함께 병기하는 것이 권고됨. - 저자가 제공하는 전체 예제 코드는 Codeberg 에 있다고 언급됨 (링크 미포함). ## Related / 관련 - 동일 주제 공식 문서: [[raw/official-docs/spring-data-jpa-enable-jpa-auditing-api]] — Spring Data JPA `@EnableJpaAuditing` 설정 계약 - 이 자료를 인용한 wiki 요약: (생성 전)