Spring Boot 협업(마무리 및 느낀 점)

제이 용·2025년 12월 1일

팀 프로젝트는 저번 주에 끝났지만 밤샘 작업으로 인해 TIL을 작성하지 못했다. 하지만 그냥 넘기기에는 느낀 것들이 많아 기록하려고 늦게나마 작성해보려고 한다.

협업을 하기 위한 단계

1. 협업 하기 전의 셋팅

  • 컨벤션 정리

  • GitHub 정리

  • 코드 스타일 정리

  • 파일 구조화 통일

  • 네이밍 구조 통일

  • 공통으로 사용할 클래스 구성 정리

  • 머지 계획 구성

  • API명세서 구체화

  • 기간 별 계획 구체화

    • 마감 이틀 전까지 마무리하는 것으로 최대한 계획
  • 동시 개발 계획 구성

2. 협업 간의 셋팅

  • 머지 구간 세분화

  • 코드 리뷰 디테일

    • 컨벤션 확인(띄어쓰기)

    • API명세서 누락부분

    • 네이밍 포인트

    • 리뷰 받는 자는 설명할 수 있어야한다.(중요)

  • 코드 수정 시 명세서 수정(팀원 공유)

  • 제 3자가 봤을 때 이해하기 좋도록 가독성 좋은 코드 작성

이번 프로젝트 때 혼자가 아닌 여러사람의 코드를 통해 협업을 하게 됨으로써 준비하면 좋을 것들을 한 번 프로젝트가 끝나고서도 복기해보면서 적어보았다.


잘했던 점

  • 와이어 프레임을 초기에 잘 설정해 두었다.

    • 필요한 엔티티와 기능들이 무엇인지 명확하게 알 수 있었다.
  • 머지 계획을 잘 구성하였다.

    • dev브랜치를 통해 main에 병합하는 실수나 테스트를 완전히 거쳐간 프로젝트만을 담기 위해 진행하였고, 다행히 실수없이 성공적인 결과물이 나올 수 있었다.
  • 머지와 커밋하는 양이 많았다.

    • 그만큼 머지나 커밋하는 구간이 타이트했기에 실수나 리팩토링할 수 있는 양이 바로바로 잡을 수 있는 양이 었기 때문에 쉽게 진행할 수 있었다.

아쉬웠던 점

  • 마감 시간 전날 밤을 새가면서 까지 완료했다는 점.

    • 잘한거기도하지만 계획을 세분화하지 못했다는 것이기에 아쉬운 점이었다.
  • 코드리뷰를 꼼꼼하게 하지 않았다는 점.

    • 코드리뷰를 하면서 잘했겠거니 싶기만 했지 뜯어보았을 때는 자잘한 컨벤션 실수나, 넣지말아야할 파일이 있다거나, 기본적인 통일성 조차 보지 않아 뭔가 뒤죽박죽 뒤엉킨듯한 코드가 되었다.
    • 여러번 수정할바에 한번에 꼼꼼하게 잘 확인해서 수정 소요를 줄일 수 있는게 좋을 것 같다.
  • API명세서를 제대로 작성하지 않았고 명확한 목적과 결과가 없어 코드를 작성하면서도 추가적인 기능들이 붙는 바람에 머지하는 계획이 점점 미루어졌다.

    • API명세서를 작성하는데 초점을 두고 명세서 대로만 작성하면 끝날 일이었다. 또한, 명확하게 여기까지 만들자. 라는 목적의식이 없어 머지하는데 자꾸 미루어졌다. 계획뿐만이 아닌 결과물을 정해두어야 차질이 없을 것 같다.
  • 코드 스타일과 개성이 너무나도 달랐지만 개인적이니 최대한 수용하려고 하였다.

    • 코드 스타일 스타일일 뿐이고 통일성을 맞추기 위해서는 사용하는 기능이나 메서드들을 어느정도 통일을 시키는 편이 좋았을 것 같다.

느낀점

  • 코드는 계획이 전부였다.

  • 코드를 작성하는데 가독성이 매우 중요했다.

    • 남의 코드를 보면서 해결하기가 굉장히 어려웠다.
  • 기능이 있다고 한들 왜 쓰는지를 알아야하고 남한테 설명할 줄 알아야한다.

    • 그래야 내가 이 코드를 쓰는데 적합한지, 그리고 실수는 없는지 알 수 있다.
  • 가장 중요하다고 생각하는 부분은 내 코드는 내가 알아야하고, 작성한 근거가 있어야한다.

    • 코드리뷰나 팀원의 코드를 해결해 주는 과정 속에서 대부분 실수나 잘못된 곳에는 본인의 근거가 없었던 것을 알 수 있었다. 차라리 틀리더라도 본인의 근거가 있다면 잘못되었다고 설명하거나, 다른 방안을 제시할 수 있는데 본인의 코드를 본인이 모르면 설명도 안되고 해결하기도 매우 어려워지기 때문이다.

배운점

1) @EntityGraph

  • 지연 로딩으로 인해 추가 쿼리가 반복되는 상황에서, 쿼리 실행 시점에 어떤 연관 엔티티를 함께 로딩할지 미리 정의할 수 있다는 점을 배웠다.

  • 성능 튜닝이 필요한 곳에서 “Eager로 바꿀까?” 고민하기 전에 적용해볼 수 있는 옵션이라는 걸 알게 됨.

