강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

hklee.study님의 프로필 이미지
hklee.study

작성한 질문수

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

MemberRepository의 JPA 종속성에 관하여

해결된 질문

작성

·

341

0

쉽게 이해할 수 있게 설명해주셔서 강의 잘 봤습니다. 👍

 

강의 후반부(39. 문서와 코드 다듬기)에 MemberRepository에 @Query를 사용하면서 JPA 종속성이 추가되었는데 이 부분에 대해서 언급 없이 2가지 조인 방식과 관련하여 설명하고 넘어갔습니다.

강의 중반부(23. 회원 애플리케이션의 포트 정의)의 MemberRepository 설명과 같이 spring-data-commons의 Repository라는 마커 인터페이스를 사용하는 것은 동의하나 application layer에 기술 종속성이 추가된 내용 관련하여 부가 설명 요청 드려도 될까요?

 

물론 다음 강의에 해당 설명이 있을것으로 생각되지만..

 

MemberQueryRepository로 분리하고 adapter layer에서 구현하는 방향이 더 좋아보이는데 개선 방향도 같이 부탁드립니다.

답변 1

2

토비님의 프로필 이미지
토비
지식공유자

강의 후반부로 가면서 설명해야 할 것들이 너무 많아서 @Query라는 스프링 데이터의 JPA용 애노테이션 사용에 대해서는 별다른 언급을 하지 않고 넘어갔습니다. 날카롭게 질문을 해주셨네요.

 

Repository는 헥사곤 내에 정의된 포트이고 기술에 종속되지 않아야 하는 것이 아키텍처 요구사항으로 맞습니다. 이걸 풀어내려면 엔티티까지는 아니더라도 MemberRepository는 메소드 정의만 해두고, 어댑터에서 이를 구현한 클래스를 만들고 거기서 다시 MemberJpaRepository 인터페이스를 스프링 데이터 JPA로 만든 것을 재호출하는 식으로 구현을 해야할 겁니다.

그런데 저는 이렇게 질문을 하고 싶어집니다. 그렇게 해서 얻는 효과가 무엇이죠? 어떤 이득이 있나요.

말씀하신 JPA에 종속이라는 건 어떤 의미인가요? 이건 다시 엔티티 클래스까지 올라가서 이야기를 해야할 겁니다. @Entity라는 JPA의 애노테이션이 붙으면 Member는 JPA 기술에 종속되었다고 할 수 있나요?

물론 특정 기술, 그것도 변경 가능한 선택 기술 중의 하나에 등장하는 어떤 코드가 존재하는 것이 어떻게 그 기술에 종속을 만들어낼까요? 엔티티에 JPA 애노테이션이 붙은 것을 도메인 엔티티로 사용하는 것이 더 나은 선택이라고 판단했던 것과 거의 동일한 논리로 저는 MemberRepository에 JPA 애노테이션이 붙은 코드를 그대로 사용하는 것이 아키텍처 관점에서, 혹은 코드를 이해하거나 변경에 대응할 수 있는 관점에서 특정 기술에 종속되었다고 보지 않습니다.

코드의 종속이란, 내가 종속한 코드 또는 해당 기술의 변경이 내 자신에게 변경을 요구할 가능성이 있는 경우에 쓰는 말입니다. @Query가 JPA의 JPQL을 담은 기술 지식을 드러내는 코드임에 분명하지만, 강의에서도 여러번 강조했듯이 애노테이션은 코드의 동작에 그 자체로 "직접적으로는" 영향을 미치지 않는 "주석"에 불과합니다.

JPA의 @Entity가 붙은 엔티티 클래스를 JPA가 아니라 MongoDB로 기술이 변경되더라도 지금 Member의 주석(애노테이션)이 아닌 코드의 동작 방식, 예를 들어 도메인 테스트에 전혀 영향을 주지 않습니다. @Document라는 애노테이션을 @Entity 위에 하나 더 붙여주면 기술적으로도 충분하죠.

