TIL(Today I Learned)

[TIL] 뉴스피드 프로젝트(백엔드 구현)

jy3574 2024. 11. 26. 23:13
프로젝트 요약

1. 프로젝트 목적

  • 협업 도구(Git & Github)를 사용하여 컨벤션 준수의 중요성 체득
  • RESTful API 설계 및 JPA 기반 CRUD 구현
  • Spring Boot와 JPA를 활용한 데이터 검증 및 인증/인가 로직 구현
  • Cookie/Session을 활용한 인증 및 사용자 데이터 유효성 검증
  • 유지보수성이 높은 코드를 위한 비즈니스 로직 분리 및 예외처리

2. 프로젝트 구현

<필수 구현>

  • 프로필 관리 : 사용자 프로필 CRUD, 비밀번호 변경, 본인확인 로직
  • 뉴스피드 게시물 관리 : 게시물 CRUD, 조회 시 생성일 기준 정렬, 페이지네이션
  • 사용자 인증 : 회원가입, 로그인, 로그아웃, 세션/쿠키 관리
  • 친구관리 : 친구 요청, 수락, 삭제 및 친구의 최신 게시물 조회

<도전 구현>

  • 뉴스피드 게시물 관리 : 조회 시 수정일 기준 정렬, 좋아요 많은 순 정렬, 기간별 검색
  • 댓글 : 댓글 CRUD, 게시물 및 댓글 작성자만 수정/삭제 가능
  • 좋아요 : 게시물, 댓글에 대한 좋아요/좋아요 취소, 자신이 작성한 게시물과 댓글에는 좋아요 할 수 없음

사용한 기술 및 개념
& 맡은 역할

1. Backend : Spring Boot, Spring Data JPA

  • Spring Boot
    • 스프링 프레임워크를 기반으로 한 애플리케이션 개발 플랫폼
    • 내장 서버(Tomcat)를 사용하여 빠르게 애플리케이션을 실행 가능
    • RESTful API 설계 및 계층 분리(Controller, Service, Repository) 구조 지원
  • Spring Data JPA
    • JPA(Java Persistence API)를 더 쉽게 사용할 수 있도록 도와주는 스프링 모듈
    • 데이터베이스와의 상호작용을 위한 기본적인 CRUD 메서드 제공(findAll, save, delete)
    • Entity, DTO를 사용해 관계형 객체 매핑 처리

2. Database : MySQL,  ERD(DB diagram)

  • MySQL
    • 관계형 데이터베이스 관리 시스템(RDBMS)
    • SQL(Structured Query Language)을 사용해 데이터베이스 CRUD 가능
    • 일정관리 프로젝트에서 일정, 유저, 댓글의 데이터 저장 및 연관 관계 설정에 사용
  • ERD
    • 데이터베이스 설계 시 Entity 간의 관계를 시각적으로 표현

3. Tool : Postman(API test), IntelliJ IDEA, Git / Github

  • Postman
    • API 요청 & 응답 테스트 도구
    • 프로젝트에서 구현한 RESTful API를 테스트하고 상태 코드(200, 404 등)와 응답 데이터 확인
  • IntelliJ IDEA
  • Git / Github
    • Git
      • 분산 버전 관리 시스템으로 코드의 변경 이력을 관리하고 협업에 사용
      • 로컬 환경에서 파일의 상태를 추적하고 버전을 기록하며, 특정 시점으로 되돌릴 수 있음.
      • commit, branch, merge 등의 기능을 제공하여 프로젝트 관리 효율성 증가
    • Github
      • Git 저장소를 원격으로 호스팅하는 클라우드 플랫폼
      • 협업을 위한 코드 리뷰, 이슈 관리, PR(Pull Request) 기능 지원
      • 팀원 간 소스 코드 공유 및 관리 용도로 사용
      • Git과 연계하여 프로젝트의 버전 관리와 협업을 한곳에서 처리 가능