개념과 사용법

  • JPA 기본 페치 전략만으로는 특정 조회 시 N+1 문제가 발생할 수 있음.

  • @EntityGraph는 “이번 조회는 이 테이블도 같이 가져와줘!” 라고 명시하는 방법.

  • Repository 메서드에 붙여서 동작함.

@EntityGraph(attributePaths = {"user", "comments"}) // 함께 조회할 연관 엔티티들
Optional<Post> findById(Long id);

2) @AuthenticationPrincipal

  • Spring Security에서 로그인한 사용자의 정보를 컨트롤러 파라미터에 바로 받아올 수 있다는 점을 배웠다.
  • 굳이 SecurityContextHolder를 직접 꺼내지 않아도 된다는 점이 편리하고 유지보수에도 좋음.

개념과 사용법

  • 현재 인증된 사용자(UserDetails)를 파라미터로 받을 때 사용.

  • 커스텀 UserDetails 를 반환하도록 만들어 두면 더욱 깔끔하게 사용 가능.

@GetMapping("/profile")
public ResponseEntity<?> getProfile(@AuthenticationPrincipal CustomUserDetails user) {
    Long userId = user.getId(); 
    return ResponseEntity.ok("Hello " + userId);
}

3) .flush()

  • 영속성 컨텍스트에 있는 변경 사항을 즉시 DB에 반영하고 싶을 때 사용되는 기능이라는 걸 배움.
  • 특히 테스트 환경이나, 트랜잭션 안에서 DB 상태가 바로 필요할 때 유용함.

개념과 사용법

  • flush()는 커밋과 다름. 커밋은 트랜잭션을 종료하지만, flush는 변경 내용을 DB에 적용만 하고 트랜잭션은 유지됨.

  • “영속성 컨텍스트 ↔ DB” 간의 동기화를 강제로 시키는 느낌으로 생각하면 이해가 쉬움.

user.setName("updated");
em.flush();  // 여기서 update 쿼리가 바로 나감

Spring Data JPA — 메서드 이름 기반 쿼리 생성 규칙 정리

1) 기본 형태

  • Spring Data JPA는 메서드 이름을 분석해서 자동으로 JPQL을 만들어준다.
findBy + [필드명] + [조건] + And/Or + ...

2) 가장 자주 쓰는 조건 키워드

  • Equality(=)

    • 일치 검색은 별도 키워드 필요 없음.

  • Boolean 필드

    • Boolean 타입은 True, False로 많이 씀.
findByIsDeletedFalse()
findByApprovedTrue()

  • And / Or
findByUsernameAndStatus(String username, Status status)
findByUserIdOrEmail(Long userId, String email)

  • 비교 (Greater / Less)
findByAgeGreaterThan(int age)
findByCreatedAtLessThan(LocalDateTime time)
findByPriceBetween(int min, int max)

  • 포함 여부 (IN)
findByIdIn(List<Long> ids)

  • 문자열 (Like / Containing / StartsWith / EndsWith)

    • Containing = LIKE %keyword%

    • StartsWith = keyword%

    • EndsWith = %keyword

findByTitleContaining(String keyword)
findByUsernameStartsWith(String prefix)
findByEmailEndsWith(String suffix)

  • Null 여부
findByDeletedAtIsNull()
findByDeletedAtIsNotNull()

  • 정렬 (OrderBy)
findByUserIdOrderByCreatedAtDesc(Long userId)
findAllByOrderByIdAsc()

  • First / Top (limit)
findFirstByOrderByCreatedAtDesc()  // 최신 1개
findTop3ByLikesDesc()              // 상위 3개

예시 1 — 유저의 ‘삭제되지 않은’ 최신 게시글 10개

findTop10ByUserIdAndIsDeletedFalseOrderByCreatedAtDesc(Long userId)

예시 2 — 제목에 keyword 포함 & published 상태

findByTitleContainingAndPublishedTrue(String keyword)

예시 3 — 생성일 조건 + 여러 사용자 포함

findByUserIdInAndCreatedAtAfter(List<Long> userIds, LocalDateTime time)

정리

  • Spring Data JPA는 메서드 이름만으로도 쿼리를 자동 생성한다.

  • 기본 구조는 findBy + 필드명 + 조건이며, And, Or, OrderBy 등으로 조합 가능.

  • 자주 쓰는 조건들은 다음과 같음:

  • Containing, StartsWith, EndsWith

  • GreaterThan, LessThan, Between

  • In, IsNull, IsNotNull

  • IsDeletedFalse, ApprovedTrue 같은 boolean 조건

  • OrderBy + ASC/DESC

  • Top, First (limit)


피드백

튜터님의 피드백을 통해 컨밴션의 통일화와 코드리뷰의 중요성, API명세서가 얼마나 잘 짜여져 있는지에 따라서 계획의 차질이 많이 바뀌는 것을 느꼈고, 팀원과 충분한 소통과 코드 스타일을 타협함으로써 좋은 결과물을 얻을 수 있다는 것을 느낄 수 있는 첫 프로젝트 였습니다.

계기를 토대로 다음에 더 좋은 결과물을 얻을 수 있을 것이고 같은 실수를 안하기 위해 노력하겠습니다ㅎㅎ

  • 이번 조도 분위기가 굉장히 좋았기에 같이 밤을 새도, 늦게까지 남아도 소중한 시간이었고 경험이었습니다. 앞으로 팀원분들도 승승장구 하길!

0개의 댓글