inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Readable Code: 읽기 좋은 코드를 작성하는 사고법

DTO 생성과 관련해서 궁금한 게 있습니다!

149

yg04076

작성한 질문수 5

0

@Transactional
    public ShelterResponse.FindShelterListDTO findActiveShelterList() {
        List<Shelter> shelters = shelterRepository.findAllWithAnimalAndLatitude();

        List<ShelterResponse.ShelterDTO> shelterDTOS = shelters.stream()
                .map(shelter -> new ShelterResponse.ShelterDTO(
                        shelter.getId(),
                        shelter.getName(),
                        shelter.getLatitude(),
                        shelter.getLongitude(),
                        shelter.getCareAddr(),
                        shelter.getCareTel()))
                .collect(Collectors.toList());

        return new ShelterResponse.FindShelterListDTO(shelterDTOS);
    }

    @Transactional(readOnly = true)
    public ShelterResponse.FindShelterInfoByIdDTO findShelterInfoById(Long shelterId) {
        Shelter shelter = shelterRepository.findById(shelterId).orElseThrow(
                () -> new CustomException(ExceptionCode.SHELTER_NOT_FOUND)
        );

        return new ShelterResponse.FindShelterInfoByIdDTO(
                shelter.getId(),
                shelter.getName(),
                shelter.getLatitude(),
                shelter.getLongitude(),
                shelter.getCareAddr(),
                shelter.getCareTel(),
                shelter.getAnimalCnt()
        );
    }

 

위 코드는 유기 동물 보호소 서비스에서 보호소 목록을 가져오고, 보호소의 상세 정보를 가져오는 코드입니다.

서비스 레이어에서 컨트룰러 레이어로 응답을 내보낼 때 DTO로 변환해서 보내는데, 데이터양이 많은 엔티티의 경우 위 코드처럼 DTO 빌드 코드가 길어지더라구요..

 

그래서, 정보량이 많은 엔티티에 관한 데이터를 DTO로 리턴할 때는 아래와 같이 서비스 레이어에 private 메서드로 추출해서 사용합니다.

private ShelterResponse.AnimalDTO createAnimalDTO(Animal animal, List<Long> userLikedAnimalIds) {
        return new ShelterResponse.AnimalDTO(
                animal.getId(),
                animal.getName(),
                animal.getAge(),
                animal.getGender(),
                animal.getSpecialMark(),
                animal.getKind(),
                animal.getWeight(),
                animal.getNeuter(),
                animal.getProcessState(),
                animal.getRegion(),
                animal.getInquiryNum(),
                getCachedLikeNum(animal.getId()),
                userLikedAnimalIds.contains(animal.getId()),
                animal.getProfileURL());
    }

 

여기서 고민이 시작 됐는데, 응답으로 보낼 DTO를 빌드하는 로직을 서비스 레이어에 private 메서드로 추출하는 게 서비스 레이어의 역할 상 괜찮을지 의문이 들더라구요.

현업에서는 정보량이 많은 DTO 코드를 빌드하는 부분을 메서드로 따로 추출하는지, 추출한다면 어떻게 처리하는지 궁금합니다!

이거를 메서드로 추출하지 않을까도 생각해봤는데, 그러면 메서드의 코드 길이가 너무 길어져서 가독성을 해치는 느낌도 있더라구요.. 또 DTO만 처리하는 클래스를 만들어볼까도 생각했는데 이게 맞나 싶기도 하구요

 

 

객체지향 리팩토링 클린코드-기획전

답변 2

1

박우빈

안녕하세요, yg04076 님!

DTO 내부에 변환 로직을 두면 서비스는 깔끔해지지 않을까요?
AnimalDTO.of(animal, ...) 과 같이 각 DTO에 정적 팩토리 메서드를 만들고, 필요한 정보를 파라미터로 받아 내부에서 변환하도록 하면 될 것 같아요.

