약 26주 간의 코드스테이츠 교육을 수강하면서 가장 고대하던 메인 프로젝트를 진행한 회고를 작성해야겠다.
팀 프로젝트는 약 4주간 (2023.08.24 ~ 2023.09.19) 진행하였다. 백엔드와 프론트 모두 기획부터 디자인, 설계, 개발, 발표를 함께 고민하고 결정하는 부분에 있어서 4주라는 기간은 굉장히 빡빡한 일정이었다.
프로젝트를 하는 기간동안 흔히 말하는 소프트 스킬이라는 협업의 전반적인 태도와 소통의 중요성을 배울 수 있었다. 팀원들 모두 나처럼 하나씩 배워가는 과정이었을테니.. 누구하나 완벽하고 부족할 거 없이 애쓰는 것이 느껴졌다. 그 결과 총 34팀 중 5팀만 뽑은 나름의 우수상을 수상하여 굉장히 뿌듯하고 보람찼던 프로젝트였다.
기간 내에 완벽한 결과물을 만들고자 하는 욕심에 정신 없이 개발에만 집중하다 보니 중간 중간 기록을 하지 못했다. 프로젝트가 끝난 이 시점에 4주 간의 경험을 되돌아보면서 아쉬웠던 점들을 기록하며 더욱 성장하는 내가 되어야겠다.
📌 프로젝트 소개
- 팀원: 6명 (BE 3명, FE 3명)
- 프로젝트 명: 실시간 중고 경매 웹 서비스 WonPrice
- 깃허브: https://github.com/codestates-seb/seb45_main_003
- 배포 링크: https://wonprice.shop/
- 협업 툴: Discord, Zoom, Notion
- 기술 스택
- Infra: AWS EC2, RDS, S3
📌나의 역할
- 백엔드 개발
- Spring Boot, JPA, MySQL, AWS EC2, Postman
- DB 설계 / 구축
- API 명세서 작성
- g프로젝트 개발
- 상품 등록, 조회, 수정, 삭제
- 상품 상태, 카테고리, 제목 별 분류
- 웹소켓을 통한 실시간 경매 기능
📌프로젝트 과정
1. 기획
프로젝트 주제를 결정할 때 가장 먼저 고려했던 점은 "사용자 입장에서 바라보는 서비스의 형태" 였다.
그만큼 유저친화적이면서 특별한 강점을 가진 프로덕트를 개발하고자 우리 팀만의 특별한 무언가를 보여주고 싶었다.
팀원들 모두 본인이 지금껏 경험해보고자 했던 서비스를 함께 이야기하는 시간을 가지면서 내 사고력 또한 확장되는 느낌을 받았다. 그 중에서도 팀장님이 제안하신 "실시간 중고 경매 서비스"가 눈에 띄었다. 실제로 이커머스 플랫폼 뿐만 아니라 중고 상품을 거래하는 형태의 서비스가 많이 출시된 가운데, 경매라는 특별한 이벤트가 적용된다면 유저 입장에서도 눈에 띌 것 같았다. (개인적인 입장이지만.. 개발하기에 재밌을 것 같다는 생각도 들었다. ㅎㅎ)
그렇게 고심 끝에 프로젝트 주제를 선정한 뒤, 빡빡한 일정을 고려하여 곧장 프로젝트의 전체 흐름을 함께 이야기하는 시간을 가졌다. 흐름을 이해하지 못하고 바로 개발에 들어가는 것은 추후에 어마어마한(?) 파장을 일으킬 거라고 생각하는 편이라.. 팀원들 모두가 서비스의 흐름을 제대로 상기했으면 했는데, 팀원들 모두 나와 같은 마음인거 같아 좋았다.
- Notion
2. 설계
서비스의 흐름을 이해한 뒤, 프론트와 백엔드가 각각 화면 정의서와 ERD를 고려하는 시간을 가졌다. 도중에 프론트의 제안으로 함께 화면 정의서에 대한 디자인을 함께 구상하는 시간을 가졌다. 디자인이라는 것은 개인의 취향에 따라 천차만별이기 때문에 실제 개발에 들어가기 전에 백엔드 측에도 함께 고민해보자는 이야기였다. (so 감동 ..) 그렇게 웹의 대표 색상 및 전체적인 분위기를 다수결을 통해 좁혀가면서 UX/UI 에 관한 이야기를 마쳤다.
- Figma
돌아와 백엔드 팀원들끼리도 각자 개념적 데이터 모델링을 구성한 상태로, 논리적 데이터 모델링을 함께 만들어 냈다. 핵심 기능에 관한 테이블을 크게 나눈 후, 해당 테이블의 KEY, 데이터 타입, 테이블 간의 관계 등을 지정해주었다. 생각한 것보다 테이블 간의 구조가 복잡했기에 처음 설계된 ERD는 개발에 들어간 후에도 조금씩 수정되곤 했다.
- ERDCloud
채팅방 기능을 구현할 때, 한 유저가 채팅방을 나갈 경우 해당 채팅방이 삭제된 것을 DB 상에서 표현하고자 하였으나, 채팅을 주고 받은 다른 상대에게까지 적용되는 건에 관하여 삭제된 채팅방에 관한 테이블을 따로 빼야 하는 것인가? 하는 고민에 빠졌다.. 팀장님이 맡으신 파트를 함께 고민하면서 멘토님께 질문한 결과, DB가 삭제될 경우 화면도 변경되어야 하는 로직이라고 하셨다.
결국 우리가 고민하고자 하던 것은 결국 비즈니스 로직이기 때문에 채팅 쪽 ERD를 모두 수정할 것을 권장하셨다. DB는 화면과 다르게 DB 값 하나에 의해 화면이 좌지우지 되는 것은 지양해야 하는 것이라고 이해했다. 내가 DB를 설계할 때 항상 어려움을 느끼던 부분이 바로, 화면 상에 보이는 데이터와 서버 상의 비즈니스 로직을 다른 관점에서 보아야 한다는 것이었다. 함께 고민하던 내용 또한 비슷한 어려움이었던 것 같아 다시 한 번 상기할 수 있는 시간이었다.
- API 명세서
API 명세서는 백엔드 측에서 프론트와 협업하는데 있어서 가장 밀접한 관계가 있는 문서 작업이라고 생각했다. 그래서 실제 개발에 들어가는 즉시 API 명세서를 업데이트하였으며 프론트에게 해당 변경 사항을 공유하곤 했다. 한참 개발을 진행하는 도중 회원 정보에 관한 파트를 맡은 백엔드와 프론트 분께서 변수명을 수정해줄 것을 요구하셔서 중간에 내가 추가해놓은 변수명을 모두 변경하고 작성해두었던 내 파트 쪽 API 명세서를 다시 업데이트해야 할 일이 생겼었다. (물론 나의 파트너 프론트분에게도 해당 수정사항을 말씀드렸다..) 이러한 시행착오를 겪으면서 사전에 코드 틀을 잡을 때 꼼꼼히 체크하는 것이 중요하구나! 하고 다시 한 번 알게 된 에피소드였다는.. 🤣
3. 개발
사실 우리 팀은 위에서 진행했던 설계와 개발을 함께 병행하면서 진행했다. 그래도 팀원 모두가 서비스 시나리오를 확실히 짚고 넘어갔기 때문에 중간에 문제가 발생했을 때 빠르게 해결할 수 있었던 것 같다. (아무래도 개발 기간이 짧다 보니 정석대로 하기 힘들었던 것도 있다.)
먼저 우리 프로젝트 기능을 크게 나누자면 다음과 같다.
- 회원가입 / 로그인
- 회원 상품 찜 / 리뷰 / 알림 / 프로필 조회
- 상품 (카테고리, 상태 별) 조회 / 등록(이미지 포함) / 수정 / 삭제
- 실시간 경매 / 입찰
- 실시간 채팅 / 알림
맨 처음 프로젝트 기획 당시 각자 구현해보고자 하는 기능을 나열하고, 중요도를 선정하는 시간을 가졌다.
제한된 기간 안에 현실적으로 구현 가능한 영역까지를 중요도 상으로 설정한 뒤, 추후 기능 구현이 완벽해졌을 때 가지를 늘어뜨리는 방향으로 진행하였다. 기대한 것 이상으로 팀원들 모두가 기한 내에 기능 구현을 매우 잘 해주셔서 아마 추가하지 못할 뻔한 (?) 알림 기능이나 채팅의 읽음 안읽음 처리까지 구현될 수 있던 것 같다.
그 중에서 나는 상품 조회, 등록, 수정, 삭제와 실시간 경매와 입찰 부분을 담당했다.
사실 위에 나열한 기능은 기본적인 CRUD라 생각하였지만 개발하는 도중에 몇가지 고민을 해야했던 기억이 남는다.
상품 카테고리
상품 카테고리를 설정하는 데 있어서 가장 먼저 떠오르는 방법으로는 그냥 "Enum 타입 클래스를 하나 추가하자!" 였다. 물론 Enum 타입으로 카테고리를 설정했더라도 코드 상에 큰 문제는 없었을 것이다. 하지만 여기서 고려해야 할 점은 코드의 확장성이었다. 만약 Enum 타입으로 고정시킨 카테고리 정보를 변경하고 싶다면 때 코드를 일부 수정하고 다시 빌드해야 하는 번거러움이 생기게 될 것이다. 이런 번거로움을 고려해 보았을 때 카테고리 쪽 테이블을 하나 추가하는 것이 좋은 해결 방안이라 판단했다.
bigint형 id를 PK로 설정하고, 각 카테고리를 네이밍 할 varchar타입 name을 추가했다. 이렇게 하면 카테고리명을 변경하거나 카테고리를 추가하고 싶을 때 코드 자체를 수정하지 않고 DB 쿼리문만 수정해주면 된다. 이러한 고민의 과정을 통해 단순히 기능 구현에 의존하지 않고, "어떻게 하면 객체지향적으로 코드를 짤 수 있을까?"라는 생각을 많이 하게 된 것 같다.
실시간 경매 & 입찰
프로젝트의 핵심 기능이라 할 수 있는 경매와 입찰에 관한 부분이다. 이 기능의 가장 핵심은 실시간이기 때문에 이 부분을 어떤 방법으로 구현하는 것이 가장 효율적인가에 대해 많은 고민을 했던 것 같다. 그 과정에 멘토님께 질문을 드린 결과 프로젝트의 정체성에 맞게 실시간성을 강조하는 것은 좋지만, 각 페이지 별로 서버에 부담이 가지 않는 선에서 각각 다른 통신 기술을 사용하는 것도 좋은 방법이라고 말해주셨다.
- 전체 상품 페이지
전체 상품 페이지에는 한 페이지 당 총 10개의 상품이 나열되어 있다. 경매중인 상품에 입찰자가 존재하여 입찰을 시도했을 경우에는 전체 상품 페이지에 나열된 해당 상품의 현재 입찰가 또한 계속해서 변경되어야 한다. 여기에 만약 웹소켓 통신 기술을 사용한다고 가정해보자. 웹소켓은 HTTP와 달리 stateful한 프로토콜이기 때문에 서버와 클라이언트 간의 연결을 항상 유지해야 한다. 만약 많은 클라이언트가 동시에 해당 페이지에 접속할 경우, 트래픽 양이 증가하여 서버 리소스에 부담을 줄 수가 있다. 대규모 웹사이트나 애플리케이션에서는 이러한 트래픽 증가에 대응하기 위해 적절한 인프라와 네트워크 관리가 필요할 것이다. 우리는 서버 리소스를 고려하여 전체 상품 페이지에서는 웹소켓이 아닌 롱 폴링 기술을 적용하기로 했다.
- 상품 상세 페이지
상품 상세 페이지 같은 경우는 한 개의 상품 입찰가 영역에 대한 실시간 데이터 스트리밍을 요구하고 있다. 그래서 실시간으로 변경되는 부분을 웹소켓으로 구현하는 것이 적절하다고 판단했다.
@MessageMapping("/bid/{productId}")
@SendTo("/topic/bid/{productId}")
public ResponseEntity sendBid(@DestinationVariable("productId") Long productId, @RequestBody BidRequestDto request) {
try {
Product product = productService.updateCurrentAuctionPrice(productId, request);
Member member = memberService.getMemberById(product.getBuyerId());
...
return new ResponseEntity(bidResponseDto, HttpStatus.OK);
} catch (BusinessLogicException ex) {
BidErrorResponse bidErrorResponse = new BidErrorResponse(ex.getExceptionCode().getMessage(), request.getMemberId());
return ResponseEntity.badRequest().body(bidErrorResponse);
}
}
웹소켓은 양방향 통신을 지원하고 빠른 응답으로 데이터를 주고받을 수 있기 때문에 현재 상품을 입찰하려는 클라이언트로부터 요청 메시지를 받으면 해당 상품 페이지에 접속한 즉, 구독한 클라이언트들에게 메시지를 보낼 수 있게 코드를 구현했다. (사진 상으로 저 상품을 구경하던 누군가는 3,000원이던 상품이 5,000원으로 변경된 것을 볼 수가 있는것..이다!)
배운 점 / 느낀 점
지금까지 내가 접했던 프로젝트는 모두 학교에서 진행한 소규모 프로젝트였다. 처음으로 프론트엔트와 협업하면서 실제 서비스를 개발한다는 느낌을 받은 것 같다. 독학과 스터디를 통해 배웠던 건 하드 스킬이었지만, 프로젝트를 진행하면서 협업에 필요한 커뮤니테이션의 자세를 배울 수 있었다. 개발 도중 문제 상황에 직면했을 때 함께 모여 고민하고 해결하던 순간들은 나에게 큰 보람이었다.
- 자신감을 가지면 뭐든 된다.
사실 본격적으로 프로젝트에 들어가기 전에는 막연한 불안함과 걱정이 컸다. 나로 인해 팀원들에게 피해를 끼치면 어떻게 하지? 기대한 만큼의 결과가 나오지 않으면 어떻게 하지? 하는 생각들에 조금 위축되었다. 쏟아붓은 시간만큼의 퍼포먼스가 나오지 않아 좌절할 뻔한 순간들에 팀원들이 진심 어린 조언과 격려가 다시 자신감을 가질 수 있는 원동력이 되어줬다. 그렇게 담당한 기능을 성공적으로 구현하고, 에러를 고쳐나가면서 조금씩 성장하는 느낌을 받았다. 겸손과 위축된 자세는 한 끗 차이인 것 같다. 지금껏 내가 취한 자세는 겸손이었을까 위축이었을까? 그게 무엇이었던 간에 나 자신을 믿고 자신감을 가졌으면 한다.
- 리팩토링 하자.
정해진 기한 내에 프로젝트를 완성해야만 했기에 코드를 구현하는데 있어서 코드 로직 자체가 클린하다고 볼 수는 없었다. 테스트 코드는 개발에 정말 중요한 부분인데 이 또한 제대로 구현하지 못한 아쉬움이 계속 남는다. 그래서 희망하는 팀원들을 대상으로 구현해놓은 코드를 다시 들여다보고 수정하는 시간을 가져야겠다는 생각이 들었다.
수많은 시행착오가 있었지만 좋은 사람들을 만나 좋은 퍼포먼스를 보여줄 수 있어 너무나 뿌듯하고 보람있는 프로젝트 경험이 되었다. 함께 노력한 결과로 나름의 우수상을 받아 더욱 기억에 남는 프로젝트가 될 것 같다. 이 경험을 기억하며 계속해서 성장하는 개발자가 되어야겠다.
'Project' 카테고리의 다른 글
[PROJECT] PROJECT01- 상호 용돈관리 웹앱 (0) | 2023.02.19 |
---|