3. 팀 내에서 맡은 역할

  • 필수 기능 : 게시물 조회 담당
    • 전체 게시물 조회 - 최신순 정렬, 페이지네이션
    • 특정 사용자의 게시물 조회 - 최신순 정렬
    • 단일 게시물 조회
  • 도전 기능 : 뉴스피드 업그레이드 담당
    • 기간별 게시물 조회 - 입력받은 날짜에 따라 게시물 필터링
    • 정렬 기능 추가 - 수정일 기준 최신순, 좋아요 많은 순
  • 기초 설계
    • API 명세서 작성 : 프로젝트 전반의 API는 다같이 맡은 부분을 작성하되, 마지막 검토 및 수정 담당
    • ERD 설계 : 데이터베이스 구조와 도메인 간 관계를 시각화하여 설계 (팀원 1명이랑 같이 설계)

팀에서 구현한 내용
& 내가 구현한 내용

1. 프로젝트 설계

-API 명세서 작성

 

-ERD 작성

 

2. 구현 기능 - 내가 맡은 부분

  • 게시물 조회 및 뉴스피드 업그레이드
    • 구현 내용
      • 전체 게시물 조회
        • 최신순 정렬, 페이지네이션 구현
      • 특정 사용자의 게시물 조회
        • 사용자의 ID로 필터링
      • 단일 게시물 조회
        • 게시물 ID로 특정 게시물 반환
      • 기간별 게시물 조회
        • 클라이언트에서 날짜만 입력받아 서버에서 LocalDateTime으로 변환
        • 시작날짜는 00:00:00, 종료날짜는 23:59:59로 설정해 모든 데이터 포함
      • 정렬 기능
        • 기본 정렬 : 수정일 기준 최신순
        • 다음 정렬 : 좋아요 개수 기준
    • 구현 기술
      • @PageableDefault를 활용한 기본 페이지 크기 = 10개 설정, 정렬 설정
      • @GetMapping, @PathVariable 로 동적 URL 처리
      • Sort 객체를 사용하여 중앙관리로 정렬 구현
      • @RequestParam을 활용해 사용자 입력처리

3. 팀원 구현 기능 분석

  • 사용자 프로필 관리
    • 구현 내용
      • 사용자 프로필 조회 : 민감 정보를 제외한 정보만 제공
      • 사용자 프로필 수정 : 이름, 나이, 소개글 등을 업데이트 가능
      • 비밀번호 변경 : 기존 비밀번호 확인 후 새로운 비밀번호로 변경
    • 사용기술
      • JPA를 활용한 엔티티 설계 및 데이터베이스 연동
      • @PatchMapping과 @Valid로 입력값 검증
    • 학습 내용
      • DTO에서 비즈니스 로직을 제거하고, 순수 데이터 전달 객체로 사용하는 방법
      • 비밀번호 검증 로직에서 정규표현식을 활용한 데이터 유효성 검증
  • 댓글 관리
    • 구현 내용
      • 댓글 작성, 조회, 수정, 삭제 기능 구현
      • 댓글 작성자는 본인 댓글만 수정/삭제 가능, 게시물 작성자는 댓글 삭제 가능
    • 사용 기술
      • JPA 연관관계 매핑 : @ManyToOne, @JoinColumn으로 댓글과 게시물 & 사용자 연결
      • 데이터 검증 : @NotBlank 등으로 입력값 유효성 확인
    • 학습 내용
      • 연관관계 설계 시 Cascade와 Fetch의 중요성
      • 작성자와 관리자 권한 분리를 통한 권한 검증 로직 설계
  • 좋아요
    • 구현 내용 
      • 게시물 및 댓글에 좋아요/좋아요 취소 기능 구현
      • 같은 게시물/댓글에는 사용자 당 한 번만 좋아요 가능
    • 사용 기술
      • Optional을 활용해 중복 좋아요 방지
      • 게시물, 댓글의 좋아요 개수를 실시간으로 업데이트
    • 학습 내용
      • 데이터 무결성을 위한 트랜잭션 처리
      • 좋아요 기능의 비즈니스 로직을 효율적으로 구현하는 방법
  • 친구
    • 구현 내용
      • 친구 요청, 수락, 삭제 기능 구현
      • 친구의 최신 게시물을 뉴스피드에서 조회 가능
    • 사용 기술
      • @EmbeddedId로 복합키 설계
      • 친구 요청/수락 상태를 나타내는 상태값(friendRequest) 관리
    • 학습 내용
      • 복합키 설계와 데이터 추적성 관리
      • 상태값을 활용한 요청, 수락 로직 구현의 중요성

