영속성 어댑터
의존성 역전
영속성 어댑터와 포트 인터페이스
영속성 계층에 대한 코드 의존성을 없애기 위해 간접 계층(포트 인터페이스)을 추가한다.
영속성 어댑터는 애플리케이션 서비스에 영속성 기능을 제공한다.
실제 영속성 작업 수행하고 DB와 통신하는 영속성 어댑터는 포트 인터페이스를 구현한다.
영속성 어댑터는 애플리케이션에 의해 호출되기만 하는 아웃고잉 어댑터이다.
영속성 어댑터의 책임
💡 5가지 책임
입력을 받는다
입력을 데이터베이스 포맷으로 매핑
입력을 데이터베이스로 전달
데이터베이스 출력을 애플리케이션 포맷으로 매핑
출력 반환
입력 모델을 데이터베이스 테이블 구조를 반영한 JPA 엔티티 객체로 매핑
맥락에 따라 매핑할 필요 없을 경우도 있음 (경계 간 매핑 참고)
영속성 어댑터의 입력 모델과 출력 모델이 애플리케이션 코어에 있으므로 영속성 어댑터 내부를 변경해도 코어에 영향을 미치지 않음
entity를 입력/출력모델로 변경하는 것처럼 만약 다른 기술을 사용하더라도 매핑만 잘해주면 된다
포트 인터페이스 나누기
특정 엔티티가 필요로 하는 모든 DB연산을 하나의 Repository 인터페이스에 넣어두는 것이 일반적임
각 서비스는 인터페이스에서 일부의 메서드만 사용하더라도 다른 넓은 포트 인터페이스에 의존성을 갖게 된다
단위테스트 작성 시 인터페이스의 어떤 메서드를 모킹해야 할 지 찾아봐야 한다.
필요없는 메서드를 가진 클래스에 의존하고 있다면 예상치 못한 문제가 발생할 수 있다.
인터페이스 분리 원칙에 따르면, 클라이언트가 자신이 필요로하는 메서드만 알면 되도록 넓었던 인터페이스를 특화된 인터페이스들로 분리해야 한다.
인터페이스 분리 원칙을 적용해 불필요한 의존성을 제거하고, 기존 의존성을 눈에 띄게 만들 수 있다.
영속성 어댑터 나누기
영속성 연산이 필요한 도메인 클래스 하나당 하나의 영속성 어댑터 구현 가능
영속성 어댑터들은 각 영속성 기능을 이용하는 도메인 경계를 따라 나뉘어진다.
JPA나 OR Mapper를 이용한 영속성 포트를 구현하면서, 성능 개선을 위한 native SQL 이용하는 포트도 구현하려면 각각의 어댑터 클래스를 만들면 된다.
한 Aggregate 당 하나의 영속성 어댑터를 가지는 방식은 바운디드 컨텍스트의 영속성 요구사항을 분리하기 위해 좋다.
각 바운디드 컨텍스트는 영속성 어댑터를 하나 이상씩 가진다.
어떤 컨텍스트가 다른 컨텍스트의 데이터를 필요로 한다면 바로 어댑터로 접근하는 것이 아닌, 전용 인커밍 포트로 접근해야 한다.
데이터베이스 트랜잭션
트랜잭션은 하나의 특정한 유스케이스에 대해 일어나는 모든 쓰기 작업에 걸쳐있어야 다같이 롤백이 가능하다.
유스케이스를 구현한 애플리케이션 서비스 클래스에
@Transactional
을 붙여 모든 public 메서드를 트랜잭션으로 감쌀 수 있다.이 방식보다는 각 메서드마다 설정하면 될 것 같다.
영속성 엔티티와 도메인 엔티티
영속성 엔티티와 도메인 엔티티를 따로 두면 양방향 매핑이 존재하게 된다.
물론 매핑하지 않기 전략을 사용할 수도 있겠지만, 항상 원하는 로직이 영속성 엔티티의 구조와 같을 순 없다.
예제에서는 항상 데이터의 일부만 가져오길 바라기 때문에 연관관계 매핑도 사용하고 있지 않다.
영속성 측면과 타협없이 풍부한 도메인 모델을 생성하고 싶다면 도메인 모델과 영속성 모델을 매핑하는 것이 좋다.
Last updated