카카오 프렌즈 골프를 클로닝해보았다

Jun·2021년 5월 23일
3

클론프로젝트

목록 보기
1/1
post-thumbnail

지난 2주간 카카오VX의 골프 관련 굿즈를 판매하는 사이트, 카카오 프렌즈 골프를 클로닝해보았다.

클론 프로젝트는 2주간 진행되었고, 프론트엔드 4명, 백엔드 2명으로 이루어진 팀이 함께 합을 맞추었다.

나는 백엔드 파트를 맡았으며, 모델링부터 장바구니 기능 구현까지 Django와 함께 보낸 흥미로운 2주를 여기 정리해보고자 한다.

타겟 사이트를 분석해보자

사실 클론 프로젝트 타겟을 고를 때, 백엔드의 입장에서 후보군을 살펴보니 그리 튀는 선택지가 존재하지는 않았다. 실시간으로 DB 업데이트가 많이 일어나야 하는 어렵거나 구현하기 힘든 기능들 있는 사이트는 처음부터 제외해서 그랬던거 같다.

그럼에도 불구하고 카카오 프렌즈 골프는 흥미로운 클론 타겟이다. 아래는 내가 느낀 카카오프렌즈 골프 사이트가 가진 특징이다.

  1. 제품의 캐릭터별 분류가 중요하게 작용하는 쇼핑몰이다.


    기성 골프 제품을 판매한다기 보다는 카카오 프렌즈 캐릭터가 들어간 굿즈를 판매하는 쇼핑몰이 이 쇼핑몰의 아이덴티티이다.
    그만큼 각 제품에 특정 캐릭터가 반드시 들어가있으며 캐릭터별 분류와 유저의 특정 캐릭터 선호도에 따른 추천이 무척 중요해보였다.
    이를 방증하듯, 회원가입시에 선호하는 프렌즈 캐릭터도 선택해야 한다.

  2. 쇼핑몰에 블로그와 프로모션 페이지가 따로 달려있다.
    메인페이지와 동떨어진 다른 카테고리로 골프 제품에 대한 블로그와 이벤트 프로모션 페이지가 따로 달려있었다. 우리팀의 목적은 쇼핑몰 기능의 구현이었기에 이부분은 클론 타겟에서 제외하기로 했다.

백엔드 구현의 시작은 모델링

카카오 쇼핑몰에 보이는 데이터를 기반으로 구현에 필요한 DB 테이블을 모델링 하고 그것들 간의 관계를 생각했다.
모델링 한 결과 테이블이 유저에 대한 부분 / 상품에 대한 부분 / 주문에 대한 부분으로 크게 세 갈래로 나뉘었다.
가장 중요한 세 가지 테이블만 소개해보자면,

유저 테이블


유저 테이블은 기본적으로 유저에 대한 정보를 담고 있으며, 유저가 선호하는 캐릭터를 담을 수 있게 캐릭터 테이블과 연결된다.

상품 테이블


가장 중요한 상품 테이블은 상품 기본 정보 / 가격 / 할인이나 이벤트 여부 / 연계된 캐릭터 / 매진 / 할인율과 같은 정보를 모두 포함한다.
우리는 서브카테고리를 상품에 달고, 서브카테고리 테이블이 또 메인 카테고리 테이블을 가리키게 모델링 했는데, 이 부분 때문에 나중에 View 로직을 짤 때 조금 힘이 들었다.

주문 테이블


주문 관련 모델링을 하는 부분이 사실 가장 고민을 많이 하게 만들었다.
처음에 장바구니와 주문 관련 데이터를 어떤 식으로 구성해야 할 지 감이 안와서 시간을 많이 쓰다가, 결국 위의 사진처럼 세 테이블로 나누고 그들간의 관계를 설정해 두었다.

  • 주문의 상태(장바구니에 들어감 | 구매중 | 구매됨)를 담는 order_status 테이블
  • 주문의 정보(구매자, 주소, 전화번호, 주문상태)를 담는 orders 테이블
  • 존재하는 주문들을 담는 order_lists 테이블

위와 같이 나누어 관리해주면 주문의 상태 변경 - 주문 자체의 정보 변경 - 주문의 추가 및 삭제를 독립적으로 수행할 수 있어 효율적이다.

API 구조 설계하기

본격적으로 View 로직을 구현하기 전에 우리가 구현할 API의 전체적인 구조를 설계하였다.
위의 DB 모델을 크게 세 부분으로 나누었듯, API 엔드포인트도 세 부분으로 나누어 진행하기로 했고, 최대한 Restful하게 설계하려 노력했다.
너무 미리 세세하게 설계하기 보다는 커다란 필요 기능과 관련 HTTP 메서드로 각 엔드포인트를 정의했다.

Users API

POST /users/signup

  • 유저의 회원가입시 도달하는 엔드포인트
  • 회원가입에 필요한 정보를 JSON으로 전달받고, 검증한 후 결과값을 반환한다.

POST /users/signin

  • 유저가 로그인시 도달하는 엔드포인트
  • 아이디와 패스워드를 JSON으로 전달받고, 검증한 후 로그인 성공시 Json Web Token을 반환한다.