4. 예외처리

  • 구현내용
    • 컨트롤러 계층
      • 클라이언트 요청 검증과 세션 유효성 확인
      • 세션 검증 예외 : 사용자가 로그인 상태가 아니면 IllegalStateException을 발생
      • 예외 메시지를 포함해 클라이언트가 문제를 이해할 수 있도록 설계
    • 서비스 계층
      • 비즈니스 로직과 데이터 유효성을 검증
      • 문제가 있을 경우 ResponseStatusException을 활용해 예외처리
      • 데이터 유효성 검증 예외 : 잘못된 사용자 ID를 요청했을 때 ResponseStatusException을 통해 HTTP 상태코드와 메시지 설정
    • 한계
      • 중복 코드 : 각자 맡은 부분을 예외처리하다 보니 세션 검증 로직과 같은 반복적인 코드가 분산되어있음
      • 일관성 부족 : 예외 발생 시 응답 형식과 메시지가 계층마다 다름
    • 개선방법, 학습내용
      • GlobalExceptionHandler와 같은 전역 예외처리를 설계 시에 같이 정했으면 코드 중복을 줄이고 관리가 용이했을 것 같음
      • 예외처리의 중요성을 알 게 되었음

진행 중 어려웠던 점과 해결방법
& 피드백

1. 진행 중 문제점과 해결방법은 트러블 슈팅을 작성해 정리

https://jy3574.tistory.com/100

 

[내일배움캠프/백엔드] Spring 숙련. 뉴스 피드 프로젝트 트러블 슈팅

1. Git 충돌 해결1) 개요develop 브랜치에서 동시에 작업을 진행하면서 push, pull 하는 과정에서 다른 팀원이 작성한 내용을 pull로 가져올 때, 현재 작업하고 있던 내용과 충돌이 발생 2) 문제상황-모

jy3574.tistory.com

 

2. 설계에 관한 피드백

-API 설계 피드백

  • Header와 Body의 명확한 구분
    • Header와 Body 구조체를 명확히 구분한 점에서 긍정적인 피드백
    • 개선사항 : Body의 예시는 데이터 타입에 맞게 json 형식으로 작성하고, HTTP status를 따로 쓸 것
  • 날짜 포맷
    • 날짜는 yyyy-MM-dd로 포맷팅하지 않고, 데이터베이스에 저장된 그대로 반환하도록 변경
    • 클라이언트 측에서 필요한 경우 포맷팅하도록 권장
  • 불필요한 데이터 제거
    • 특정 사용자의 게시물 조회 API에서 visible 필드가 프론트엔드에서 사용되지 않는다는 피드백을 받고 해당 필드 제거
  • HTTP Method 재검토
    • 친구 요청 거절 시 Hard-Delete를 수행하는 경우라면 DELETE 메서드를 사용
    • 상태만 변경하는 경우 PUT, PATCH 메서드로 수정해야한다는 피드백 반영
    • 구현 시 요청 상태에 따른 적절한 HTTP 메서드를 재검토 후 적용
  • 응답 데이터의 부정적 표현
    • 내용이 없을 경우 x로 표시해뒀는데, 이는 부정적으로 보일 수 있다는 피드백을 반영하여 공백 또는 -으로 변경

