inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1

엔티티 식별자와 JPA 엔티티

JPA 엔티티로 만들었다고 기술종속이 아닌지에 대한 질문

49

LichKing

작성한 질문수 4

0

안녕하세요. 강의 잘 듣고있습니다.

오늘 수강한 "엔티티 식별자와 JPA 엔티티" 에서 JPA 엔티티로 만들었다고해서 달라진게 없다 라고 표현하셨는데요. 애노테이션을 붙여서 컴파일 단계의 의존성은 생겼지만 해당 클래스가 다른 기술적 종속이 생긴건 아니라고 말씀하신거에 질문이 있습니다.


일단 애노테이션을 붙인 것을 용인할 수 있다는건 이해했고, 저도 동의합니다. 그런데 JPA 엔티티가 됨으로써 해당 클래스는 final 로 만들 수 없고, 생성자도 기술적 요구사항에 의해 최소 protected 로 공개할 수 밖에 없는데요. 이번 강의에서도 기존 의도는 private 이었지만 기술을 도입함으로써 애노테이션을 붙이는 것 이상의 작업이 있었습니다(생성자의 접근 수준 변경).


정말 애노테이션만 붙이고 아무것도 하지 않았다면 납득할 수 있지만 애노테이션 외에 다른 변경이 발생했는데도 기술적 종속이 없다고 볼 수 있을까요? 이정도 수준의 변경과 의존은 트레이드오프로 용인할 수 있다고 생각하면 할수는 있지만 엄밀히 따진다면 객체 설계에 영향을 줬다고 생각하는데, 어떻게 생각하시는지 궁금합니다.

java spring spring-boot jpa 리팩터링 ddd

답변 3

0

LichKing

답변해주셔서 감사합니다!

강의 내에서 말씀해주신 부분들도 어떤 의도에서 하신 말씀인지 이해되고, 제 질문에 답변주신 것들도 다 이해됩니다. 다만 토비님의 생각이 궁금해서 좀 더 질문을 이어가보겠습니다.


JPA(엄밀히 얘기하면 hibernate) 가 나오기전 ORM 기술이 강하고 복잡한 기술적 요구사항이 있었고, 이에 비해 JPA 가 요구하는 기술적 요구사항은 대단히 미미한 부분이라는 점도 인지하고 있습니다. 불필요한 상속을 받아야하고, 기술때문에 메서드를 구현해야하는 일에 비해서 protected 생성자 하나 만드는 수준은 충분히 용인 가능한 수준입니다.


하지만 용인 가능한 미미한 수준의 기술적 의존이 있는것과 기술적 의존이 아예 없는건 좀 다르다고 생각해서 질문을 이어가는데요. 답변해주신 부분에서 "기존 코드를 그대로 두고 기술을 바꿔도 무방합니다." 라고 말씀해주셨습니다. 다만 제 생각에 토비님의 답변은 기본적으로 처음부터 JPA 를 사용한다는 전제에서는 동의하는데요.

만약 JDBC 를 사용해서 직접 매핑코드를 구현하고, 도메인모델을 생성하는 애플리케이션이 있다고 가정해보겠습니다. 직접 매핑코드를 구현하고 있기 때문에 파라미터없는 기본 생성자는 없는 상태입니다. 이때 해당 애플리케이션에 JPA 를 도입하자는 의사결정이 나오게 된다면 코드 내부가 변경될 수 밖에 없습니다.


의사결정자들은 기존 도메인 모델을 건드리지 말자고 결정했기때문에 JPA 관련된 설정들은 모두 orm.xml 로 처리하기로 했을때 이때도 생성자만큼은 해결할 수 없게됩니다.


제가 극단적인 예시를 들었지만 이런 상황이 발생할 수 있는 것 자체가 어느정도는 기술의존성이 있다는거 아닐까 싶은데요. 혹시 토비님의 생각을 더 들어볼 수 있을지 궁금합니다.

0

토비

네. 기술 변경 때문에 코드를 고쳐야 하니 기술의존성이 있습니다. 제 설명이 부족했나보네요.

하지만 저는 이런 기술의존성이라면 얼마든지 선택할 겁니다.

0

LichKing

제가 너무 극단적으로 여쭤본것 같아 죄송합니다. 답변 감사합니다!

0

토비

