회사 프로젝트 마이그레이션 중간 기록 -끄적끄적

이재훈·2024년 3월 7일
0

삽질모음집

목록 보기
8/8

현재 회사에서는 기술 스택 변경을 위해 힘든 나날들을 보내고 있습니다.
10년이 넘는 기간동안 많은 사람들 손을 거쳐 있던 프로젝트는 생각보다 많이 복잡하였고,
쓸모없는 코드도 꽤나 존재하였습니다.

하지만 가장 큰 문제는 Spring 과 Ext.js는 굉장히 강한 결합성을 가지고 있습니다.
이제 프론트와 백엔드의 결합을 끊고 RestApi 형태의 백엔드 프로젝트로 변경하려고 한합니다.

기존 기술 스택

  • Java7 or 8
  • Spring 3.XX
  • Ext.js : 아는 사람이 있을까..
  • Elastic-Search
  • ibatis
  • Mysql

변경 기술 스택

  • Java8
  • Spring boot : 2.XX
  • Elastic-Search
  • mybatis
  • Mysql

Spring 3점대 프로젝트를 Spring boot 2점대로 옮기는 작업은 생각만큼 쉽지 않습니다..

마이그레이션 순서는 다음과 같습니다.

  1. Spring boot 프로젝트 생성
  2. 프로젝트 구조 잡기
  3. 디펜던시 마이그레이션
  4. 소스 이관 + 휴먼 테스트 + 문서화 ### 현재 단계
  5. 리펙토링 + 테스트코드 작성
  6. CI/CD 구축

이번 포스팅에서는 DTO 리펙토링에 대해 다루도록 하겠습니다.

1,2,3 작업을 마친 후 프로젝트 구조는 아래와 같습니다. (백엔드)

기존 코드에서 마이그레이션을 할 때 먼저 서비스 코드는 변경하지 않기로 결정하였습니다. 기존 서비스 코드에서는 MAP을
사용하고 있었기 때문에 자유로운 포맷으로 데이터를 주고 받을 수 있었으나 마이그레이션 과정에서는 굉장히 큰 리스크로 다가왔습니다.

RequestDTO와 ResponseDTO를 분리하여 코드를 작성하기로 하였고 그 과정에서 사용했던 코드를 생각나는대로 작성해보려고 합니다.

DTO 에서 Map으로 바꾸는 코드와 Map에서 DTO로 바꾸는 코드는 모두 DTO 클래스 안에 static 함수로 작성하였습니다.

코드의 재사용성을 높히기 위해 ResponseService 클래스를 만들어 동일한 포팻으로 리턴할 수 있게 하였습니다. 각기 다른 ResponseDTO 내부에 있는 toModel 메서드의 예시입니다.

public class PolicyResponseDto {
    private String name;
    private String content;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

	// 컨버팅
    public static PolicyResponseDto toModel(Map<String, String> map) {
        PolicyResponseDto policyResponseDto = new PolicyResponseDto();
        policyResponseDto.setName(map.get("name"));
        policyResponseDto.setContent(map.get("content"));
        return policyResponseDto;
    }
}

여기서 제가 고민한 부분은 하나의 함수를 거쳐서 map을 각각의 클래스의 toModel을 호출하여 컨버팅 되어 리턴되는 함수를 만드는 것이였습니다.

@FunctionalInterface
public interface DataConverter<T> {
    T toModel(Map map);
}

인터페이스를 하나 만든 후 ResponseDTO에 인터페이스를 구현시켰습니다.

public class PolicyResponseDto implements DataConverter<PolicyResponseDto>{
    private String name;
    private String content;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public PolicyResponseDto toModel(Map map) {
        PolicyResponseDto policyResponseDto = new PolicyResponseDto();
        policyResponseDto.setName((String) map.get("name"));
        policyResponseDto.setContent((String) map.get("content"));
        return policyResponseDto;
    }
}

ResponseService 클래스에는 DataConverter 클래스를 구현한 클래스의 객체를 생성시킨 후 그 안에 toModel 함수를 호출 시킵니다.
그리고 그것을 리스트에 담고 페이징 정보를 담는 역할을 합니다.

public class ResponseService {
    
    public <T extends DataConverter<T>> PagingListResponse<T> getPagingListResult(List<Map> list, Class<T> dtoClass) {
        PagingListResponse<T> result = new PagingListResponse<>();
        
        result.setList(
                list.stream().map(item -> mapToDto((Map<String, Object>) item, dtoClass))
                        .collect(Collectors.toList())
        );
        // 생략
        return result;
    }
    
    
    private static final<T extends DataConverter<T>> T mapToDto(Map map, Class<T> dtoClass) {
        try {
            return dtoClass.getDeclaredConstructor().newInstance().toModel(map);
        } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
            e.printStackTrace();
            throw new IllegalStateException("Failed to map to DTO", e);
        }
    }
}

이제 서비스에서 컨트롤러로 데이터를 돌려줄 때 ResponseService에 컨퍼팅 함수에 넣어 리턴시켜줍니다.


public PagingListResponse getPolicyList(Map map) {
	// 생략
    return responseService.getPagingListResult(list, PolicyResponseDto.class);
}

이제 해당 함수를 통해 컨트롤러로 보내주면 알맞은 DTO로 변경되어 컨트롤러로 넘어가게 됩니다.
더 좋은 방법이 존재할 것 같습니다. 최근에 자바 공부를 또 열심히 하고 있는데 제네릭을 활용하여 하나의 함수로
컨버팅을 할 수 있게 만든 것 같아 뿌듯합니다. :) 더 공부하여 나중에 더 좋은 방법을 찾을 수 있도록 하겠습니다 :)

profile
부족함을 인정하고 노력하자

0개의 댓글