-ERD 설계 피드백

  • 케이스 규칙
    • 데이터베이스 명명 규칙을 카멜 케이스에서 스네이크 케이스로 변경
    • JPA 기본 전략에 맞춰 명명 규칙을 통일하고, 코드와 데이터베이스 간의 매핑을 명확하게 해야함
  • 회원 탈퇴 여부 필드명
    • status는 의미가 모호하여, is_active 또는 _yn과 같은 명칭으로 변경
    • 상태가 Boolean 값인지, Enum 값인지 명확히 정의
    • MySQL에서는 Boolean 대신 TINYINT로 구현
  • PK, FK 명칭
    • friends 테이블의 PK 명칭(id)이 다른 테이블과 일치하지 않아 혼란을 줄 수 있음 -> id로 통일
    • FK명칭은 to_user_id, from_user_id로 변경하여 관계를 더 명확히 표현
  • 친구 요청 상태
    • friends_request 필드에 bit 데이터 타입(0: 요청, 1: 수락)을 사용
    • 구현할 때 코드에서 명확히 치환하도록 로직을 작성

-역할 분담 및 스코프 관리

  • 기능과 도메인 단위로 균등한 역할 분배
    • 팀원들이 각자 맡은 역할을 명확히 정의하여 프로젝트 진행 중 충돌이 없도록 관리
  • 스코프 관리
    • 설계 이후 구현, 테스트, 발표를 고려하여 일정관리를 할 것
    • 버전 관리는 Git 컨벤션을 따르고, 코드 병합 시간을 두어 개발 흐름을 방해하지 않도록 함
    • 회의는 수시로 짧고 명확하게 진행하며, 주의 논의사항과 결론을 기록으로 남김

3. 코드 구현 후 최종 피드백

-컨벤션 및 중복 코드 개선

  • 규칙적인 컨벤션 적용
    • 프로젝트 전반적으로 규칙적인 컨벤션이 적용되었다는 긍정적인 피드백을 받았음
    • Git 커밋 메시지, 코드정렬, 네이밍 규칙 등을 일관성 있게 관리한 점을 인정 받았음
  • Session 정보 관리 개선
    • Session 정보를 email로 저장하는 대신 Constant 객체로 static final로 관리하도록 개선
    • @SessionAttribute 활용이나 RequestContextHolder를 통해 개선 가능하다는 피드백을 받고, RequestContextHolder로 관리하는 방법을 학습

-API 설계 및 데이터 관리 개선

  • 로그아웃 API 추가
    • 로그아웃 API가 빠져있다는 피드백을 반영하여 구현 완료
    • 세션을 무효화하고 사용자 로그아웃 처리를 추가
  • ResponseDto 추상화
    • ResponseDto 객체에 공통적으로 사용되는 message와 같은 필드를 추상화하여 상속 구조로 변경
    • 중복 코드를 줄이고 유지보수성을 높였음
  • DTO
    • DTO는 데이터를 전달하는 객체이므로 데이터를 수정하거나 비즈니스 로직을 포함하지 않도록 수정
    • ProfileUserResponseDto에서 age와 introduce를 변경하는 로직을 제거하고, 프론트엔드에서 처리하도록 권장
  • PageableDefault 옵션
    • 기본 페이지 크기를 설정한 점에 대해 긍정적인 피드백을 받음
    • 모든 API에서 일관되게 10개씩 데이터를 반환하도록 설정

