영속성 어댑터

의존성 역전

  • 영속성 어댑터와 포트 인터페이스

    • 영속성 계층에 대한 코드 의존성을 없애기 위해 간접 계층(포트 인터페이스)을 추가한다.

    • 영속성 어댑터는 애플리케이션 서비스에 영속성 기능을 제공한다.

    • 실제 영속성 작업 수행하고 DB와 통신하는 영속성 어댑터는 포트 인터페이스를 구현한다.

  • 영속성 어댑터는 애플리케이션에 의해 호출되기만 하는 아웃고잉 어댑터이다.

영속성 어댑터의 책임

💡 5가지 책임

  • 입력을 받는다

  • 입력을 데이터베이스 포맷으로 매핑

  • 입력을 데이터베이스로 전달

  • 데이터베이스 출력을 애플리케이션 포맷으로 매핑

  • 출력 반환

  • 입력 모델을 데이터베이스 테이블 구조를 반영한 JPA 엔티티 객체로 매핑

    • 맥락에 따라 매핑할 필요 없을 경우도 있음 (경계 간 매핑 참고)

  • 영속성 어댑터의 입력 모델과 출력 모델이 애플리케이션 코어에 있으므로 영속성 어댑터 내부를 변경해도 코어에 영향을 미치지 않음

    • entity를 입력/출력모델로 변경하는 것처럼 만약 다른 기술을 사용하더라도 매핑만 잘해주면 된다

포트 인터페이스 나누기

  • 특정 엔티티가 필요로 하는 모든 DB연산을 하나의 Repository 인터페이스에 넣어두는 것이 일반적임

  • 각 서비스는 인터페이스에서 일부의 메서드만 사용하더라도 다른 넓은 포트 인터페이스에 의존성을 갖게 된다

  • 단위테스트 작성 시 인터페이스의 어떤 메서드를 모킹해야 할 지 찾아봐야 한다.

필요없는 메서드를 가진 클래스에 의존하고 있다면 예상치 못한 문제가 발생할 수 있다.

  • 인터페이스 분리 원칙에 따르면, 클라이언트가 자신이 필요로하는 메서드만 알면 되도록 넓었던 인터페이스를 특화된 인터페이스들로 분리해야 한다.

  • 인터페이스 분리 원칙을 적용해 불필요한 의존성을 제거하고, 기존 의존성을 눈에 띄게 만들 수 있다.

영속성 어댑터 나누기

  • 영속성 연산이 필요한 도메인 클래스 하나당 하나의 영속성 어댑터 구현 가능

  • 영속성 어댑터들은 각 영속성 기능을 이용하는 도메인 경계를 따라 나뉘어진다.

  • JPA나 OR Mapper를 이용한 영속성 포트를 구현하면서, 성능 개선을 위한 native SQL 이용하는 포트도 구현하려면 각각의 어댑터 클래스를 만들면 된다.

  • 한 Aggregate 당 하나의 영속성 어댑터를 가지는 방식은 바운디드 컨텍스트의 영속성 요구사항을 분리하기 위해 좋다.

    • 각 바운디드 컨텍스트는 영속성 어댑터를 하나 이상씩 가진다.

    • 어떤 컨텍스트가 다른 컨텍스트의 데이터를 필요로 한다면 바로 어댑터로 접근하는 것이 아닌, 전용 인커밍 포트로 접근해야 한다.

데이터베이스 트랜잭션

  • 트랜잭션은 하나의 특정한 유스케이스에 대해 일어나는 모든 쓰기 작업에 걸쳐있어야 다같이 롤백이 가능하다.

  • 유스케이스를 구현한 애플리케이션 서비스 클래스에 @Transactional 을 붙여 모든 public 메서드를 트랜잭션으로 감쌀 수 있다.

    • 이 방식보다는 각 메서드마다 설정하면 될 것 같다.

영속성 엔티티와 도메인 엔티티

  • 영속성 엔티티와 도메인 엔티티를 따로 두면 양방향 매핑이 존재하게 된다.

  • 물론 매핑하지 않기 전략을 사용할 수도 있겠지만, 항상 원하는 로직이 영속성 엔티티의 구조와 같을 순 없다.

  • 예제에서는 항상 데이터의 일부만 가져오길 바라기 때문에 연관관계 매핑도 사용하고 있지 않다.

  • 영속성 측면과 타협없이 풍부한 도메인 모델을 생성하고 싶다면 도메인 모델과 영속성 모델을 매핑하는 것이 좋다.

Last updated