Products API

GET /products?cname=&search=&offset=&limit=

  • 상품을 리스트 형태로 받고 싶을 때 사용한다.
  • 쿼리파라미터 형태로 상품의 카테고리 / 서브카테고리 / 캐릭터 이름 / 검색어 / 페이지네이션과 관련된 정보를 받아와 처리해서 조건에 해당하는 상품만 내어준다.

GET /products/<id>

  • 각 상품의 상세 정보를 알고 싶을 때 사용한다.
  • 상세 정보를 JSON 형식으로 반환한다.
  • 유효한 JWT가 헤더에 포함되어있을 시, 해당 유저가 상품을 좋아하는지 여부를 반환한다.

PATCH /products/<id>

  • 유저의 해당 상품을 좋아하는지 여부를 토글해준다.

Orders API

장바구니 API는 설계할때 특히 고민을 많이 했는데 그 이유는 다음과 같다.

  • 주문 상태 변화의 갈래가 바로 구매 또는 장바구니 구매로 두 가지이다.
  • 유저가 구매를 다 마치지 않고 이동할 경우, 장바구니 구매의 경우는 장바구니로 롤백되어야 하고, 바로 구매의 경우 삭제되어야 한다.
  • 장바구니는 계속해서 업데이트 가능해야 한다.

결과적으로 아래와 같은 상태 관리 로직을 염두해 두고 API 구조를 짠 후 View 로직을 작성하기 시작했다.

GET /orders?orderType=

  • 유효한 JWT가 헤더에 포함되어 있을 시 유저의 주문 리스트에서 해당 주문 타입에 맞는 주문 리스트를 가져다준다.

POST /orders

  • 새로운 상품을 장바구니에 담거나 바로 구매하기를 눌러 주문하기 페이지로 간다.
  • 담을 상품 리스트와 상품의 주문 타입을 JSON 형식으로 받는다.

PATCH /orders

  • 주문 리스트에 있는 상품의 상태를 업데이트 한다. (예를들어, 장바구니에 있는 상품 -> 주문중인 상품 -> 구매한 상품)

View 로직 구현

위에서 Aquery Tool을 통해 설계한 테이블을 Django를 통해 구현한 후에는 각 API에 해당하는 View 로직과 각각 필요한 헬퍼 함수 또는 데코레이터를 작성했다.
여기에서는 전체 코드 중 기억에 남는 코드를 소개해보고자 한다.

Products 모델의 get_info 메서드

ProductListView와 ProductDetailView를 동료와 함께 작성하다보니, 공통적으로 각 상품의 상세 정보를 연계된 여러 테이블에서 긁어와 예쁜 딕셔너리 형태로 변환해 줄 일이 잦다는 것을 알게 되었다.

하지만 경우에 따라 다른 키가 필요할 때가 있었고, 또, User가 존재할 경우 추가적인 키 값을 넣어 줄 때가 있었다.

각 경우에 일반적으로 대응 가능한 메서드를 만들기 위해 제외할 키 값을 exclude에 리스트 형태로 받고, 유저 정보가 있다면 받아서 처리 가능한 메서드를 위와 같이 구현했다.

login_required 클래스 메서드 데코레이터

이 데코레이터는 View 클래스의 메서드에 붙여서 request 헤더에 token이 존재하는지 검사해준다.
더불어, 토큰 유효성과 유저 유효성에 대한 예외 검사까지 데코레이터와 함께 처리할 수 있어 메인 코드가 매우 깔끔해질 수 있어서 좋았다.

참고로 일반 데코레이터와는 달리 세 겹으로 함수가 싸여있는데, 이는 클래스 메서드에 붙이기 위해 아래와 같이 django의 method_decorator와 함께 쓰기 위함이다.

모델의 unique 필드 중복 검사 validator 함수

이 부분은 일반적으로 Django 모델에서 중복되면 안되는 unique 속성을 갖는 필드의 중복성을 자동으로 검사해주는 함수를 구현한 것이다. (오버엔지니어링이고 가독성이 똥망이라는 평을 받긴 했지만) 나름 Django 모델의 하부 메서드를 뒤져가면서 만들어낸 기능이라 빼고 싶지 않아 고집부리며 머지시켰다.

이 함수는 어떤 모델과 데이터를 받아, 모델에서 중복될 수 없는 unique 필드를 자동으로 찾아낸 후, 이러한 비 중복 필드의 값이 DB에 존재하는지 검사하고, 만약 존재한다면 예외를 발생시킨다.

이와같이 Django 모델 클래스의 _meta 밑으로 들어가면 생각보다 일반적으로 많이 쓸 수 있는 메서드와 기능이 많아 흥미로웠다.

프론트엔드와 함께 일하기

프로젝트 동안 팀은 애자일의 스크럼 개발방법론을 따라 개발을 진행했다.
따라서 매 주 시작일에 함께 Backlog를 작성하며 한 Sprint 내에서 해결할 목록을 작성했다.
또, 매일 아침에 Scrum meeting을 가지며 진행 상황을 서로 추적하고 Blocker를 확인하며 우선순위를 조절했다.

