[데브툰] 프로젝트 기획부터 설계까지

2024. 4. 30. 15:32Project/데브툰

목차

프로젝트 기획

프로젝트 목표

프로젝트 기간 및 기술 스택

설계

  아키텍처 및 패키지 구조

  요구사항 분석

  ERD

  시퀀스 다이어그램

  와이어 프레임

회고

  만족한 점

  아쉬운 점

  다음에는 이렇게

 

프로젝트 기획

개발자 유머 짤들을 종종 보면서 재미있기도 하고, 개발자들끼리 대화할 때 사용하면 좋겠다는 생각이 들었다. 이런 재미있는 짤들을 한 곳에 모아 적재적소에 사용할 수 있는 플랫폼을 만들기로 했다. 이 플랫폼의 목표는 개발자들이 쉽게 유머 짤들을 찾고 즐기고 사용할 수 있도록 하는 것이다.

 

프로젝트 목표

요구사항 분석 후, 바로 개발을 시작하기 전에 각자 달성하고 싶은 목표를 명확히 정했다. 목표 기간에 비해 많은 시간을 투자했지만, 결과적으로 개발 도중 '나 지금 뭐 하는 거지?'라는 생각을 하지 않도록 도왔다.

 

나는 이번 팀 프로젝트의 목표를 다음과 같이 정했다: 

1. 프로젝트 기획 역량 기르기

2. 확장성을 고려한 시스템 설계 (객체 지향 설계 적용)

3. Git을 활용한 협업 경험

4. 리팩토링을 통한 설계 개선 및 성능 최적화

5. 단위 테스트 및 통합 테스트 진행

 

프로젝트 기간 및 기술 스택 

프로젝트 기간

2024.05.01 ~ 2024.05.15 (약 2주) + 계속적인 리팩토링 

 

기술 스택
java 21, springboot 3.2.5, gradle, MySQL, Docker

 

팀 구성원
백엔드 2명

 

설계

레이어드 아키텍처 채택

  • 하위 단에서 상위 단을 바라보면 안 됨.
  • controller → service → repository

패키지 구조

presentation(= controller)
application(= service)
infrastructure(= repository)
domain	
dto
  request
  response
constant

 

dto 패키지를 presentation 패키지와 분리. 만약 dto패키지가 controller패키지 안에 있었다면 application계층이 presentation를 바라보는 역방향 관계가 생김

 

요구사항 분석

최근 웹툰 플랫폼에 다양한 프로모션과 추가 요금 정책이 도입되고 있습니다. 새로운 할인 정책을 추가하고 삭제하는 정책 변경 작업에 유연하게 대응하는 시스템이 필요한 상황입니다.

웹툰을 미리 보기 위해서는 🍪쿠키가 필요합니다. 쿠키의 가격은 쿠키를 구매하는 개수나 회원 정보(등급)에 따라 가격이 다르게 책정됩니다.

 

필수로 구현해야 하는 API는 다음과 같습니다.

1. 쿠키 구매 시 요금을 계산하는 API(고려할 사항: 회원 등급, 쿠키 가격 정책, 쿠키 프로모션)

2. 미리 보기 결제 시 필요한 쿠키 개수를 구하는 API(고려할 사항: 회원 등급, 웹툰 장르, 쿠키 프로모션)

  • 웹툰 장르마다 필요한 쿠키 개수는 다르게 책정됩니다. 예를 들어, 판타지 장르 미리 보기 1편당 쿠키 4개, 스릴러 장르는 쿠키 3개 필요

3. 댓글 비속어 모니터링 및 회원 정지 API(고려할 사항: 비속어 누적 횟수)

  • 댓글에 사용된 비속어의 누적 횟수를 모니터링하여, 3회 이상 누적된 경우 회원에게 경고를 부여합니다. 경고상태인 회원은 모든 할인 프로모션 혜택을 받을 수 없습니다. (누적 횟수는 회사 정책에 따라 달라질 수 있다.)
  • 경고 대상인 회원이 추가적으로 비속어 누적 3회 적발되면 쿠키를 몰수당하고 영구 정지됩니다.

다음은 구체적인 프로모션, 쿠키 가격 정책, 회원 등급에 대한 내용이다.

더보기

1. 프로모션 ▷ 공통 로직은 인터페이스화 할 것

프로모션은 크게 두 종류가 존재한다. (Enum Type)

  • 쿠키를 구매할 때 현금 할인 = CASH_DISCOUNT
  • 웹툰을 구매할 때 쿠키 개수 할인 = COOKIE_QUANTITY_DISCOUNT

프로모션 속성  

1. 월간 프로모션(CASH_DISCOUNT)

예) 웹툰 출시 월(createdAt)에 쿠키 구매 시 10% 현금 할인

 

2. 장르별 프로모션(COOKIE_QUANTITY_DISCOUNT)

예) 7월에 스릴러 장르 웹툰 구매 시 개수 1개 할인

 

3. 구매 개수별 프로모션: 많이 살 수록 쿠키 가격 할인(CASH_DISCOUNT)

예) 10개 : 2,000원 / 30개 : 5,000원 / 50개 : 8,000원 / 100개 : 17,000원

 

4. 프리미엄 회원 할인(CASH_DISCOUNT)

예) 프리미엄 회원은 쿠키 구매 시 20% 할인 

 

5. 추가 할인 프로모션(CASH_DISCOUNT)

예) 이전 달에 50개 이상 쿠키를 구매한 회원은 다음 달 구매 시 추가 5% 현금 할인 적용

  • 이전 달 startDate ~ endDate내 쿠키 구매 내역 중 50개 이상만 가져와서 확인
  • isDiscountDuplicatable : ture → 5% 추가 할인 가능
    • 중복 할인 가능: 예를 들어, 프리미엄 회원이면서 이전 달 혜택을 받는 회원은 총 25% 할인 받음