-엔티티 설계 및 코드 리팩토링

  • 복합키 사용
    • Friend 엔티티에서 EmbeddedId를 활용하여 복합키를 적용한 점이 데이터 추적성과 Join의 장점으로 인정받음
    • 하지만 복합키 필드 개수가 많아지면 Hash 충돌 가능성과 복잡성이 증가할 수 있으므로 적합한 설계를 고민
  • 중복 코드 제거
    • Repository에 Default 메서드를 구현하거나 별도의 메서드로 분리하여 코드 간소화
  • 가독성 개선
    • Service에서 getter 만으로 작성된 코드가 가독성을 떨어뜨린다.
    • entity 내부에서 처리하는 메서드로 이동하여 가독성과 유지보수성을 개선
  • 친구 관계 데이터 관리
    • Friend 엔티티에서 toUser와 fromUser를 교차 저장하는 방식이 불필요하다는 피드백
    • 상태값만 관리하도록 수정하여 중복 데이터를 제거
  • Soft Delete
    • 삭제 요청 시 명시적으로 Soft Delete 여부를 표현하지 않아도 Delete 메서드와 Entity의 설정만으로 충분히 의도가 전달될 수 있다는 피드백

느낀점 및 개선해야할 점

 

프로젝트에서 팀장을 맡아 설계 단계에서 팀원들과 소통도 많이하고, 역할도 나누며 꼼꼼하게 설계했다고 생각했는데 피드백을 받고 나니 어떤 디테일을 챙겨야 하는지 조금 더 알게 되었고, 피드백을 바탕으로 수정하면서 API와 데이터 모델의 일관성을 좀 더 높일 수 있었던 것 같다. 또한, 설계 초기 단계에서 클라이언트와 서버 간의 데이터 요구사항을 명확히 정의하는 것이 구현하고 테스트 하는 과정에서 발생할 수 있는 문제를 줄이는 것을 좀 더 명확히 알게 되었고 조금 더 구체적으로 설계를 해야겠다고 생각했다. 그리고 충분히 소통을 하고 설계를 했다고 생각했는데도 코드 컨벤션이나 커밋컨벤션 등을 얘기를 하지 않아 중간 점검을 할 때 코드가 너무 복잡해 보이는 단점이 있었다. 이런 부분도 다음번에 고려해서 정해야겠다고 생각했다.

 

이번 프로젝트에서 처음 팀원들과 협업을 하고 코드를 짜봤는데 팀원들의 코드를 보면서 서비스 계층에서 예외처리를 다양하게 구현하는 방법을 배웠다. 특히 스프링 제공 기능을 잘 활용하여 코드를 짠 부분들이 인상 깊었다. 하지만 GlobalExceptionHandler를 사용했으면 코드의 중복을 줄이고 응답형식이 일관성 있었을 것 같다고 느꼈다. 다음 프로젝트는 전역 예외 처리에 대해 조금 더 공부해보고 적용해봐야겠다. 또한, 프로젝트 진행 중 git, github에 관련한 부분에서 충돌도 있었고, 친구 관련 API에서 의견이 일치하지 않아 일단 그 부분을 맡은 팀원의 의견에 맡기고 진행하였는데, 결국 나중에 코드를 고쳐야하는 일이 있었다. 이를 통해서 코드를 짜면서도 저장소 관리와 사소한 의견이라도 소통을 충분히 해야겠다고 느꼈다. 마지막으로 저번 과제에서 해결하지 못했던 로그인과 White List 관리와 관련된 부분을 팀원은 해내는 것을 보고 이런식으로 적용하면 되겠구나 라는 것을 배우게 되었다.

 

개인적으로 프로젝트를 진행하면서 배우게 된 점은 뉴스피드의 조회 기능을 구현하면서 클라이언트를 고려한 개발을 해야한다는 것이 가장 크게 느껴졌고, API 명세서와 ERD 설계를 꼼꼼히 하는 것이 개발 방향 뿐 아니라 효율적인 협업을 하는데에도 중요하다는 것을 알게 되었다. 또한 단계별로 기능을 분리하고 Postman으로 테스트를 하면서 하는 것이 가장 효율적이고, 디버깅 모드를 잘 활용해야겠다는 생각도 하게 되었다. 또한 RESTful 설계를 하는 것이 무엇인가에 대한 생각을 항상 가지고 있었는데 협업을 하니 아 이런 부분을 말하는 거였구나를 확실히 알게 되었다.