스프링 프로젝트를 진행하다보니 DTO 객체를 사용하는 계층이 정확히 정의되지 않았다 는 문제점을 발견하고
어느 계층까지 DTO를 전달하는것이 맞을까? (어느 계층에 DTO를 엔티티로 변환하는 로직이 존재해야하는가)
-> 이 로직을 컨트롤러, 서비스, 리포지토리 어느계층에 두어야 하는가? 를 고민하게 되었다.
PROBLEM. DTO 와 엔티티(VO)간의 변환 로직을 어느 계층에 두는것이 적절할까?
별 생각없이 컨트롤러에서 DTO를 엔티티로 변환하여 서비스로 넘기는 방식으로 구현하고보니 지나치게 많은 로직이 컨트롤러에 포함되어있음을 알게되었다. 사용자 인터페이스의 역할을 하는 컨트롤러에 서비스에 있어야할 로직들이 포함되는 문제가 발생한다.
but DTO를 서비스단으로 넘긴다면?
우선 서비스는 리포지토리를 DI(dependency injection)받아 사용하게된다. 영속성 계층과 엔티티를 주고받는 로직들이 대부분을 이루는것은 물론 하나의 서비스와 하나의 리포지토리가 대응되는 경우가 많다. 그런데 여기서 DTO라는 모호한 데이터(DTO가 어떤 데이터를 가지고있는지 상황에 따라 다를 수 있다) 객체를 받아서 사용한다는 점에서 해당 서비스의 역할이 불분명해지는것은 물론 다른 컨트롤러나 서비스에서 해당 서비스를 신뢰할 수 없는 경우가 생긴다.
solution 1
엔티티의 변환작업을 다루는 별도의 유틸을 만들어 컨트롤러에서의 로직을 최소화한다.
서비스와 리포지토리 계층에선 DTO는 전혀 다루지 않고 엔티티만 다루며 모든 변환과정은 컨트롤러와 엔티티 변환 유틸에서 이루어진다.
solution 2
서비스 클래스에서 오버로딩을 사용하여 DTO를 파라미터로 받는 메소드와 엔티티를 파라미터로 받는 메소드를 각각 구현한다.
아직 서비스단에서 DTO를 다루기 때문에 서비스 메소드 로직의 불명확성이 존재하지만, 엔티티를 파라미터로 받는 차선택을 둠으로써 특이 조건에서의 객체 변환은 해당 컨트롤러에서 직접 엔티티로 변환하여 사용할 수 있게된다.
+ solution 1에서의 유틸을 따로 분리하진 않고 서비스 클래스의 private 메소드로 정의하여 사용하면 서비스 클래스 내부의 코드 복잡도도 감소할것이다.
+ 오버로딩 하지않고 엔티티를 파라미터로 받는 update 메소드를 만드는 것도 괜찮다.
결론
난 프로젝트에서 solution 2를 선택했다. solution 1과 같은 경우 아무래도 변환 유틸을 따로 둔다 하더라도, 복잡한 구조의 객체같은경우 변환과정이 상당히 복잡해지는것은 물론, 변환유틸 자체에서 서비스를 주입받는 기이한 구조 가 연출되어 초반까지만 이용하다가 이후 리팩토링하여 solution 2로 바꾸게 되었다.
구글링하며 찾아보니 이 문제에 대해서 딱히 답은 없는 것 같다. 특정 구조에 얽메일게 아니라 어떤 구조가 본인이 진행하는 프로젝트에 적합할지 고민을 하고 결정하는것이 중요할 것 같다.
끝
'컴퓨터과학 > Spring' 카테고리의 다른 글
Firebase Cloud Message(FCM) 스프링 부트 프로젝트에 적용하기 (0) | 2022.06.20 |
---|---|
[Spring]Jenkins로 ec2 서버에 원격 배포하기 (publish over ssh 없이) (0) | 2022.01.19 |
[Spring] 예외 발생은 어디서 해야할까? (0) | 2021.08.27 |
[Spring] 페이지 리로드(새로고침)시 발생하는 데이터 중복전송 현상 방지 (0) | 2021.04.15 |
[Spring] 스프링(Spring) 이란? (0) | 2020.12.29 |