본문 바로가기

카테고리 없음

JPA는 레이어드 아키텍처에서 어디에 속할까?

*상위 문서: 코드 리뷰: 불완전한 객체에서 나타난 문제들

 

JPA를 사용하던 중 도메인 모델링의 규칙과 JPA의 규칙이 상충하는 일이 생겼습니다. 

 

Progress라는 Help가 가진 값객체에서 Optional한 필드를 만들고 싶었지만 값객체가 JPA의 @Embeddable로 구현되어 있어 JPA 오류가 생겼습니다. 

실행시에는 JdbcTypeRecommendationException이 나옵니다.

 

 

A. 문제가 생긴 이유

    JPA를 처음 배울때 객체지향 방식을 따라서 데이터 베이스에 영속화 시켜주기에 도메인의 엔티티들과 자연스럽게 같이 프로젝트에서 사용되었습니다. 그러나 프로젝트는 꼭 JPA를 영속화도구로 이용하지 않을 수 있습니다. Mapper를 이용한 MyBatis, iBatis를 사용할수도 있고 preparedstatement나 statement를 이용하거나 JdbcTemplate을 사용할 수도 있습니다. 

 

    개발의 편의성을 위해 JPA를 도메인 계층에서 이용하고 있었지만 엄밀히 따지면 도메인 계층이 인프라 계층의 코드에 의존하고 있어서 생긴 문제 입니다. 

 

B. JPA는 어느 계층에 위치해야 할까.

    레이어드 아키텍처에 따라서 계층을 분리하면 유연한 아키텍처를 만들 수 있겠지만 꽤나 번거로운 일이기도 합니다. 특히 프로젝트의 기술적인 변경 가능성이 적다면 오히려 계층 분리에 드는 비용이 더 들수도 있습니다. 

 

    JPA를 도메인 로직과 분리할때 생기는 장점과 단점을 정리해보겠습니다. 조금 더 구체적으로 말하자면 인프라의 엔티티와 도메인의 엔티티(모델)을 분리할때 생기는 장단점입니다. 

 

장점

  • 인프라의 구현의 한계가 지금처럼 도메인 모델링에 영향을 끼치지 안습니다. 
  • 현재 MySQL을 이용하고 있지만 JPA로 이용하지 않는 NoSQL기반의 데이터베이스로 변경이 쉽게 변경이 가능합니다.
  • 도메인 계층에 영향을 주지 않고 캐싱을 도입하기도 쉬워 집니다.

단점

  • 도메인 엔티티와 인프라의 엔티티를 매번 각각 구현해야 합니다.
  • 도메인 모델링과 인프라의 엔티티 모델링이 구현 한계에 따라 달라질 수 있고 이 경우 복잡성이 매우 증가합니다. 
  • 이 둘을 변환 시켜주는 과정이 또한 필요합니다. 

 

C. 변경 과정 

우선 인프라 계층의 디렉토리에 JPA엔티티들을 관리하기 위한 entity라는 폴더를 만들 었습니다. 

 

왼쪽: 변경 전 / 오른쪽: 변경 후

 

JPA 엔티티를 만들어 JPA의 @Embeddable을 그대로 이용할 수 있도록 하였습니다. 

@Embeddable
@NoArgsConstructor
public class ProgressEntity {

    private Long helperId;
    private String photoPath;

    @Getter
    @Enumerated(EnumType.STRING)
    private Progress.ProgressStatus status;

    @Getter
    private boolean completed;
}

 

기존 도메인 계층의 모델은 Optional을 사용할 수 있게 되었습니다. 

@Getter
public final class Progress {
    private final ProgressStatus status;
    private final Optional<Long> helperId;
    private final Optional<String> photoPath;
    private final boolean completed;
}

 

D. 결론

 

    구현을 하면서 느꼈지만 인프라에 엔티티를 만들어서 관리하는게 시간도 많이 들고 쉽지만은 않았습니다. 특히 두개의 엔티티를 매번 매퍼 엔티티로 바꾸어 주어야하는 작업은 모델링이 복잡 할 수록  꽤나 번거로웠고 코드가 많아지면 필드값을 넘겨주면서 실수할수도 있겠다는 생각이 들었습니다. 

 

    이렇게 JPA를 인프라계층과 도메인계층으로 분리하는 것은 결국 trade-off를 생각해야 합니다. 들이는 개발시간과 수고로움보다 기술 변경의 유연성이 중요하다면 이렇게 만드는 것이 레이어드 아키텍처의 원칙에는 더욱 부합하다고 생각됩니다. 그렇지만 특히 영속성 기술은 한번 채택 시 잘 변경되지 않는 경향이 있고, 도메인 모델링이 추가될수록 복잡도가 증가하고 변경때 들어가는 수고로움도 굉장히 늘어나다보니 처음부터 도입하기 보단 일단 JPA코드를 도메인 계층에서 사용하다가 분리가 필요한 임계점을 잘 찾아 필요할때 과감히 분리하는 방법이 좋을 수 있다고 생각합니다. 

 

 

더보기:

레이어드 아키텍처

 

출처

심규민님의 우리는 DDD와 Layered Architecture 잘 쓰고 있는 걸까?(JPA는 Infra 계층인걸까?)

공병주님의 의존성 리팩터링을 하면서 느낀점(JPA, DDD)

coco3o님의 Service와 Repository를 완전히 분리하기 (with. DDD)

Big Sun님의 DDD의 Entity와 JPA의 Entity를 구분해야 하는 것인가?