shape

도담도담 - 프로젝트 심야자습 신청 기능 구현하기

프로젝트 설명

도담도담 심야자습 기능 확장하기

기술 스택

  • Java
  • Spring Boot
  • MySQL
  • AWS
  • Docker Compose
  • GitHub Actions
  • Figma

참여인원

9명 (백엔드 2명)

기간

2025.04 ~ 2025.05

관련 링크

상세 내용

  1. 내가 기여한 부분
    • 프로젝트 단위의 심야자습 신청을 구현하였습니다. 사용자는 프로젝트 심야자습 신청 시 날짜와 시간, 프로젝트 개요를 입력하고 팀원을 선택 후 신청합니다. 학생이 신청하거나 교사의 상태 변경(수락·거절)시 프로젝트 리더를 포함한 참가자들의 신청 상태를 모두 변경해야 하였습니다.
  2. 트러블 슈팅
    • 데이터베이스 설계 시 다음과 같은 고민을 하였습니다.
    • 기존에도 개인 심야자습 신청 기능은 존재하였습니다. 초기 설계 시 이미 있던 일반 심야자습 테이블을 사용하고, 프로젝트들은 night_study_project 테이블을 만들어 FK로 프로젝트 아이디를 받아와 저장하였습니다. 초기 테이블 구조는 다음과 같습니다.
  3. 초기 테이블 구조
    • <night_study>
    • id
    • type (개인 심자와 프로젝트 심자 1, 2를 구분하는 ENUM)
    • content (자습 내용)
    • do_need_phone (휴대폰 사용 여부)
    • reason_for_phone (휴대폰 사용 이유)
    • status (신청 상태 - ALLOWED, PENDING, REJECTED)
    • reject_reason (신청 거절 시 사유)
    • startAt (시작 날짜)
    • endAt (종료 날짜)
    • fk_project_id (일반 심자 시 null)
    • fk_student_id (신청 학생)
    • fk_teacher_id (상태 변경 시 교사 ID)
    • <night_study_project>
    • id
    • type
    • name
    • description
    • startAt
    • endAt
    • room (ENUM)
    • status
    • fk_leader_id
  4. 문제 배경
    • 하지만 여기에서 문제를 발견하였습니다. 일반 심야자습과 프로젝트 단위의 심야자습은 독립되어 클라이언트에서 사용되는 경우가 많았습니다. 예를 들어, 전체 조회를 하여도 일반 심야자습과 프로젝트 심야자습은 각각 따로 검색합니다. JPA가 심야자습들을 찾을 시 project_id의 유무로 심야자습 종류를 구분해야만 하였고, 요청이 될 때마다 불필요한 where 조건이 추가되어야 했습니다.
    • 코드리뷰 중 잦은 반복문 사용과 SQL 쿼리 발생으로 인하여 JPA n+1 문제가 발생하였고 시간복잡도가 높다는 것을 파악하였습니다.
  5. 개선 후 테이블 구조
    • <night_study>
    • id
    • content (자습 내용)
    • do_need_phone (휴대폰 사용 여부)
    • reason_for_phone (휴대폰 사용 이유)
    • status (신청 상태 - ALLOWED, PENDING, REJECTED)
    • reject_reason (신청 거절 시 사유)
    • start_at (시작 날짜)
    • end_at (종료 날짜)
    • fk_project_id (일반 심자 시 null)
    • fk_student_id (신청 학생)
    • fk_teacher_id (상태 변경 시 교사 ID)
    • <night_study_project_member>
    • id
    • name
    • description
    • room
    • type (시간대를 구분하기 위함)
    • status
    • startAt
    • endAt
    • rejectReason
    • fk_teacher_id
    • <night_study_project_member>
    • id
    • role (LEADER, MEMBER)
    • fk_student_id
    • fk_project_id
  6. 해결 방법
    • night_study, night_study_project, night_study_project_member 테이블로 데이터베이스 정규화를 하여 SQL 최적화를 하였습니다.
    • 반복문보다는 JPA와 JPQL에서 in과 join, exists 등을 이용하여 시간복잡도를 줄였습니다. 또한 코드의 리팩터링으로 평균 응답 시간이 ≈522.6ms → 73ms 로 7배 이상(약 737.5%) 줄였습니다.
    • 이 결과로 night_study_project 조회 시 불필요한 쿼리(join, where 등)가 발생하지 않았습니다.
  7. 리팩터링 전
      리팩터링 전 1
      리팩터링 전 2
      리팩터링 전 3
    • 리팩터링 후
        리팩터링 후 1
        리팩터링 후 2
        리팩터링 후 3