Mapper 사용기
프로젝트를 수행하는데 있어 DTO와 Entity간의 변환을 Mapper를 적용했다.
확실히 코드의 길이는 줄어들었고 중복 부분도 많이 처리했다.
그렇다면 Mapper란 무엇이며 실제 적용 방법과 확장에 대해 기술해보겠다.
문제 상황
‘FrameCheckMate’에 있어 하나의 비즈니스 로직을 예시로 얘기를 풀어보고자 한다.
- 위 로직은 사용자의 email로 메일을 전송하고 메일 정보를 DB에 저장하는 로직이다.
- 로직
- customMailSender를 통해 Mail 전송
- Mail(Notification) Enitity를 JPA를 통해 Repository에 저장
- NotificationSaveResponse를 클라이언트에게 반환
위 로직에 있어 코드에서 가장 많은 부분을 차지하는 것은 DTO와 Entity간의 변환과정이다.
예시로 하나의 로직만을 가져왔지만 실제 서비스에 있어 변환 과정은 중복이 많은 부분이다.
변환 과정의 중복을 줄여 보는 것이 좀더 객체 지향에 가까운 코드를 작성하는 것이라 생각한다.
Service 로직에서 구현한다면 ?
- 실제로 프로젝트를 진행하면서 팀원 중 한명은 Service에서 변환 과정을 메서드로 구현하는 것에 대한 의견을 제시했다.
- 확실히 중복 코드는 줄어들 것이지만 과연 올바른 방법일까? (얘기를 나눠보고자 한다)
역할과 책임
객체 지향 프로그래밍에 관한 도서를 읽다 보면 많이 나오는 말이 역할과 책임이다. ‘오브젝트’라는 근본 도서에서 정말 깊이 있게 다루는 내용이다. 해당 내용은 도서에서 너무 잘 나와 있어 별도로 첨부하지는 않겠다.
단일 책임 원칙 (Single Responsibility Principle)
- ‘하나의 클래스는 하나의 책임을 가져야 한다.’ 라는 객체 지향 설계에 있어 중요한 원칙이다. Service 로직 내부에서 변환을 구현하는 것은 단일 책임 원칙을 위배한다.
- 서비스 로직은 실제 비즈니스 로직을 담당한다. 변환 과정은 실제 비즈니스 로직과는 별개의 관심사이다.
Mapper
mapper는 서로 다른 데이터 구조나 객체 간의 변환과 관련된 개념
매퍼는 한 타입의 객체를 다른 타입의 객체로 변환하는 역할을 하는 함수나 클래스를 의미한다. 이 과정을 일반적으로 mapping이라고 부른다.
참고 : https://chatgpt.com/c/67490b51-6700-8002-90d4-b2be17474101
Mapper 적용
- NotificationMapper
- NotificationMapper를 적용한 Service
다른 방법은 없을까?
별도의 클래스를 정의하여 사용하는 것을 좋아하지만 해당 방법만 존재하는 것은 아니다.
Mapping 과정을 자동으로 제공해주는 MapStruct에 대해 간단히 말하고 글을 마무리하겠다.
MapStruct
Java Bean 유형 간의 매핑 구현 단순(자동)화하는 코드 생성기
참고 : https://www.baeldung.com/mapstruct
특징
- 컴파일 시점에 코드 생성
- 반복적 구현을 줄여준다.
- Annotation processor를 이용하여 객체 간 매핑 자동화
- MapStruct는 Lombok의 Getter,Setter,Builder를 이용한다.
- 꺼내오는 객체 → Getter 필요
- 저장하는 객체 → Builder OR 모든 필드를 포함하는 생성자
MapStruct 동작 우선순위
- Builder가 있으면 Builder를 사용합니다.
- Builder가 없으면 Setter를 사용하여 객체를 생성하고 값을 설정합니다.
- 필드에 직접 접근하도록 설정할 수도 있습니다(기본적으로 비활성화).