감사합니다. 🙂

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다. yg04076님께서 질문해 주신 내용은 DTO(Data Transfer Object) 생성 및 관리에 관한 사항으로 보입니다. 현실적인 개발 상황에서는 종종 데이터의 복잡성과 양이 커지면서 DTO 생성 코드가 복잡해질 수 있습니다. 이런 경우 다음과 같이 다양한 접근 방식을 고려해볼 수 있습니다.

  1. Private 메서드로 추출: 현재와 같은 방식으로, 서비스 레이어 내에서 private 메서드로 DTO를 생성하는 코드를 분리할 수 있습니다. 이를 통해 코드의 중복성을 줄이고 가독성을 높일 수는 있지만, 서비스 레이어의 책임이 과중되지 않도록 주의해야 합니다.

  2. DTO 전용 변환 유틸리티 클래스 생성: DTO를 변환하는 로직을 별도의 유틸리티 클래스나 변환기 클래스로 분리하여 사용할 수도 있습니다. 이 방법은 서비스 레이어를 깔끔하게 유지하면서 변환 로직을 재사용할 수 있도록 합니다. 예를 들어 ShelterDTOConverter 같은 클래스를 만들고, 여기서 변환 로직을 책임지게 할 수 있습니다.

  3. 모델 매퍼 활용: ModelMapper와 같은 라이브러리를 활용하는 것도 좋은 방법입니다. 이는 객체 간의 변환을 자동화하여 수작업 코드를 줄이고 매핑을 보다 선언적으로 처리할 수 있도록 도와줍니다.

  4. Builder 패턴 사용: 데이터가 많고 생성이 복잡한 경우 빌더 패턴을 활용하여 DTO 생성 과정을 직관적으로 만들 수 있습니다. 이렇게 하면 코드의 가독성을 높일 수 있습니다.

관련된 보다 자세한 논의와 유사한 사례를 controller, service용 dto를 분리시키는 것에 대한 질문에서 찾아 참고하실 수 있습니다.

이와 같은 다양한 방법을 검토하시면서 프로젝트의 성격과 팀의 컨벤션에 맞추어 적합한 방법을 선택하시면 좋겠습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

[강의 질문] 메서드 선언부

0

90

1

[강의 질문] 메서드와 추상화

0

61

2

DIP 개념에 대한 질문입니다.

0

64

1

만약 보드를 이용한 게임의 종류가 더 다양해진다면 어떻게 될 수 있을지에 대한 고민

0

86

2

DIP 설명 후반부에 IOC에 대한 질문 드립니다.

0

79

2

안녕하세요 ! 혹시 자바가 아닌 다른 객체지향 언어를 알고있어도 강의를 들어도 괜찮을까요 ?!

0

71

1

안녕하세요 메서드명 때문에 고민이 있어서 질문드립니다.

1

64

2

자바 record 사용에 대해서 질문 드립니다!

0

128

2

강의 내용 정리 및 자료 제작 툴 문의 드립니다.

0

136

2

사용할 변수 가깝게 선언하기 질문

0

93

1

오버 엔지니어링

0

150

2

학습용 java/spring 오픈소스 추천

1

368

2

중복된 메서드 줄이는 방법

0

184

2

MarketPlace에서 Sonarlint 검색이 안됩니다.

0

417

3

isLandMineCell() 메서드 질문

0

209

1

Cell[][]BOARD 매개변수받기

0

153

2

ConsoleInputHandler에서 왜 final붙여야 하는지

0

193

1

정적 생성자 메서드 of, from

0

264

2

Getter관해서

0

148

3

이름 바꾸기

0

129

2

stack 대신 queue 를 사용해 bfs 로 변경해도 되나요??

0

164

2

현업에서 ISP를 도입하려는데 인터페이스 설계에 있어서 의문이 있습니다.

0

208

2

null을 가질 수 있는 값을 인자로 넘겨야 하는 경우

0

252

3

리팩토링을 하고 난 뒤 다시보면 오히려 더 복잡해 보이는것 같은 느낌입니다..

0

255

2