코딩과 결혼합니다

[Game_Crew] 리팩토링 : Post 상세조회 리팩토링 본문

코딩과 매일매일♥/Game_Crew

[Game_Crew] 리팩토링 : Post 상세조회 리팩토링

코딩러버 2023. 11. 14. 17:00
728x90

11월 13일(어제)은 우리 팀원들과 약속했던 유저 테스트 날이었으나, 상황적인 문제로 이틀 뒤로 연기되었다. 개인적으로는 MVP 기능 구현은 모두 마친 상태이지만, 내부 로직이 아직 완벽하다고 판단하지 못해 코드의 가독성, 유지보수성, 그리고 성능을 높이기 위해 리팩토링을 결정하였다.

 

이 코드는 다른 백엔드 팀원이 작성한 것으로, 서로 이해가 어려운 부분들이 있어 수정이 필요하다는 결론을 내렸다. 그리하여 나의 방식에 따라 코드를 수정하고 코드 리뷰까지 진행하였다.


📌Controller

리팩토링 전

    @GetMapping("/{postId}")
    public PostResponseDto getPost(@PathVariable("postId") Long postId,
                                   @AuthenticationPrincipal UserDetailsImpl userDetails) {
        if(Objects.isNull(userDetails)){
            postService.updateView(postId);
            return postService.getPost(postId,null);
        }
        User user = userDetails.getUser();
        postService.updateView(postId);
        return postService.getPost(postId,user);
    }
리팩토링

@GetMapping("/{postId}")
public PostResponseDto getPost(@PathVariable("postId") Long postId,
                               @AuthenticationPrincipal UserDetailsImpl userDetails) {
    if(Objects.isNull(userDetails)){
        return postService.getPost(postId,null);
    }
    User user = userDetails.getUser();
    return postService.getPost(postId,user);
}
  • 게시물 상세 조회를 할 때마다 count 하여 그 값을 반환해 주는 servie를 따로 만들고 있었는데 내부적으로 처리하도록 하여 없앴다.

📌Service

리팩토링 전

@Transactional
public void updateView(Long postId) {
    Post post = postRepository.findByPostId(postId);
    post.update();
}

public PostResponseDto getPost(Long postId, User user) {
    //해당 메모가 DB에 존재하는지 확인
    Post post = postRepository.findById(postId).orElseThrow(()->
            new IllegalArgumentException("선택한 글은 존재하지 않습니다."));
    PostResponseDto postResponseDto;
    if(Objects.isNull(user)){
        postResponseDto = new PostResponseDto(post);
    } else if (post.getUser().getEmail().equals(user.getEmail())) {
        postResponseDto = new PostResponseDto(post);
        postResponseDto.checkOwner();
    } else {
        postResponseDto = new PostResponseDto(post);
    }
    return postResponseDto;
}
리팩토링

public PostResponseDto getPost(Long postId, User user) {
    Post post = postRepository.findById(postId)
            .orElseThrow(() -> new CustomException(ErrorMessage.NON_EXISTENT_POST, HttpStatus.BAD_REQUEST));

    post.increaseViewCount();
    postRepository.save(post);

    boolean isPostUser = false;
    if (user != null) {
        // Post의 소유자가 현재 User인지 확인합니다.
        isPostUser = user.getUserId().equals(post.getUser().getUserId());
    }
    return new PostResponseDto(post, isPostUser);
}
  • 예외 처리 시 ErrorMessage 클래스의 메시지를 사용하여 유지보수성을 높이고, 적절한 상태코드 값도 함께 반환한다.
  • updateView 메서드를 따로 구현하지 않고 내부에 포함시키며 가독성을 높였다.
  • 예외 처리도 CustomException을 사용하여 메시지와 상태코드를 웹브라우저에도 나타나게 하였다.
  • user가 null인지 아닌지에 따른 처리를 명확하게 하고 이로 isPostUser의 값을 결정하는 로직이 간결해졌다.
  • user가 null인 경우에 대한 처리를 먼저 수행함으로 불필요한 연산을 줄이고 NullPointerException을 방지하는 등 예외 상황을 미리 대비하는 안정적인 코드를 작성하였다.

📌DTO

리팩토링 전

@Getter
public class PostResponseDto {

    private Long postId;
    ...

    private boolean isPostUser =false;
//    private Boolean isASC;

    public PostResponseDto(Post post){
        this.postId = post.getPostId();
        ...
    }
    public void checkOwner(){
        isPostUser = true;
    }
}

 

리팩토링

@Getter
public class PostResponseDto {
    private Long postId;
    private String category;
    private String title;
    private String content;
    private Long totalNumber; // 전체 참가자 수

    private Long userId;
    private String nickname;
    private String userImg;
    private boolean isPostUser;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createdAt;



    public PostResponseDto(Post post, boolean isPostUser){
        this.postId = post.getPostId();
        this.category = post.getCategory();
        this.title = post.getTitle();
        this.content = post.getContent();
        this.totalNumber = post.getTotalNumber();
        this.createdAt = post.getCreatedAt();

        this.userId = post.getUser().getUserId();
        this.nickname = post.getUser().getNickname();
        this.userImg = post.getUser().getUserImg();

        this.isPostUser = isPostUser;
    }
}

 

  • 로직 변경으로 checkOwner 메서드를 없애주었다. 이곳 말고도 다른 entity나  Dto에 게시글의 조회수를 올려주는 로직과 관련된 변수나 메서드가 정리되지 않고 복잡하게 있었는데 모두 없애고 간단하게 구현하여 가독성을 높였다.
  • 약속된 API에 맞게 변수들을 추가/삭제해 주었다. 또한 다른 클래스와의 통일성을 위해 변수명도 변경해 주었다.
    [ex) profileImg -> userImg]

결과
1) 비회원이거나 게시글 작성자가 아닌 사람이 상세조회 했을 때

 

2) 본인이 쓴 게시물을 상세조회 했을 때