나는 개인적으로 구현되는 API를 최대한 상세하게 문서화해서 FE 팀원들에게 제공하고 실시간으로 업데이트해 FE 개발을 돕고자 하는 작은 목표가 있었다.

이를 위해 두 가지를 실천했다.

Postman을 통한 API 문서화 및 공유

Postman에 무료 Team을 개설하고 (3명까지 무료) 툴을 가지고 백엔드 팀원과 함께 같은 API 문서를 함께 작성할 수 있었다. 또, 퍼블리싱 툴을 통해 체계화된 API 문서를 아주 쉽게 만들어 낼 수 있었다.

문서화된 API는 옆에 쿼리 예시까지 둘 수 있어서 특정 경우에 어떤 API 에러가 전달되고, 또 어떤 방식으로 API를 써야 하는지 FE에게 그나마 쉽게 전달해 줄 수 있었다. (하지만 이 툴이 실제로 프론트 동료들에게 충실히 도움이 되었는지는 잘 모르겠다. 내 생각엔 팀 내에서의 툴 공유는 툴에 대한 교육이 선행되어야 하는 것 같다.)

개발 서버 작동 및 실시간 업데이트

아무래도 백엔드와 프론트엔드가 같은 시작점에서 함께 개발되다보니, FE는 백엔드 엔드포인트가 메인에 머지되거나 할 때까지 기다리면서 목업데이터를 만들어 써야 하는 불편함이 있었다.

이를 조금이라도 해소해주고자 나는 dev 브랜치를 따로 파서 merge를 기다리는 PR을 미리 merge 시키고 이를 AWS Light Sail에 미리 호스팅해 개발 API 서버를 팀원들에게 따로 제공했다.

이 부분은 유효하게 FE팀원들에게 도움이 되었던 것 같아 돌아보니 기쁘다.

또, dev 브랜치를 유지 관리 한 점은 나의 git 사용 능력을 많이 향상시켜 주었고, 새로운 기능 개발 시 PR을 넣기 전에 미리 테스트를 하고 PR을 넣어 리뷰어의 번거로움을 조금 줄여줄 수 있는 것 같아 다음에도 이 방법을 쓰고자 한다.

애로사항들

저작권과 데이터

프로젝트 진행하면서 내가 만난 가장 큰 Blocker는 아무래도 저작권과 데이터에 대한 부분이었다.

클론 프로젝트이고, 아무래도 캐릭터 특화 굿즈 판매 쇼핑몰이라는 특성을 살리고자 하니, 카카오 프렌즈 캐릭터 자체의 저작권은 물론이고 그것이 붙어있는 굿즈마저 클론 사이트에 가져오지 못하는 엄청난 벽이 있었다.

그렇다고 아무 사진이나 들고 붙이자니, 성에 차지 않았다.

우리는 그래서 일단 저작권이 없는 최대한 귀여원 캐릭터를 골라와, 목업 이미지 생성을 도와주는 사이트에서 캐릭터가 붙은 상품을 최대한 많이 만들었다.

또, Python의 Faker 라이브러리를 통해 Fake 유저와 제품 이름 및 특성을 생성하였다.

이를 csv 파일로 저장하고 다시 DB에 Populate 시키는 코드를 만들어 빠르게 목업 데이터 변화를 실제 DB에 적용할 수 있게 했다.

소통은 문서 기반으로 하되, 문서만 준다고 끝이 아니다.

FE와의 소통에서 나는 API 문서를 만드는데 시간을 많이 썼지만, 그 효용은 그렇게 높지 않았다.
나는 앞으로 팀 내 문서화에 신경 쓰는 만큼 그것을 설명하는 시간 또한 그만큼 할당해야만 문서가 빛을 발한다는것을 배웠다.

마무리하며

처음으로 타인과 함께 개발 협업을 진행한 2주간 코드 자체를 떠나 배운 것들은 정말 값진 것들이 많았다.

  1. Git을 통한 협업은 사실 그렇게 어렵지 않다. 제대로 알고 쓰는 git 명령어는 두려운 것이 아니라 너무나 효과적이고 재밌는 것이다.

  2. 개발은 키보드로만 하는 것이 아니다. 설명하고 이해하고 이해시키는 부분이 최소 30% 이상은 차지한다. 개발자는 오히려 사회적이고 남이 모르는 부분을 잘 캐치하고, 또 내가 모르는 부분을 잘 질문할 수 있는 능력을 가져야만 수행할 수 있는 직업이다.

  3. 개발자 간의 소통은 감정을 배제하고 로직에 충실할 때 빛이 난다. 서로간에 합당한 근거 제시와 수긍이 있다면 어떤 Blocker도 함께 넘어갈 수 있다.

Special Thanks to.. KOKOA TEAM

프론트엔드
백엔드
profile
개발합니다.

2개의 댓글

comment-user-thumbnail
2021년 5월 25일

저작권 때문에 진짜 고생 많으셨어요 🥲 해결 방법 듣고 대단하다 생각했었는데
최종 발표 때 사이트 보고 👍👍👍 역시 갓준식 짱짱! 남은 2차도 화이팅입니당!!

1개의 답글