@Entity는 데이터베이스 테이블과 매핑되는 인프라 객체다. 이름이 같지만 완전히 다른 개념이다.
Clean Architecture(20장)에서 말하는 Entity는 "핵심 업무 규칙(Critical Business Rules)"과 "핵심 업무 데이터(Critical Business Data)"를 하나로 모은 객체다.
예를 들어 대출 이자를 계산하는 규칙과, 그 계산에 필요한 원금·이율·기간 데이터를 함께 보관하는 Loan 객체가 Entity다.
반면 JPA @Entity는 ORM 프레임워크가 DB 테이블과 객체를 매핑하기 위해 붙이는 어노테이션이다. 이 어노테이션이 붙으면 객체는 인프라(데이터베이스)에 의존하게 된다.
Clean Architecture는 이 둘을 반드시 분리해야 한다고 말한다.
그래서 질문처럼 "외부 인프라 계층에 오염되면 안 된다"는 말은 맞다 — Clean Architecture의 Entity에는 @Entity, @Table, @Column 같은 JPA 어노테이션이 붙으면 안 된다.
그것은 도메인 순수성을 해치는 오염이다.
Clean Architecture의 동심원 구조를 먼저 떠올려야 한다. 가장 안쪽 원이 Entity 계층이고, 바깥쪽으로 갈수록 Use Case → Interface Adapters → Frameworks & Drivers 순서다.
의존성 규칙(Dependency Rule): 소스 코드의 의존성은 반드시 안쪽(고수준)을 향해야 한다. Entity는 가장 안쪽이므로 아무것도 의존하지 않는다. JPA는 Frameworks & Drivers 계층에 해당하므로, Entity가 JPA를 알아서는 안 된다.
DDD(Domain-Driven Design)의 Entity도 같은 맥락이다. DDD에서 Entity는 고유한 식별자(identity)를 가진 도메인 객체다. Clean Architecture의 Entity 개념은 DDD Entity와 거의 일치한다. 두 개념 모두 "비즈니스 로직이 여기에 산다"는 철학을 공유한다.
"도메인이라고 봐야 하나요?" — 맞다. Clean Architecture의 Entity는 도메인 계층에 속한다. 실제 Spring 프로젝트에서 이를 구현할 때 흔히 두 가지 클래스를 따로 만든다:
Loan (domain/entity 패키지) — 순수 자바 객체, 업무 규칙 포함, JPA 어노테이션 없음LoanJpaEntity 또는 LoanEntity (infrastructure/persistence 패키지) — @Entity, @Table 붙은 JPA 매핑 객체그리고 Repository 구현체에서 LoanJpaEntity ↔ Loan 간 변환(매핑)을 수행한다. 이 변환 코드가 번거롭게 느껴지지만, 이것이 도메인을 인프라로부터 보호하는 핵심 장치다.
왜 이게 중요한가? JPA @Entity는 다음과 같은 제약을 강제한다: 기본 생성자 필요, 필드를 final로 만들기 어려움, Lazy Loading을 위한 프록시 생성 등. 이런 기술적 제약이 도메인 객체 설계를 훼손한다. 순수한 도메인 객체는 이런 걱정 없이 불변(immutable)으로, 의도를 드러내는 방식으로 설계할 수 있어야 한다.
실무에서의 타협점: 소규모 프로젝트에서는 JPA Entity에 업무 로직을 함께 담기도 한다. 이는 Clean Architecture를 완전히 따르지 않는 pragmatic한 선택이지만, 의도적인 트레이드오프임을 인식해야 한다. 프로젝트가 커지고 도메인 로직이 복잡해질수록 분리의 필요성이 드러난다.
왼쪽의 동심원에서 Entity는 가장 안쪽 — 아무 것에도 의존하지 않는다. 오른쪽은 두 클래스를 분리한 실제 구현 패턴이다. Repository 구현체가 LoanJpaEntity를 DB에서 조회한 후 Loan으로 변환해 도메인 계층에 전달한다.