아래의 기능은 제외했습니다.
그런데 요청받은 Service API의 Return Type이 JPA Entity
에 의존적인 클래스였습니다. 결국 DB 접근 기술에 의존적이고 싶지 않아 Service Layer로 접근하자고 하면서 리턴타입은 JPA에 의존적인 Entity? 이거 조삼모사가 아닌가 싶어 의견을 드렸습니다.
그래서 대안으로 필수 정보만 Dto로 담아서 API Spec으로 생성하자라는 말씀을 드렸지만, 다른 우선순위가 많았기 때문에 일단 Entity로 리턴하고 나중에 수정하자라는 답변을 받게 되었습니다. 저도 우선순위가 높은 부분들이 많다라는건 인정하는 부분이었기때문에 일단 진행하게 되었습니다.
일단 Entity만 바로 반환을 하면 되니 개발속도는 정말 빠릅니다. 하지만 문제는 리팩토링 단계에서 발생하게 되었는데요..!
프론트엔드분들과 협업을 진행하는 와중에도 요구사항은 끊임없이 변경되었습니다. 저희 백엔드팀이 미처 캐치하지 못한 점들을 많이 짚어주셔서 정말 도움이 많이되었는데요. 문제는 여기서 발생합니다.
요구사항이 변경되면서 Table을 변경해야하는데.. Entity가 영향을 받고.. 또 이를 제공하는 Service도 영향을 받고... 또 이 API를 사용하는 다른 API도 영향을 받고...
정말 꼬리에 꼬리를 무는 리팩토링의 연속이었습니다. Entity에 필드 하나를 수정하는데에도 10개가 넘어가는 클래스가 영향을 받는 일도 비일비재했죠.
Entity를 통째로 넘기다 보니 불필요한 정보들 역시 많이 넘어가게 되었습니다. 메서드들도 마찬가지고요!
굳이 알지 않아도 되는 정보를 넘기다보니 잘못된 사용이나 수정에 대한 위험성이 존재하게 됩니다.
가령 위의 Comment 처럼 Post의 전체 정보를 넘기게 된다면, 게시글의 정보가 노출되는 위험성이 존재하게 되는 것이죠!
위의 불편한점들을 그대로 안고 갈 수는 없죠! 수정을 해봅시다.
public Post findById(Long id) {
return postRepository.findById(id)
.orElseThrow(PostNotFoundException::new);
}
해당 Service API를 아래와 같이 Dto로 변경합시다.
@Override
public PostDetailResponseDto findById(Long id) {
return PostDetailResponseDto.entityToDto(postRepository.findById(id)
.orElseThrow(PostNotFoundException::new));
}
public PostCommentResponseDTO createComment(CreateCommentRequest req) {
...
return commentRepository.save(
Comment.builder().post(postQueryService.findById(req.getPostId())) // ERROR!
.member(memberService.getMember(req.getMemberId())).content(req.getContent())
.anonymity(req.getAnonymity()).parentComment(parentComment).build())
.toPostCommentResponseDTO();
}
바로 문제가 발생하게 됩니다. 여기서 문제는 Comment.Builder
에 더이상 post를 채워넣을 수 없다는 것이 되겠죠.
public PostCommentResponseDTO createComment(CreateCommentRequest req) {
...
if (!postQueryService.isExist(req.getPostId())) {
throw new PostNotFoundException();
}
return commentRepository.save(
Comment.builder().post(Post.builder().id(req.getPostId()).build()) // id만 존재하는 Post로 변경!
.member(memberService.getMember(req.getMemberId())).content(req.getContent())
.anonymity(req.getAnonymity()).parentComment(parentComment).build())
.toPostCommentResponseDTO();
}