5일동안 진행한 아웃소싱 프로젝트가 끝났습니다. 프로젝트에서 어디까지 진행되었고, 트러블 슈팅, 우리팀이 보여줄 만한 코드가 무엇이었는지 소개해드리겠습니다.
https://github.com/leetaegeon1/Spring26
-해당 프로젝트 Git Hub 주소-
프로젝트 개요
• 프로젝트 이름: 배달 어플 아웃소싱
• 주요 기능: 가게 관리, 주문 처리, 리뷰 작성, 메뉴 및 카테고리 관리
• 사용 기술 스택:
• Backend: Java, Spring Boot, Spring Security, JWT
• Database: MySQL
• 테스트: JUnit, Mockito, MockMvc
• 인증 및 권한 관리: JWT 기반 인증, Spring Security
프로젝트 주요 기능 설명
가게 관리
• 가게 등록 및 수정
• 가게 주인(OWNER)이 가게를 등록하고 수정할 수 있는 기능.
• 영업 시간, 최소 주문 금액 설정 및 변경 가능.
• JWT를 통해 가게 주인의 인증과 권한 확인.
• 가게 조회
• 사용자(USER)는 가게 리스트 및 세부 정보를 조회할 수 있음.
• 영업 시간 내에만 주문이 가능하며, 최소 주문 금액 이상만 주문이 가능.
주문 관리
• 주문 생성
• 사용자는 메뉴를 선택하고 가게에 주문을 생성할 수 있음.
• 주문 상태는 ‘ORDER_ACCEPTED’, ‘COOKING’, ‘DELIVERY’ 등으로 업데이트됨.
• 주문 시 JWT로 사용자 인증을 하며, USER 권한을 확인.
• 주문 상태 업데이트
• 가게 주인이 주문 상태를 변경할 수 있는 기능.
• 각 상태 변화에 따라 AOP를 사용해 로그 기록 및 알림 전송.
• 주문 조회 및 취소
• 사용자는 자신의 주문 목록을 조회할 수 있고, 일정 상태 전까지 주문을 취소 가능.
리뷰 관리
• 리뷰 작성
• 주문이 완료된 사용자는 해당 가게와 메뉴에 대해 리뷰를 작성할 수 있음.
• 리뷰는 ‘DELIVERY’ 상태의 주문에서만 작성 가능.
• 리뷰 수정 및 삭제
• 작성자는 본인의 리뷰를 수정하거나 삭제 가능.
• JWT를 통해 작성자 권한을 확인 후 수정 및 삭제 처리.
• 리뷰 상태 관리
• 리뷰의 공개/비공개 설정 기능.
• 관리자 권한을 가진 사용자만 리뷰 상태를 변경 가능.
메뉴 및 카테고리 관리
• 메뉴 등록 및 수정
• 가게 주인이 메뉴를 등록, 수정, 삭제할 수 있음.
• 각 메뉴는 특정 카테고리에 속하며, 메뉴의 기본 정보와 인기 여부를 관리.
• 카테고리 관리
• 메뉴를 카테고리별로 분류하여 조회 및 관리 가능.
트러블 슈팅
주문 상태에 따른 리뷰 작성 문제
• 문제: 주문 상태가 ‘DELIVERY’가 아닌 경우에도 리뷰가 작성되는 문제 발생.
• 원인: 리뷰 작성 시 주문 상태 검증 로직이 부재하거나 잘못 처리됨.
• 해결: 리뷰 작성 시 반드시 주문 상태가 ‘DELIVERY’일 때만 작성 가능하도록 검증 로직 추가.
MenuEntity의 boolean 기본값 문제
• 문제: MenuEntity에서 Boolean 타입의 popularity 필드가 NullPointerException을 발생시킴.
• 원인: 참조 타입 Boolean의 기본값이 null이기 때문에 초기값이 지정되지 않음.
• 해결: Boolean을 원시 타입 boolean으로 변경하여 기본값이 false로 설정되도록 처리.
주요 코드
MenuStatus
MenuStatus는 메뉴의 상태를 관리하기 위한 enum으로, 메뉴가 현재 가게에서 제공되는지 여부를 명확하게 구분하고 상태에 따른 처리를 일관되게 도와줍니다.
- AVAILABLE: 메뉴가 현재 판매 가능할 때.
- UNAVAILABLE: 메뉴가 일시적으로 판매 중단되었을 때.
- DISCONTINUED: 메뉴가 영구적으로 판매 종료되었을 때.
MenuController에서 API Response의 일관성 유지
API Response의 일관성은 클라이언트와 서버 간의 통신에서 매우 중요한 부분입니다. 일관성 있는 API 응답을 통해 클라이언트는 예측 가능하고 안정적인 방식으로 데이터를 처리할 수 있습니다.
일관성 있는 API Response의 장점
1. 클라이언트 측에서의 코드 관리 용이성:
일관된 API 응답 형식은 클라이언트 측에서 데이터를 처리하는 코드를 단순화하고, 재사용성을 높여줍니다. 예를 들어, 모든 성공 응답이 같은 구조로 제공된다면 클라이언트는 각기 다른 응답 형식에 맞추어 별도의 처리를 하지 않아도 됩니다.
2. 에러 핸들링의 통일성:
실패 응답도 일관된 형식으로 제공된다면, 클라이언트에서 예외 처리 로직을 한 곳에서 통합적으로 관리할 수 있습니다. 예를 들어, 모든 에러 응답이 status, message 필드를 포함한다면 클라이언트는 동일한 방식으로 에러를 처리할 수 있습니다.
3. 디버깅과 유지보수의 용이성:
서버와 클라이언트 간의 문제 발생 시 일관된 응답을 통해 문제가 있는 지점을 쉽게 파악할 수 있습니다. 클라이언트 측에서 예기치 않은 응답 구조가 오면 바로 해당 요청의 문제를 쉽게 발견할 수 있게 됩니다.
4. 확장성:
API가 일관된 응답 구조를 가지고 있다면, 새로운 기능이 추가되거나 확장될 때도 기존의 구조를 유지할 수 있어 쉽게 확장할 수 있습니다.
결론적으로 일관성 있는 코드가 좋은 이유가 무엇인가요?
- 코드 가독성 및 유지보수성 향상: MenuStatus와 같은 enum을 사용함으로써 코드에서 상태 전환이 명확해지고, 상태 변경 로직의 일관성이 유지됩니다. 이는 코드의 가독성을 높이고 유지보수가 쉬워집니다.
- 클라이언트와의 원활한 통신: MenuController에서 일관성 있는 API 응답을 제공함으로써 클라이언트가 데이터를 효율적으로 처리하고 에러 핸들링을 일관되게 수행할 수 있습니다. 이는 개발자의 생산성을 높이고 시스템의 확장성을 향상시킵니다.
- 오류 방지 및 디버깅 용이성: 상태 관리에서 오타나 잘못된 상태값을 입력할 가능성을 줄이고, 디버깅 시 문제를 빠르게 찾을 수 있습니다.
최종 ERD
엔티티 설명
1. User (사용자)
• User는 가게 주인 또는 고객일 수 있습니다.
• 주요 필드:
• id: 고유 식별자 (PK)
• email: 사용자 이메일
• password: 암호화된 비밀번호
• role: 사용자 역할 (고객, 가게 주인 등)
2. Restaurant (가게)
• Restaurant는 가게 정보를 관리합니다.
• 주요 필드:
• id: 고유 식별자 (PK)
• name: 가게 이름
• minDeliveryPrice: 최소 배달 금액
• openTime, closeTime: 영업 시간
• owner: 가게 주인 (User와 N:1 관계)
• 관계:
• 하나의 User는 여러 Restaurant을 가질 수 있습니다. (1:N 관계)
• 하나의 Restaurant는 여러 Order, Menu를 가질 수 있습니다. (1:N 관계)
3. Menu (메뉴)
• Menu는 가게에서 제공하는 메뉴 정보입니다.
• 주요 필드:
• id: 고유 식별자 (PK)
• name: 메뉴 이름
• price: 메뉴 가격
• status: 메뉴 상태 (AVAILABLE, UNAVAILABLE, DISCONTINUED)
• restaurant: 해당 메뉴가 속한 가게 (Restaurant와 N:1 관계)
• 관계:
• 하나의 Restaurant는 여러 Menu를 가질 수 있습니다. (1:N 관계)
• 하나의 Menu는 하나의 Category에 속합니다. (N:1 관계)
4. Category (카테고리)
• Category는 메뉴가 속하는 분류입니다.
• 주요 필드:
• id: 고유 식별자 (PK)
• name: 카테고리 이름
• 관계:
• 하나의 Category는 여러 Menu를 가질 수 있습니다. (1:N 관계)
5. Order (주문)
• Order는 고객이 한 주문 정보입니다.
• 주요 필드:
• id: 고유 식별자 (PK)
• orderStatus: 주문 상태 (ORDERED, COOKING, DELIVERED 등)
• orderTime: 주문 시간
• totalPrice: 총 주문 금액
• user: 주문을 한 사용자 (User와 N:1 관계)
• restaurant: 주문한 가게 (Restaurant와 N:1 관계)
• 관계:
• 하나의 User는 여러 Order를 가질 수 있습니다. (1:N 관계)
• 하나의 Restaurant는 여러 Order를 가질 수 있습니다. (1:N 관계)
6. Review (리뷰)
• Review는 주문 후 남긴 리뷰 정보입니다.
• 주요 필드:
• id: 고유 식별자 (PK)
• content: 리뷰 내용
• rating: 평점
• status: 리뷰 상태 (작성됨, 수정됨 등)
• order: 해당 리뷰가 작성된 주문 (Order와 1:1 관계)
• user: 리뷰를 작성한 사용자 (User와 N:1 관계)
• restaurant: 리뷰 대상이 된 가게 (Restaurant와 N:1 관계)
• 관계:
• 하나의 Order는 하나의 Review만 가질 수 있습니다. (1:1 관계)
• 하나의 Restaurant는 여러 Review를 가질 수 있습니다. (1:N 관계)
• 하나의 User는 여러 Review를 남길 수 있습니다. (1:N 관계)
ERD 다이어그램 요약
User ---< Restaurant
User ---< Order ---< Restaurant
User ---< Review ---< Order ---< Restaurant
Restaurant ---< Menu ---< Category
주요 관계:
1. User와 Restaurant: 1:N (한 사용자가 여러 가게를 소유할 수 있음)
2. Restaurant와 Menu: 1:N (한 가게는 여러 메뉴를 가질 수 있음)
3. Restaurant와 Order: 1:N (한 가게는 여러 주문을 받을 수 있음)
4. User와 Order: 1:N (한 사용자는 여러 주문을 할 수 있음)
5. Order와 Review: 1:1 (한 주문에 대해 하나의 리뷰만 작성 가능)
6. Menu와 Category: N:1 (여러 메뉴가 하나의 카테고리에 속함)
커버리지 테스트
KPT 회고
Keep - 현재 만족하고 있는 부분
- 주문 상태에 따른 리뷰 작성 제한 로직 강화
• 리뷰 작성 가능 여부를 배달 완료 상태인 ‘DELIVERY’에서만 가능하게 한 로직이 성공적으로 적용되었습니다. 이를 통해 신뢰성 있는 리뷰 시스템을 구축했으며, 이 부분은 지속적으로 유지할 필요가 있습니다.
• 또한 테스트 코드에서도 해당 로직을 검증하여 오류를 사전에 방지할 수 있었습니다.
- 통일된 API 응답 처리
• ApiResponse 객체를 통해 일관성 있는 응답 처리가 가능해졌습니다. 이를 통해 클라이언트 측에서 응답을 처리하는 데 혼란이 줄었고, API의 신뢰성을 높였습니다.
• 앞으로도 일관된 응답 구조를 유지하면서 필요한 확장이 있을 경우, 이에 맞춰 개선할 수 있을 것입니다.
- Menu 상태 관리의 효율성
• 메뉴 상태를 Enum 값(AVAILABLE, SOLD_OUT, DELETE)으로 관리하여 하나의 컬럼으로 메뉴의 품절 및 삭제 상태를 처리한 부분이 매우 효율적입니다. 이는 메뉴 상태 관리를 일관성 있게 유지하면서, 데이터베이스 관리에도 용이함을 제공했습니다.
Problem - 불편하게 느끼는 부분
- 리뷰 작성 로직에서의 상태 검증 부족
• 주문 상태가 ‘DELIVERY’가 아닌 상태에서도 리뷰가 작성되는 문제를 겪었습니다. 이는 상태 검증 로직이 불완전했던 것이 원인이며, 초기부터 상태를 철저히 검증하지 못한 점이 있었습니다.
• 문제를 발견한 후 로직을 수정했으나, 검증 로직이 모든 주문 상태에 대해 명확히 적용되지 않았던 부분은 추가적인 테스트와 확인이 부족했다는 것을 반영합니다.
- Boolean 필드 기본값 문제
• MenuEntity의 popularity 필드에서 Boolean 참조 타입을 사용해 발생한 기본값 미설정 문제가 있었습니다. 기본값이 설정되지 않아 등록 과정에서 예상치 못한 에러가 발생했으며, 이를 원시 타입으로 변경해 해결했지만 초기 설계에서의 데이터 타입 선택에 대한 고려가 부족했습니다.
Try - Problem에 대한 해결책, 당장 실행 가능한 것
- 주문 상태 관리 로직의 고도화
• 현재는 리뷰 작성 가능 상태만 ‘DELIVERY’로 제한하고 있지만, 다양한 주문 상태에 대해 더 명확한 로직을 추가하여 주문 처리 및 상태 관리의 복잡성을 줄일 수 있을 것입니다. 예를 들어, 주문 취소 상태나 배달 실패 상태에 대한 구체적인 로직을 추가하는 것을 시도해볼 수 있습니다.
- 테스트 커버리지 확대
• 주문 상태나 메뉴 상태와 같은 핵심 로직에 대한 테스트 커버리지를 확대할 필요가 있습니다. 특히 리뷰 작성과 같은 중요한 기능에 대해 더 많은 상황을 고려한 테스트 시나리오를 작성하여 미처 발견하지 못한 오류를 사전에 방지할 수 있도록 해야 합니다.
• 또한, 각종 예외 처리에 대한 테스트도 강화하여 시스템이 안정적으로 작동하는지 확인하는 절차를 추가해야 합니다.
- 데이터베이스 설계에 대한 사전 검토 강화
• Boolean 필드 기본값 문제를 해결하면서 데이터베이스 설계에 대한 중요성을 다시 한번 느꼈습니다. 앞으로는 데이터 타입을 선택할 때 기본값 설정 여부를 명확히 하고, 이에 대한 검증 절차를 프로젝트 초기에 강화할 필요가 있습니다.
• 추가적으로, 필드 타입의 적절성을 고민하는 과정에서 데이터 무결성과 성능을 고려한 최적화를 시도할 수 있습니다.
나의 회고
오늘은 프로젝트의 **주문(Order)**과 리뷰(Review) 상태 관리를 마무리하는 중요한 날이었다. 처음엔 간단할 거라고 생각했던 이 작업이 예상보다 훨씬 복잡했다. 주문 상태 변화와 리뷰 작성 조건이 시스템 안정성에 큰 영향을 미친다는 사실을 깨닫게 되었고, 이를 제대로 구현하기 위해 많은 고민과 수정이 필요했다.
특히 어려웠던 건, 주문이 가게의 영업 시간 내에만 가능하도록 설정하는 부분이었다. 실시간으로 처리해야 하는 상황이라 LocalDateTime.now()를 사용했는데, 테스트 환경에서 일관성 있게 시간을 처리하는 것이 만만치 않았다. 테스트마다 시간이 달라져 버리니, 원하는 대로 검증이 되지 않아서 답답했다.
하지만, 문제는 결국 해결했다! 명시적인 시간 설정으로 테스트 코드를 개선하고, 가게의 영업 시간 로직을 세밀하게 검증하는 방법을 찾았다. 그 결과, 주문 처리 로직이 안정화되었고 사용자 실수나 시스템 오류를 방지할 수 있었다. 이 부분을 해결했을 때는 정말 뿌듯했다.
리뷰 기능에서도 예상치 못한 문제가 있었다. 원래 계획은, 배달이 완료된 주문에 대해서만 리뷰를 쓸 수 있도록 하려는 것이었다. 하지만 처음 구현한 코드에서는 주문이 완료되지 않았는데도 리뷰가 작성될 수 있었고, 이로 인해 데이터의 일관성이 깨질 수 있는 상황이었다. 만약 제대로 된 검증 없이 리뷰가 작성되면, 잘못된 피드백이 가게의 평가에 영향을 줄 수도 있었다.
그래서 주문 상태가 ’배달 완료(DELIVERY)’일 때만 리뷰를 쓸 수 있도록 로직을 다시 강화하고, 여러 테스트를 통해 확인했다. 테스트를 통해 모든 것이 제대로 작동하는 걸 확인했을 때, 한시름 놓을 수 있었다. 이 과정에서 리뷰 시스템의 신뢰성을 크게 향상시켰다는 자신감이 생겼다.
이번 프로젝트를 통해 많은 문제를 직면했지만, 그중에서도 가장 기억에 남는 건 시간 검증 로직과 상태 관리 일관성이다. 주문이 가게의 영업 시간 내에 이루어져야 하는데, 처음엔 이 로직이 제대로 작동하지 않았다. 영업 시간 안에만 주문을 허용하는 검증 로직을 수정하며 시간 데이터를 다루는 방법에 대해 더 깊이 배울 수 있었다. 특히, 실시간 데이터를 어떻게 처리하고 검증할지에 대해 새로운 시각을 얻게 되었다.
또한, 주문 상태와 리뷰 상태의 일관성을 유지하는 것이 얼마나 중요한지 깨달았다. 처음에는 각각의 상태를 개별적으로 처리하다 보니, 코드가 일관되지 않았고 관리하기도 어려웠다. 이를 해결하기 위해 상태 전이 로직을 명확히 하고, 가능한 작업들을 제한하면서 오류 발생 가능성을 줄였다. 그 결과, 코드의 가독성과 유지보수성이 크게 향상되었다.
이번 프로젝트를 통해 가장 크게 얻은 것은 비즈니스 로직에 대한 깊은 이해와 이를 기술적으로 구현하는 능력이다. 주문과 리뷰 흐름에서 데이터의 일관성을 유지하는 것이 시스템에 얼마나 중요한지 다시 한 번 느꼈다. 다양한 문제를 해결하며 내 기술적 역량뿐만 아니라 비즈니스 로직을 설계하고 분석하는 능력도 함께 성장했다.
그리고 무엇보다도, 테스트 코드의 중요성을 실감했다. 테스트는 단순히 기능을 확인하는 것이 아니라, 시스템의 안정성을 보장하는 데 필수적이라는 것을 깨달았다. 이번 프로젝트에서 테스트 코드를 강화하면서, 예상치 못한 문제를 사전에 발견하고 해결할 수 있었다는 점에서 큰 만족감을 느낀다.
이번 프로젝트를 성공적으로 마쳤지만, 여전히 개선해야 할 부분들이 남아 있다. 특히 상태 관리 로직의 확장성에 대해 더 고민해봐야 할 것 같다. 주문과 리뷰 상태만 고려했지만, 향후 시스템이 복잡해질 때도 유연하게 대처할 수 있는 구조로 만들어야 할 것 같다.
오늘 프로젝트를 돌아보면서 내가 겪었던 어려움과 그 과정을 해결해나가는 순간들이 기억에 남는다. 프로젝트를 통해 정말 많은 것을 배웠고, 비즈니스 로직과 기술적 역량을 모두 성장시킬 수 있었다. 앞으로도 이런 경험을 토대로 더 나은 개발자가 되기 위해 노력해야겠다.
'Spring > 미니 프로젝트(배달)' 카테고리의 다른 글
미니 프로젝트(배달 어플 아웃소싱) (0) | 2024.09.19 |
---|