저는 그런 관점에서 기술 애노테이션이 붙은 코드는 해당 기술을 쓰지 않으면 그 애노테이션은 의미가 부족한 주석이거나, 아니면 orm.xml 등으로 분리한 후에 남은 JPA 엔티티 관점에선, 도메인의 의미를 잘 드러내주는 이해를 돕는 주석으로 사용된다고 봅니다.

JPA는 도메인 오브젝트를 객체지향적인 모델 구조를 그대로 유지해서 도메인 구성요소를 만들고 도와주는 기술입니다. 그래서 @Query에 붙은 JPQL은 해당 리포지토리의 메소드가 어떤 엔티티 정보를 주어진 파라미터를 조건으로 해서 가져올지에 대한 주석으로도 가치가 있습니다. @Query라는 애노테이션이 JPA이기 때문에 가지는 특별한 기술적 표현은 아니자나요. 이걸 JPA가 아닌 다른 저장 기술로 대체된다고 하더라도, 그 상세 조회로직 구현은 어댑터에서 만들어진다고 하더라도 @Query와 JPQL은 도메인 엔티티에 대한 객체지향적인 조회 로직을 잘 표현했기에, 그대로 두어도 괜찮아 보입니다. 물론 순간 JPA 쓰는 건가라는 애플리케이션 레이어 밖의 관심에 주의를 기울이면 살짝 헷갈릴 수는 있겠지만요.

@Query는 이 인터페이스가 순수한 DDD의 도메인 구성요소로서 리포지토리, 내지는 헥사고날 아키텍처의 기능 제공 인터페이스인 포트를 정의한 인터페이스 코드로서 그 기능에 영향을 주지 않습니다. Spring Data JPA를 쓰지 않고 이걸 구현한 어댑터를 따로 만들어서 다른 스토리지 기술을 구현한 상황이 되더라도 리포지토리 인터페이스 코드는 전혀 손대지 않아도 됩니다. JPA의 애노테이션이 붙어 있어서 jpa api를 담은 jar 파일이 컴파일할 때 계속 필요하다는 것 하나만 빼면요.

그런 관점에서 저는 JPA의 애노테이션을 리포지토리에 사용하는 순수주의자들이 볼 때는 불편할 수도 있는 트레이드 오프를 선택한 겁니다. 트레이드 오프라고 해봤자, 별로 포기해야 할 것이 없다고도 생각이 되고요.

애노테이션이 붙어도 여전히 도메인 계층의 오브젝트와 도메인 보편 언어로 정의된 깔끔하고, 기술이나 환경에 휘둘리지 않으면서, 테스트도 얼마든지 독립적으로 수행할 수 있는 헥사고날 아키텍처가 추구하는 이상에 가가운 포트의 정의로서 이런 선택을 했습니다.

JPA에 종속되었다는 것이 어떤 의미인지, 어떤 영향을 주는 것인지 다시 생각해보시면 제 선택이 그리 나쁘지만은 않다고 생각될 수 있을 겁니다. 겨우 그 애노테이션 붙인 걸 피하기 위해서 "아무런 가치도 주지 않는 기계적인 어댑터와 거의 비슷하게 생긴 추가 인터페이스 정의를 만드는 것"과 비교했을 때 저는 충분히 나은 선택이라고 생각합니다.

이 설명을 자세히 하지 않고 얼렁뚱땅 넘어간 듯해서 조금 신경이 쓰였는데 아무튼 질문을 해주셔서 감사합니다. 다음 편에서는 더 복잡한 JPA @Query 류들이 등장을 하게 될텐데 그때 또 여러가지 이야기를 하게 될 듯합니다. 특히, 인터페이스 정의로는 충분하지 않은 QueryDSL 구현이 사용되는 경우는 확연히 구별된 접근을 하게 될 것이고요. 물론 그때도 Spring Data JPA가 제공하는 편리하는 기능을 선택할 수도 있습니다만, 이건 그 파트에서 저도 고민을 하면서 더 얘기를 꺼내보겠습니다.

 

hklee.study님의 프로필 이미지
hklee.study

작성한 질문수

질문하기