날카로운 질문을 해주셨네요.

언급하신 제약사항이 JPA로 만든 도메인 엔티티의 상속 가능성, 생성 방식, 불변성 설계에 일부 영향을 미치는 것이 사실입니다. final을 사용하지 못해서 완전히 닫힌 타입을 만들지 못하는 것, 사용 가능성은 극히 낮지만 어쨌든 기술적으로 디폴트 생성자 호출이 가능해지는 것 등은 분명히 JPA 기술의 제약 때문에 도입되는 현상입니다.

만약 언어가 주는 특성을 모두 이용해서 강력한 캡슐화를 진심으로 원한다면 트레이드 오프라고 고민할 수도 있겠죠. 포기해야 할 것들이 있으니까요.

그런데 이건 도메인 모델을 코드에도 반영해서 구현하는 도메인 모델 패턴 방식에서 제약이라고는 보지 않습니다. JPA를 사용해도 private 필드를 쓰고, setter를 최소화하고, 도메인 메소드를 이용해서 상태 변경을 사용할 수 있습니다. 도메인 로직을 구현하고 기능을 넣는 것에서 방해되는 것은 없습니다. 상속도 자유롭게 사용할 수 있고요. 그런면에서 JPA가 주는 제약이 도메인 설계를 방해하는 것은 거의 없다고 봅니다.

기술 종속도 마찬가지입니다. 이런 제약을 가지고 만들어진 JPA 엔티티가 JPA 외의 기술로 대체되거나, 아예 데이터 모델을 독립시키고 매핑을 한다고 했을 때 기존의 JPA를 사용하는 도메인 엔티티가 방해를 하나요? 기존 코드를 그대로 두고 기술을 바꿔도 무방합니다. 강의에서 처럼 애노테이션은 도메인 설계의 의미를 담은 주석 역할로 의미있는 것만 남기고, 매핑은 XML로 빼둔다면 더더욱 그렇습니다. JPA를 사용하지 않게 되면서 굳이 기본 생성자가 만들어지는 게 싫다면 Lombok 설정 한 줄 제거하면 됩니다. 그 외에는 어떤 저장 기술로 바뀐다고 하더라도 도메인 로직을 충실하게 구현한 코드가 JPA에서 다른 기술로 대체되었을 때 이를 방해하거나 어렵게 만들 이유는 전혀 없습니다.

그런면에서 저는 기술에 종속되었거나 설계에 영향을 미쳤다고는 생각되지 않습니다. 구현에 약간의 군더더기를 남긴다 정도면 충분할 듯합니다.


0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다. LichKing님!

JPA 엔티티로 만들면서 @Entity 애노테이션뿐 아니라 final 제한, 기본 생성자의 접근 수준 변경 등 객체 설계에도 영향을 받는다는 지적은 타당합니다. 따라서 엄밀하게 말하면 JPA에 아무런 기술적 종속이 없다고 표현하기보다는, JPA가 도메인 모델의 코드와 설계에 일부 제약을 주지만 그 제약을 트레이드오프로 받아들일 수 있다는 의미로 이해하는 것이 적절합니다.

JPA는 프록시를 생성하거나 엔티티를 인스턴스화하기 위해 엔티티 클래스와 생성자에 일정한 조건을 요구합니다. 예를 들어 다음과 같은 제약이 생길 수 있습니다.

  • 엔티티 클래스를 final로 선언하기 어려움
  • 기본 생성자가 필요하며, 일반적으로 protected 이상의 접근 수준을 사용
  • 지연 로딩을 위해 메서드나 클래스의 final 사용이 제한될 수 있음
  • JPA 생명주기와 영속성 컨텍스트를 고려한 객체 설계가 필요함

따라서 이 부분은 단순히 컴파일 의존성이나 애노테이션 의존성만의 문제가 아니라, 객체 모델의 설계 방식에 영향을 미치는 실질적인 기술 제약이라고 볼 수 있습니다.

다만 토비님께서 말씀하신 취지는 이러한 제약이 존재하지 않는다는 뜻이라기보다는, JPA를 사용하더라도 도메인 모델의 핵심 로직과 객체 구조를 JPA의 테이블 모델에 맞춰 크게 훼손하지 않을 수 있다는 의미에 가깝습니다. 생성자를 private에서 protected로 변경하는 것은 분명 설계상의 양보이지만, 생성자 내부의 도메인 규칙이나 외부에서 객체를 임의로 생성하지 못하게 하는 의도 자체는 유지할 수 있습니다. 즉, 기술 제약을 최소한의 범위에서 수용하고 도메인 모델의 본질적인 설계는 보존하는 방식입니다.

