Repository 패턴 자체는 적용이 어렵지 않다. 하지만 많은 사람들이 놓치고 있는 부분이 있는데, 위 예시에서도 찾을 수 있다.
바로 Repository 가 DataSource 의 데이터를 그대로 전달해준다는 점이다.
위 예시를 다시한번 살펴보자. UserRepository 는 UserApi 로 부터 전달받은 User 를 별다른 처리없이 그대로 리턴하고 이를 presentation layer 에서 사용하고 있다.
이것은 다음과 같은 문제점을 가지고 있다.
back 단의 구현 이슈가 presentation layer 에 영향을 끼칠 수 있다.
User 는 서버 (혹은 로컬 DB) 의 데이터베이스 테이블을 표현하는 역할을 수행하는 객체일 뿐이다.
Data 스펙이 바뀌면 presentation layer 전반에 영향 끼치게 된다.
필드 삭제, 필드 이름 변경 등 서버가 데이터 구조를 변경하게 되면 이를 바로 참조하고 있는 다른 layer 에서도 필연적으로 변경이 발생하게 된다.
예를 들어 클라쪽에서는 User 정보를 표기해야 하는데 서버에서 각기 다른 데이터의 요청을 N 번 거쳐야 한다고 생각해보자. 그럼 N 개의 데이터에 대한 변경 사항은 모두 온전히 클라에 영향을 줄 것이다. 더 중요한 점은 이렇게 복잡한 데이터 모델을 혼재하여 사용하게 되면 다른 개발자가 컨텍스트를 이해하기 매우 어려워지기 시작한다.
서버 (혹은 로컬 DB) 의 데이터베이스 테이블을 표현하는 역할을 수행하는 객체일 뿐이다.
같은 도메인에 대하여 클라와 서버의 용어가 통일이 되는 것이 가장 이상적이겠지만 현실세계에서는 서로 다른 용어를 사용하는 경우가 허다하다. 그럴 경우 보통은 클라이언트 코드 베이스에서 라도 서로 통일이 이루어져야 한다. 그런데 서버 데이터 구조를 그대로 가져와 사용할 경우, 팀내 도메인 용어와 실제 코드 베이스의 용어가 달라지게 되고 커뮤니케이션 리소스가 급증하게 되는 상황이 발생한다.
또한 도메인의 비즈니스 로직 처리에 필요한 메소드를 생성할 시점이 왔을 때, (서버 테이블을 반영한) 객체에 추가하게 되면 해당 객체는 테이블도 표현하고, 도메인 로직도 처리하는 God object 가 될 확률이 높다.
Repository 패턴을 사용하는 목적은 data layer 와의 coupling 을 느슨하게 하는 것인데, 다시 강한 결합이 되어버린 꼴이 되었다.
Mapper 를 활용하자
이러한 문제점을 해결하기 위하여 Mapper 를 사용할 수 있다. Mapper 란 말 그대로 테이블 객체 ↔ 도메인 모델 객체간의 mapping 을 시켜주는 유틸성 클래스를 의미한다. repository 내에서 mapper 를 활용하여 테이블 객체가 아닌 도메인 모델로 전달을 해주면 presentation layer 는 data layer 로 부터 진정한 자유를 찾을 수 있게 된다.
Repository