2. 쿠키 가격 정책

기본 가격 1개 당 200원

 

3. 회원 등급

  • 등급 종류: 일반, 프리미엄
  • 프리미엄 승급 조건: 연속 3개월 동안 매달 50개 이상의 쿠키를 구매 시 자동 승급 처리

나는 여기서 쿠키 정책과 프로모션 등록, 쿠키 및 현금 결제, 그리고 리팩토링을 통한 개선 및 성능 최적화를 맡았다.


ERD 설계 

고민 사항

테이블을 분리한 이유는 무엇인가?

더보기

1. 결제

쿠키 결제(현금), 웹툰 결제(쿠기) 두 테이블로 나누었다. 관리 용이성을 위해 한 테이블로 가져가도 좋지만, 결제 수단도 다르고 정산 및 환불 이슈가 있을 때 대응하기 위함이다.

 

2. 프로모션

단일 테이블 → promotion(기본 프로모션 테이블), promotion_attributes(프로모션 속성 테이블)로 분리했다.

  • 기존) 한 테이블로 설계
    • 고민) 추후 여러 프로모션이 나오면 어떻게 테이블에 데이터를 저장하고 관리할 수 있을까?
  • 변경) 확장성 고민 → 두 테이블로 구분
    • promotion(기본 프로모션 테이블)로 기본 정보를 저장합니다. 프로모션 설명, 프로모션 타입, 시작 및 종료 날짜
    • promotion_attributes(프로모션 속성 테이블)은 프로모션 적용 대상과 값
      • attribute_name : 예) target_month, target_genre, premium_member_discount
      • attribute_value : 예) 5, horror, premium

3. 비속어

비속어 누적 횟수를 관리하기 위해 테이블 추가 생성하였다. 그리고 욕설, 비속어, 외설어 등을 포괄하기 위해 bad_words_warning으로 테이블 명을 정했다.

캐싱할 부분이 있는가?

더보기

프로모션 조회 캐싱

  • 선정 이유: 관리자만 수정 가능하므로 동시성 문제 없음, 일정 기간 동안 계산 로직에 적용하는 프로모션 조회 부분이 동일함
  • 업데이트 시점: 새로운 프로모션 등록 시

데이터베이스 설계 시 고려한 부분

더보기

1. nullable = false 적용: 삭제 시간 및 정책 종료 시간 제외

2. id → auto-increment, unsigned

  • auto-increment: 자동 증가
  • unsigned: 범위가 크고(약 42억) 음수가 들어갈 수 없음

3. quantity 제약 조건 설정: DB 단에서 quantity를 음수로 설정하지 않도록 제약 조건을 적용하여 안정성을 확보함 (비즈니스 로직과 DB 단에서 둘 다 검사)

  • CHECK (quantity >= 0) → try ~ catch문으로 예외처리 가능

4. 모든 필드를 VARCHAR(255)로 설정할 필요 없음

name 등의 필드를 적절하게 설정하고 비즈니스 로직에서도 제약 조건을 검증하여 안정성을 확보하고 불필요한 메모리 낭비를 줄일 수 있음

 

5. int대신 Integer 사용

  • int는 기본 자료형으로 null 값을 가질 수 없지만, Integer는 객체형 자료형으로 null 값을 가질 수 있음
  • Integer 클래스에는 parseInt, valueOf 등 유용한 메서드가 있음
  • 제네릭을 사용할 때 기본형 자료형을 사용할 수 없고, 객체형 자료형을 사용해야 함

연관관계 확인

JPA를 사용할 것이므로 모든 테이블을 단방향으로만 설계

  • 다가 주인이고 컨트롤하는 쪽, 상대 id를 가지고 있음 = 일 쪽에서 다 쪽의 데이터를 리스트로 가지고 있지 않음
  • 실무에서 양방향, 일대다 연관관계 사용하지 않음 - 무한참조 발생가능성 존재, 복잡성 감수할 필요가 없기 때문

[그림으로 확인]

 

최종 ERD

 

화면 설계

시퀀스 다이어그램

01234567

와이어 프레임

01234

회고

만족한 점

프로젝트 기간에 비해 기획 회의를 길게 진행했다. 목표를 명확히 정하고 이를 기획에 반영해야 추후 개발 진행 시 흔들림이 없을 것이라 생각했기 때문이다. 결론적으로 덕분에 의심 없이 개발을 쭉쭉 진행할 수 있었다.

 

아쉬운 점

기획 단계에서 당연하다고 생각해 지나친 부분들이 나중에 문제로 드러났다. 나는 확장성 있는 설계를 맡아 진행했는데, 프로모션 개발 시 개발 문서를 참고했지만 기획 당시 명확하게 적어두지 않아 이해하기 어려웠다. 그래서 다시 관련 문서를 보면서 시퀀스 다이어그램을 그리고, 가능한 모든 프로모션 예시를 들어 request와 response를 하나하나 적어가며 이해를 했고 위기를 넘길 수 있었다. 그러나 이 과정에서 시간을 지체했다는 아쉬움이 남았다.

 

다음에는 이렇게

기획 당시 당연하다고 생각하는 부분들도 명확하게 정리해야겠다. 반복적인 부분이라고 생각해 "이 정도는 나중에 기억나겠지? 이건 하지 말자"라는 생각은 접어두기로 했다. 시퀀스 다이어그램의 경우 나중에 추가했는데, 개발을 막힘 없이 진행하기 위해 기획 단계에서 작성해 두어야겠다.