- Chapter 1 프로젝트 회고
- 프로젝트 설계
- 프로젝트를 진행하며 고민했던 부분
- 제출 이후 생각하지 못했던 점이나 아쉬웠던 부분
- 마무리
Chapter 1 프로젝트가 마무리 되었다. 프로젝트에 대해 회고를 진행했다.
github : https://github.com/Black-White-Delivery-Driver/backend
우선 도메인을 분류하고 API와 ERD 설계를 진행했다.
- 도메인 분류
- 사용자
- 주소
- 점포
- 주문
- 결제
- 장바구니
- 리뷰
- 카테고리
- AI
ERD : https://teamsparta.notion.site/82ad5b8b927045c981d5a1a0f073a59a
API 명세서 : https://teamsparta.notion.site/API-195e3bb2fa6f4021aa9c8fe3e36b6717
코드 컨벤션은 우테코 Java Code Style을 적용했고, Git 커밋 메세지 컨벤션은 AngularJS 컨벤션을 적용했다.
배포 담당은 내가 담당하기로 했고, 비교적 간단하게 구성했다. 여유가 된다면 도커 이미지 빌드 및 CI/CD 적용, SSL 인증서 적용 등을 진행하기로 결정했다.

현재 프로젝트에서는 soft delete를 수행하기에 삭제 관련 정보를 저장하는 필드가 따로 존재한다. 그렇다면 내부 로직은 수정으로 동작한다. 그렇다면 여기에 알맞는 메서드 타입은 무엇일까?
우선 내가 생각한 것은 내부 로직이 어떻든간에 "삭제"를 수행하는 것이기에, 이를 나타내기 위해서는 DELETE 메서드를 사용하는 것이 맞다고 생각했다. 팀원들도 이 의견에 동의했다.
이후 다른 팀 발표 간에 튜터님께서 주신 피드백에서 이 내용이 맞았음을 확인했다.

내가 남겼던 리뷰이다. for문과 stream의 사용에 대한 결론은 다음과 같다.
primitive 타입은 for문으로 순회해야 성능적으로 이점
wrapper 타입은 stream과 for문 성능 차이가 많이 없고,
stream에 정의된 기능을 사용하면 가독성 측면에서 이점
상황에 따라서 for문과 stream()을 사용
현재 서비스 로직에서는 stream()을 사용하는 쪽이 맞다고 결론내렸다.
일부 Controller 메서드에서 Service 메서드의 파라미터로 UserDetails의 User Entity를 직접 넘기는 방식을 사용했다.

이런 리뷰를 받았다. 그래서 일부 로직에서 UserDetails에서 Entity를 직접 넘기던 방식을 모두 UserRepository의 findById로 찾아서 사용하도록 변경했다.
단위 테스트 코드를 작성할 때, 상태 코드가 기대했던 대로 반환되지 않는 문제가 있었다. 특히 회원가입은 인증되지 않아도 진행할 수 있도록 WebSecurityConfig에서 설정했었는데, 계속해서 401이 반환되었다.
결론은, @TestConfiguration을 통해 테스트용 security config를 만들지 않으면 기본 설정을 security가 생성하고 그것이 적용이 된다. 여기에는 WebSecurityConfig에서 설정했던 그 무엇도 설정되어 있지 않기에 csrf 문제, 401 unAuthorized 등이 발생했던 것이다. 앞으론 테스트에서 @TestConfiguration를 잘 구현하도록 해야겠다.
초반에는 리뷰를 통해 좋은 피드백과 리팩토링이 진행되었지만, 프로젝트가 진행될수록 시간이 부족해 리뷰가 부족해서 서로의 구현 방법이 다르거나, 로직의 위치가 다르게 되어있는 등 문제가 많았다.
특히 권한처리에 대한 로직이 컨트롤러에 있는 등 미흡한 부분이 있었고, 이것을 리팩토링 하는데 시간이 너무 많이 소요되었다.
위 문제에서 이어지는 문제인데, 테스트 코드를 작성할 시간이 모자랐다. TDD는 아예 생각도 하지 못했고, 직접 테스트를 진행하다 보니 edge case를 놓친 부분이 많았다. 도전 기능에 통합 테스트 코드를 작성하라는 내용이 있었는데, 너무 아쉬운 부분이다.
QueryDSL로 복합 쿼리를 작성하라는 도전 기능 요구사항이 있었는데, 결국 복합 쿼리로 처리하지 못했다. 쿼리 파라미터로 카테고리와 가게 이름이 입력되면 일치하는 내용을 검색할 수 있도록 하고, 하나만 입력되는 경우도 있을 수 있는데 JPA만으로는 힘들어서 QueryDSL을 사용하면 좋았을텐데, 시간이 부족해 결국 카테고리 / 가게 이름 검색은 분리되었다.
현재 Store Entity에는 총 평점 합산 필드와 리뷰수 필드가 있다. dto를 생성할 때 이를 계산해서 넣도록 dto에만 평균평점 필드가 있는데, Review 삭제 시에 총 평점에서는 빼도록 처리했는데 리뷰수에는 따로 처리를 안 해 버렸다... 이미 제출 시간이 지난 후에 인지해서 이후에 리팩토링을 해야 할 것 같다.
지금 단순히 EC2와 RDS만을 사용하고 있다. ELB를 통해 https를 적용하려고 했는데, IPv4 주소가 비용이 발생해서 적용하지 못했다. 그래서 NGINX의 리버스 프록시와 certbot을 통해 로드밸런서 역할을 수행하려고 했는데, https로 요청을 보내는 것까지는 성공했지만 http로 보냈을 경우 리다이렉트는 수행되는데 403 에러가 발생되었다. 마지막 날에 진행한 부분이라 트러블슈팅을 진행하기에는 시간이 너무 모자랐고, 결국 https 적용을 취소했다.
그리고 CI/CD를 프로젝트 시작 전에 미리 적용할 수 있었으면 좋았겠지만, Github Actions으로 CI/CD를 구현해 본 적이 없어서 일단 빠르게 내 기능들을 끝내놓고 적용하려고 했다. 하지만 다른 팀원의 구현 일정이 밀리면서 내가 다른 기능까지 맡아서 구현을 진행하게 되어 결국 적용하지 못한 점이 아쉽다.
refresh token을 적용하는 부분도 많이 해보지 못해서 시간이 모자랄 것 같아 일단 access token만 발급하고 사용하는 식으로 진행했는데, 결국 구현 일정에 밀려 적용하지 못했다. 후에 리팩토링을 통해 적용해야겠다.
다른 팀들이 구현한 내용에 비해 우리 팀은 설계, 문서, 구현 모두 부족하다는 느낌을 많이 받았다... 특히 Redis와 관련된 구현은 아예 해 본적이 없고 부트캠프에서 강의를 제공한다고 알고 있는데, 이미 다들 할 줄 아는 것 같았다.
좀 더 프로젝트 퀄리티를 높이고 싶다. 이후에 반드시 리팩토링을 통해 구현하려고 했지만 못 했던 부분들을 적용해야겠다.