본문 바로가기

회고

JPA 게시판 만들기 프로젝트 회고

데브코스 7주차 과제로 JPA를 사용한 간단한 CRUD 게시판을 만들었다.

 

🎃 목표

  • REST API DOCS를 사용하여 문서화하기 ✅
  • 작은 단위로 테스트 코드 작성하기 ✅
  • 페어프로그래밍 하기 ✅

 

🔮 프로젝트를 진행하며 했던 고민

JPA의 엔티티 클래스의 필드는 Primitive Type? Wrapper Class?

  • PK에서는 WrapperClass를 사용한다.
    • PK가 아직 할당되지 않았음을 명시적으로 표현할 수 있다.
    • Hibernate 공식 문서에서 WrapperClass를 사용하는 것을 권장하고 있다.
  • Null의 허용 유무에 따라 결정될 수 있다.
    • ex) Item의 재고 수량 필드 → Null이 필요하지 않고 값을 입력하지 않으면 0으로 지정해도 문제가 없기 때문에 primitive로 할 수 있다.
  • Null이 주는 의미에 따라 결정될 수 있다.
    • primitive 타입으로 지정한다면 수(Number)가 주는 의미밖에 전달할 수 없다.
    • WrapperClass로 지정한다면 수가 주는 의미 + Null이 주는 의미(값이 할당되지 않음)를 전달할 수 있다.
  • 일관성을 주고자 모든 필드를 WrapperClass로 설정할 수 있다.

💡 → 나는 WrapperClass 타입으로 통일하기로 했다.

예를 들어, User 엔티티의 age를 int라는 primitive 타입으로 했다가 만약 User의 age가 @Nullable 하도록 변경된다면 int → Integer로 변경해줘야 할 것이다. WrapperClass 타입으로 지정한다면 이런 변경으로 인한 파급효과를 조금이라도 더 줄일 수 있을 것이다.

 

static으로 사용할 것인지 bean으로 등록할 것인지

프로젝트에서 DTO → Entity, Entity → DTO로 변환시켜주는 로직을 담고있는 Converter클래스를 만들었다.

public class PostConverter {
    public static PostDTO.FindResponse postToFindResponse(Post post) {
        return PostDTO.FindResponse.builder()
                .id(post.getId())
                .title(post.getTitle())
                .content(post.getContent())
                .userId(post.getUser().getId())
                .userName(post.getUser().getName())
                .build();
    }

    public static Post saveRequestToPost(PostDTO.SaveRequest postSaveRequest, User user) {
        return Post.builder()
                .title(postSaveRequest.getTitle())
                .content(postSaveRequest.getContent())
                .user(user)
                .build();
    }
}

이 클래스를 스프링 빈으로 등록하여 주입받아 사용할지, 아니면 static 메소드로 사용할지 고민을 하였다.

 

검색해본 결과 다음과 같은 결론을 내렸다.

  • 외부 자원에 의존하여 외부 자원이 변경된다면 실행 결과에 영향을 끼치는 객체를 스프링 빈으로 등록한다. → 의존성 주입을 통해 의존성을 스프링 컨테이너에서 관리하도록 하기 위해
  • 외부 자원에 의존하지 않거나, 의존하더라도 의존하는 외부 자원에 의해 함수의 실행 결과가 바뀌지 않으면서 공용으로 사용되는 객체를 static으로 사용한다.

 

🧨 궁금한 점 & 알아볼 점

프로젝트를 진행하며 궁금했던 점이 있다.

  • PostDTO에서만 쓰는 User의 정보를 Post 패키지에서 관리하는 것이 좋은지 User 패키지에서 관리하는 것이 좋은지?

 

🎉 배운 것

  • JPA Auditing
  • @RequestBody
  • 페어프로그래밍
  • Record
  • JPA 페이징

 

🧪 느낀점

페어프로그래밍

이번 프로젝트는 이전처럼 단순히 각자 프로젝트를 진행하는 것이 아니라 팀원들끼리 팀을 나눠 페어프로그래밍을 진행하였다. 처음 해보는 작업이라 여러 느낀 점이 많았다.

  • 나는 개발하면서 정말 적은 고민을 했다.
  • 내가 한 고민은 대부분 다른 사람들도 했다. -> 모르겠으면 검색을 통해 고민을 해결해보자.
  • 페어프로그래밍을 통해 내가 아는 지식을 재점검하고 팀원이 가지고 있는 새로운 지식을 알 수 있어서 좋았다.
    • JPA Auditing에 대해 알게되었다. 
  • 팀원들과 많은 대화를 하며 더 친해질 수 있어서 좋았다.
  • 함께 같은 문제에 대해 고민하면서 시야를 넓힐 수 있었다.
  • 많은 대화를 하고 여러 사람의 고민을 함께 생각하다보니 생산성이 떨어졌다.