결국 핵심은 “기술 종속이 있는가, 없는가”를 이분법적으로 판단하기보다 다음과 같은 트레이드오프를 비교하는 것입니다.

  1. JPA가 요구하는 생성자와 프록시 제약을 수용하면서 도메인 모델의 장점을 얻을 것인지
  2. JPA와 도메인 모델을 완전히 분리하기 위해 별도의 매핑 객체와 변환 코드를 만들 것인지
  3. 기술 변경 가능성이 실제로 높은 시스템인지
  4. 분리를 통해 얻는 이익이 추가적인 코드와 복잡성보다 큰지

이와 관련해서 토비님께서 JPA 엔티티와 기술 종속성, 애노테이션의 의미를 설명한 기존 답변을 참고하시면 좋습니다.

해당 답변에서도 @Entity@Query 같은 애노테이션이 기술 의존성을 만들 수 있다는 점 자체를 부정하지는 않습니다. 다만 기술 변경 시 도메인 로직의 동작과 설계가 얼마나 크게 수정되어야 하는지를 기준으로 판단하며, 기계적인 분리 계층을 추가하는 것보다 현재 구조가 제공하는 생산성과 단순성이 더 큰 경우에는 이러한 제약을 수용할 수 있다고 설명합니다.

추가로 도메인 엔티티를 애플리케이션에서 반환하는 것과 DTO로 분리하는 트레이드오프에 대해서는 다음 답변도 함께 참고하실 수 있습니다.

결론적으로 LichKing님이 말씀하신 것처럼 JPA 도입은 애노테이션 이상의 변경을 발생시키며, 엄밀한 의미에서 기술 종속이 없다고 보기는 어렵습니다. 다만 그 종속이 도메인 모델의 핵심을 훼손하는 수준인지, 아니면 생성자 접근 수준과 프록시 지원 같은 제한적인 타협으로 충분한지는 시스템의 상황에 따라 판단할 문제입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

Part 2 듣기전 복습하던 중, 아키텍처에 관한 질문이 있습니다.

0

31

2

테스트는 인터페이스를 대상으로 만드는것에 대해 궁금한 점이 있습니다.

0

21

1

안녕하세요 토비님 혹시 완성된 코드의 repository 주소는 없을까요?

0

118

2

테스트 관련 질문!

0

96

2

N+1 관련해서 질문있습니다.

0

147

3

도메인 모델에서 관계와 규칙을 구분하는 방법

0

139

2

헥사고날 아키텍처에서의 배치, 시큐리티, 비동기 이벤트 처리는 어떻게 하나요?

0

220

2

어댑터에서 도메인에 직접 의존하는 경우에 대해

0

208

2

Member 도메인이 PasswordEncoder를 받는 구조 질문 있습니다.

0

179

2

MemberService와 EmailSender 책임 분리에 대한 질문

0

146

2

NonNullApi를 NullMarked로 대체하라고 합니다.

0

215

2

39. 문서와 코드 다듬기 updateInfo 테스트 질문 있습니다.

0

116

2

Repository Adapter 설계에 대해 피드백을 부탁드립니다

0

147

2

헥사고날 part2 강의 출시 예정일 문의 드립니다.

0

313

2

PT 문의사항

0

140

1

초기 어플리케이션 구동 시 compose.yml 파싱 오류

0

212

2

애플리케이션의 JPA 리턴과 도메인 모델

0

170

2

애그리거트 루트의 하위 도메인들의 depth가 깊어질 때 문의

0

183

2

페이징 처리를 해야한다면 어떻게 해야할까요?

0

240

2

애그리거트의 repository

0

166

2

Domain Expert가 정확히 어떤 역할을 하는 사람인가요?

0

314

1

회원 애플리케이션 서비스 테스트 (1)

0

148

2

정적 팩토리 메서드 관련 질문드립니다!

0

142

2

spotbug + @NonNullApi 로만 Null 방어가 될까요?

0

171

2