Back End/리팩토링 보고서

[리팩토링 보고서] API와 Repository 의존성 제거하기 (DTO-Repository 의존성 제거)

DevPing9_ 2022. 3. 4. 17:06
리팩토링 진행마다 계속 업데이트 됩니다.

 

* 버전 표기는 프로젝트 실제 버전이 아닌 의존성의 변화과정을 담기 위해 편의상 표기하였습니다.

* v1.0 은 배포된 버전 입니다. (PocketMark)

 

API 변경 시 DTO 만 수정해도 되도록 리팩토링 완료했습니다.

API -> DTO -> Repository 에서 API -> DTO 로의 리팩토링 여행기입니다.

 

> v1.0 바로가기

v1.0 의 장점

1. DTO->Repository 의존성 이 제거되어 API 스펙변경에도 끄떡없다. (코드 재사용성 매우 우수)

2. Spring Data JPA가 제공하는
Query Method 를 마음껏 편리하게 사용할 수 있어 신속한 쿼리작성이 가능하다.

3. Projection 이기 때문에 성능적으로도 우수 하다.

4. Class-Based 는 개발자가 마음만 먹으면 내부에 비지니스 로직을 넣을 수 있지만 Interface-Based는 넣을 수 없게 강제하기 때문에 협업시 코드안정성(불변성) 에도 큰 기여를 할 수 있다.

 

 

* API 스펙변경으로 인해 엔티티에 새로운필드를 추가해야하는 상황은 설명하고자 하는 부분과 관련이 없음.

 


PocketMark v0.1

API 스펙변경으로 인해 엔티티에 새로운필드를 추가해야하는 상황은 제외한다.

 

특징

엔티티 객체에서 Dto로 변환이 가능했었음 (ex_Entity.toDto()) (v0.2에서 삭제)

 

 

Summary. 개판 5분전

 

Spring Data JPA Repository

// Query Method (반환형은 User 이지만 Entity.toDto()가 있으므로 수정할 필요가 없음)
List<User> findByName(String name);

// Native Query
@Query(value = "SELECT u.name, u.email FROM user u",
       nativeQuery=true)
List<UserDto> findUserDto();

 

문제점 

1. Entity-DTO 양방향 의존성

2. DB의 특수한 기능을 사용하는 것도 아닌데 쓸모없는 NativeQuery

 

API 스펙변경 시

Native Query

  • SQL 문자열 수정필요

 

PocketMark v0.2

API 스펙변경으로 인해 엔티티에 새로운필드를 추가해야하는 상황은 제외한다.

 

특징 

1. ClassBased-DTO-Proejction 적용으로 Entity-DTO 양방향 의존성 삭제

2. 단순조회에서 필요없어진 NativeQuery 

 

Summary. 엔티티(도메인) 변경 없음

 

 

Spring Data JPA Repository & QueryDSL

// Class-Based Projection
List<UserDto> findAllUserDto(){
    em.createQeury("select new xx.xx.xx.ClassBasedUserDTO(u.name, u.email) "
                   + "from User u", User.class)
      .getResultList();
}

//Query-DSL
public List<UserDto> findAllUserDto(){
    return queryFactory
        .select(new QUserDTO(qUser.name, qUser.email))
        .from(qUser)
        .fetch()
        .stream().......collect(Collectors.toList());     
}

 

문제점 

DTO-Repository 의존성으로 인한 API-Repository 의존성 문제

 

API 스펙변경 시

JPQL & QueryDSL

  • 수정필요 (ex_ x.name-> x.userName)

 

PocketMark v1.0

API 스펙변경으로 인해 엔티티에 새로운필드를 추가해야하는 상황은 제외한다.

 

Summary. DTO만 수정하면 끝

 

 

 

Spring Data JPA Repository

// Interface-Based DTO Projection
List<UserDtoNameAndItemsOnly> findByNameIn(Collection<String> nameList);

DTO Side

class UserDto{
    public interface UserDtoNameOnly{
        String getName();
    }
    public interface UserDtoNameAndItemsOnly{
        String getName();
        List<Item> getItems();
    }
}

 

 

장점

1. DTO->Repository 의존성 이 제거되어 API 스펙변경에도 끄떡없다. (코드 재사용성 매우 우수)


2. Spring Data JPA가 제공하는 Query Method 를 마음껏 편리하게 사용할 수 있다.


3. Projection 이기 때문에 성능적으로도 우수하다.


4. Class-Based 는 개발자가 마음만 먹으면 내부에 비지니스 로직을 넣을 수 있지만 Interface-Based는 넣을 수 없게 강제하기 때문에 협업시 코드안정성(불변성) 에도 큰 기여를 할 수 있다.

 

 

 

728x90