인터넷 문제와 여러 사람이 함께 코딩을 하다보니 개발 속도가 느려 약간의 답답함은 있었지만 장점이 더 많은 경험이었던 것 같다. 앞으로 팀원들과 자주 페어프로그래밍을 해야겠다고 생각했다. 

 

REST API Docs 사용

처음으로 REST API Docs를 사용해보았다. 테스트를 통과해야만 API 정의서가 작성되는 점이 더 정확한 API 정의서를 작성할 수 있다고 생각하여 좋았다. 하지만 설정하는게 어려웠다.

 

작은 단위로 테스트하기

@SpringBootTest를 사용하여 통합테스트를 하면 전체적인 flow대로 테스트를 할 수 있고 의존성을 주입받아 쉽게 테스트가 가능하지만 테스트코드 실행 시 모든 빈이 컨테이너에 올라가고 테스트 실패 시 디버깅이 힘들다는 단점이 있어서 최대한 유닛테스트로 테스트 코드를 작성하고자 하였다. 이 과정에서 Mock에 대해 학습할 수 있었다. 다만 아직은 테스트 코드를 어느정도까지 세세하게 작성해야 하는지 고민이 된다. 너무 세세하게 코드를 작성하자니 들어가는 시간 대비 효율성이 떨어질 것 같고, 그냥 넘어가자니 찜찜한.. ㅠㅠ 더 깊이 생각해봐야겠다.

 

 

 

프로젝트 GitRepository

https://github.com/rhdtn311/springboot-board-jpa

 

 

피드백

멘토님, 팀원에게 받은 피드백을 정리했다.

  • URL에 공통적으로 “/posts”가 포함되어 있다. RequestMapping("/posts")로 라우터 지정해도 좋을 것 같다.
  • setter 없이 changeTitle(), chageContent() 메소드를 따로 둔 것은 setter와 다를 바가 없다. 대부분 title, content는 같이 변경될 것 같으므로 하나의 메소드로 관리하는게 좋을 것 같다.
  • Pageable과 PageRequestDTO 중 어떤 것을 사용하는 것이 좋을까 → 일단 PageRequestDTO
  • Response의 HttpStatus를 담아서 보낼 때 하드코딩보다 HttpStatus 상수를 쓰는 것이 좋다.
  • PageDTO.Response의 startPageNumber를 구하는 계산식에서 항상 10으로 나누도록 했다. page의 값은 바뀔 수도 있기 때문에 유동적으로 관리하도록 코드를 바꿔보자
  • 에러 핸들링을 할 때 RunTimeException을 핸들링 해두는 것이 디버깅 하기 편할 것이다.
  • 엔티티 생성 시에는 HttpStatus를 201로 하는 것이 좋다.
  • update 하는 API의 경우 PUT이나 PATCH를 사용하는게 좋다.
  • DTO를 inner class로 관리했는데, 이는 복잡성을 많이 늘리게 된다.

 

피드백은 대부분 기본적인 것들에 대한 내용이 많았다. 아직 내가 기본적인 것도 제대로 고민하지 못하는 것 같아 아쉬웠다. 다음 프로젝트에는 이런 세세한 부분까지 신경써서 코드를 작성할 수 있도록 노력해야겠다.

 

 

📜 References

JPA Entity Class 에서 Primitive Type 을 써야할까 Wrapper Class 를 사용해야할까

Entity의 field type은 무엇이 적합할까?

 

Entity의 field type은 무엇이 적합할까?

@Entity public class Accommodation { @Id private Long id; private String locationName; private String description; private String imagePath; private int pricePerDay; // primitive type? private int positionX; private int positionY; } 최근 리뷰를 한

hyune-c.tistory.com

언제 static 함수 모음 Class를 만들어야 할까?

 

언제 static 함수 모음 Class를 만들어야 할까?

먼저 내가 말하는 static 함수 모음 class란  Apache Commons Lang StringUtils 처럼 순전히 static 함수들만을 가지고 있고, 객체를 생성하지 않고 사용하는 클래스를 의미한다(Java 이야기이다).이에 대한 정

kwon37xi.egloos.com

JPA Auditing 기능이란?

 

JPA Auditing 기능이란?

JPA Auditing이란? Java에서 ORM 기술인 JPA를 사용하여 도메인을 관계형 데이터베이스 테이블에 매핑할 때 공통적으로 도메인들이 가지고 있는 필드나 컬럼들이 존재합니다. 대표적으로 생성일자, 수

webcoding-start.tistory.com

Page (Spring Data Core 3.0.0 API)

Slice (Spring Data Core 3.0.0 API)