[Project] WeeteWeete

임종성·2021년 8월 14일
10

Project

목록 보기
6/7
post-thumbnail

Wecode Foundation이 끝나고, 개발자로서 처음으로 2주동안 6명이 한 팀이 되어 MoteMote라는 커머스 사이트를 클로닝하는 그룹 프로젝트를 진행하여 성공적으로 프로젝트를 마치게 되었다. 지난 2주를 돌아보며 이 회고록에 프로젝트의 구체적인 내용을 담아보자.

WeeteWeete

MoteMote Cloning Project

[Project Schedule]

  • 2021/08/02 ~ 2021/08/13

[Project Member]

  • Frontend - 최호정, 차예은, 배윤아, 이나현,
  • Backend - 임종성, 백선호

[Project Github Link]

[Project Video Link]
https://www.youtube.com/channel/UCRIz9IqAEF9-2KyafzJaCoA

1st Sprint

프로젝트 첫 날, 조 편성이 발표되고 우리는 모두 모여 함께 모트모트 사이트를 살펴보고 필수 구현사항과 추가 구현사항, 개선사항들을 설정하고 트렐로를 이용해 일정을 정리했다. 실제 웹사이트를 보고 어떤 부분에서 어떤 기능을 구현해야 하는지 감이 잘 안잡혔었는데, 백엔드 동기인 선호님이 리드해서 어느정도 가닥을 잡게 되었다.

[초기 계획 필수 구현사항]

  • 로그인/회원가입
  • 메인/메뉴 페이지
  • 상품 상세 페이지
  • 장바구니
  • 상품 구매
  • 결제기능

[초기 계획 추가 구현사항]

  • 마이페이지
  • 주문 조회 기능
  • 상품 구매후기
  • 검색 기능
  • 반응형 웹사이트

기본적으로 커머스 사이트로서 필수적인 기능 중 우리가 구현 가능하다고 생각한 사항을 필수로 넣고, 나머지는 추가/개선사항에 넣었다. 사실 장바구니도 추가 구현사항에 있었지만, 멘토님이 필수로 구현하라고 하셔서 수정하였다. 1차 스프린트에서는 필수 구현사항을 모두 완료하고, 2차 스프린트에서 추가 구현사항을 진행하기로 계획했다.

이제 어느정도 계획이 잡혔으니, 남은 것은 초기세팅을 완료하고 Database Modeling을 하며 개발을 시작하는 것이었다!

Database Modeling

선호님과 함께 MoteMote 사이트를 살펴보고, 어떤 ERD로 Modeling해야할지 고민하며 아래와 같이 Database Modeling을 완료했다.

위의 ERD는 프로젝트가 모두 완료되었을 때의 ERD지만, 실제로는 몇 번의 수정을 거쳤다. 예를 들어 Status와 OrderStatus의 경우 원래는 존재하지 않았지만 상품 주문의 상태를 결정하기 위한 Table이 필요하다는 멘토님의 조언으로 생성하였고, Price와 Discount등 가격에 관한 Field를 Integer에서 Decimal로 수정했다.

다음 프로젝트 때는 따로 ERD 수정과정을 기록하여 어떻게 Modeling을 완료했는지 확인해야겠다.

FindMember & NewPassword View

Bcrypt 암호화와 JWT를 이용한 기본적인 로그인/회원가입과 인증/인가 뿐 아니라 사용자의 편의를 위해 아이디를 찾아주고 임시 비밀번호를 생성하는 기능을 구현했다.

원래 SecretString Module을 이용해 임시 비밀번호를 생성했는데, Code Review를 통해 uuid를 사용해서 비밀번호를 재생성해주기로 했다.

QueryParameter로 상품 Filtering 정보와 MainPage 여부를 전달받고 그에 따라 Main이면 전체주문량 상위 8개 상품 list를, 아니라면 Category별로 Filtering한 상품 list를 전송하는 기능을 구현했다.

처음에는 MainPageView와 MenuPageView로 나누어 기능을 작성했는데, 멘토인 연우님의 조언으로 삼항연산자를 사용해 두 개의 View를 합쳐서 작성했다.

Order & Purchase View

상품을 주문할 경우 Buy Button을 누르면 상품정보와 Status가 Order Table에 생성되고, 결제 페이지로 이동되어 Status가 결제대기중인 상품만 표출한다. 그리고 결제를 하게되면 결제한 상품의 Status를 결제완료로 Update하고 주어진 Data에 맞게 상품의 재고, 주문량, 사용자의 Point를 Update하는 기능을 구현했다.

OrderStatus

초기 OrderView를 구현할 때, 사실 Modeling에 OrderStatus는 없었다. 그런데 기능을 구현하다 보니 구매를 할 시 상품의 상태정보가 필요하다고 느끼고 Modelinㅎ에 추가했다.

Bulk_Create

상품 주문은 각각 상품 상세 페이지와 장바구니 페이지에서 할 수 있는데, 상세 페이지에서는 단일 상품을 주문하고 장바구니에서는 장바구니의 모든 상품을 한번에 주문하기에 is_cart라는 Query Parameter를 받아 For문을 이용해서 OrderItem을 생성했었다.

그런데 병민님의 조언으로 Bulk_Create를 이용해 상품의 id만 Query Parameter로 받고 삼항연산자로 id가 없으면 Cart의 정보를 request.user를 통해 받아 OrderItem을 생성했다.

Transaction

PurchaseView를 작성하고 PostMan으로 테스트를 하는데, 미리 테스트용 Order를 생성해두지 않거나 코드에 사소한 오타가 있어 오류가 몇번 발생했다. 그런데 그렇게 테스트를 마치고 사용자 정보를 확인해보니 Point가 급격하게 줄어있는 것을 확인했다.

알고보니 사용자의 Point가 차감되어 DB에 영향을 준 후에 에러가 발생하여 제대로 모든 Query문 처리가 안되었는데도 불구하고 Point는 계속 줄어든 것이었다.

이렇게 여러 개의 Query를 실행할 경우 하나의 Query Process처럼 동작하여 치명적인 오류가 발생하지 않도록 Transaction을 적용했다.

다행히 Django에는 자체적인 Transaction Decorator가 있어 바로 적용해주었다.

After 1st Sprint

프로젝트를 통해 협업능력소통능력을 키우고 싶었는데, 생각만큼 쉽지 않다는 것을 느꼈다. 조금 더 세세하게 계획을 짜고, 서로의 업무에 대해 제대로 이해하고 소통하는 것이 중요하다고 생각했다.

1차 스프린트에서는 원래 마무리하기로 했던 필수 구현사항 중 장바구니는 모두 구현하지 못했다. 사실 각 기능을 코딩하는 시간은 그리 길지 않았지만, Github을 이용해 PR을 올리고 수정 및 Merge하는 과정에서 꽤 많은 시간이 투자되었다.

그리고 프론트와 틈틈히 구체적인 기능과 서로 요청 및 반환해야 하는 Value에 대해서 소통하는 과정에서 불협화음은 없었지만 자잘한 시간소모가 있었다. 아무래도 프로젝트에서 초기에 구현해야 하는 기능에 대해 구체적으로 정하지 않고 그때그때 소통하며 제대로 기록도 하지 않다보니, 서로 이야기 했던 부분에 대해서도 "어? 그때 이렇게 정하지 않았나요?"라거나 "이건 어떻게 하기로 했죠? 아직 안정했죠?"와 같이 소통이 미흡한 느낌이 강하게 들었다.

2nd Sprint

Sprint Meeting을 하면서 지난 Sprint에서 구현했던 것과 하지 못했던 기능, 앞으로 진행할 내용들에 대해 이야기했다. 계획했던것 보다 진행상태가 좋지 않아 수요일까지 장바구니, 상품후기 까지 구현하고 나머지는 깔끔하게 날려버리기로 했다! 많은 기능을 구현하는 것은 물론 좋은 일이지만, 하나라도 제대로 된 기능을 구현하는 것이 개발역량을 더 발전시킬 수 있다고 생각했다.

[필수 구현사항]

  • 로그인/회원가입
  • 메인/메뉴 페이지
  • 상품 상세 페이지
  • 장바구니
  • 상품 구매
  • 결제기능

[추가 구현사항]

  • 마이페이지
  • 주문 조회 기능
  • 상품 구매후기
  • 검색 기능
  • 반응형 웹사이트

Cart C.R.U.D

구매를 원하는 상품을 장바구니에 담는 기능을 구현했다. 상품 상세 페이지에서 Add Cart 버튼을 통해 장바구니를 생성하는데, 이미 장바구니에 상품이 존재할 경우 수량을 변경해준다. 장바구니 페이지에서는 수량 변경과 삭제가 가능하다.

실제 모트모트 페이지에서의 수량변경은 상세 페이지에서 Add Cart를 눌렀을 경우 장바구니에 이미 상품이 존재하면 "장바구니에 이미 존재합니다. 수량을 추가하겠습니까?"라는 모달이 오고 "예"를 누르면 수량이 변경되는 구조였다.

그래서 Cart에 Item이 존재하면 Error Message를 반환해서 프론트가 이를 이용해 Modal을 띄울 수 있도록 로직을 구현했다. 하지만 프론트에서는 모달을 준비하지 않은 상태였고, 모달 없이 진행하는 것이라고 생각하고 있었다.

나는 너무도 당연히 실제 사이트처럼 구현이 될거라고 생각하고 로직을 짰는데, 실제로는 그렇지 않다는 것을 그때서야 제대로 깨닫게 되었다. 처음에는 프론트가 4명, 백엔드가 2명이어서 인원이 적은 백엔드가 빠르게 빠르게 기능을 구현해야 제대로 맞출 수 있을거라고 생각했는데, 프론트의 레이아웃과 기능 구현이 생각만큼 쉽지 않고 시간이 오래걸리는 작업이라는 것을 알았다.

무엇보다 1주일이 넘는 시간동안 같이 프로젝트를 진행했는데, 프론트와 정말 소통이 없었다는 것을 알았다. 어떤 페이지에서 구체적으로 어떤 기능이 필요하고, 이 버튼을 누르면 어떤 기능이 구현되는지, 페이지를 표출하는데 어떤 값들을 반환해줘야 하는지 등등.. 서로 연관된 기능을 구현하는데 제대로 된 소통없이 내 할 일만 하고있었다.

이런 로직같은 경우 백엔드인 내가 판단해서 프론트에게 "~~를 누르면 ~~를 반환하고 ~~로 넘어가야 합니다"와 같이 미리 소통했어야 하는데, 프로젝트를 제대로 진행하지 못한다는 느낌이 들었다.

안그래도 프론트는 페이지를 구현하느라 정말 바빠보였는데.. 뜬금없이 와서 이제서야 "모달에서 예, 아니오가 뜨고 예를 눌러야 수량이 변경됩니다. 모달 구현했죠?" 라고 하니 얼마나 황당했을까?

아무튼 그렇게 이야기를 하고, 미안한 마음에 조금이나마 프론트 부담을 덜기 위해 Add Cart를 눌렀을 경우 장바구니에 이미 상품이 존재하면 POST Method에서 PATCH Method로 넘어갈 수 있게끔 조치했다. 이 부분은 나중에 꼭 Refactoring해서 제대로 구현해야겠다고 생각했고, 무엇보다 다음부터는 꼭 프론트와 소통을 구체적으로, 자주 해야겠다고 마음먹었다.

Review View

상품 상세 페이지에서 상품 후기를 볼 수 있으며, 구매한 사용자만 상품 후기를 적을 수 있도록 구현했다. 상품 후기를 작성하며 이미지 파일을 upload 할 수 있도록 했는데, 이는 Form Data로 받아 Static File 경로로 저장하여 Request에 Server에 저장된 경로를 url로 반환하도록 했다.

Form Data

처음에 호정님이 상품후기 기능을 구현하면서 이미지 파일을 올릴 수 있도록 할거라고 했다. 우리는 아무생각없이 평소 했던대로 Image를 CharField로 지정하고, request.body를 이용해 Data를 받았다. 그런데 프론트와 통신하는 과정에서 자꾸 unicode decode 관련 에러가 떴다.

처음에는 프론트쪽 문제라고 생각했다.. POSTMAN으로 쏠 경우 정상적으로 기능이 작동하는데 프론트랑 통신하면 에러가 났기 때문이다. 그런데 성훈님?이 오셔서 확인하니 Form Data가 아니라 Json data로 받고 있어서 오류가 났다는걸 알게 되었다.

문제를 알고 난 후, request.POSTrequest.FILES를 이용해 파일을 받았고, 그제서야 에러 없이 정상적으로 Review POST가 기능했다!

Static File

그런데 문제는 여기서 끝이 아니었다. 일단 Data를 받는데는 성공했지만, 상품 상세페이지에서 후기를 표출하기 위해 우리가 Data를 보내줄 경우 제대로 전송이 안되어 자꾸 엑박이 떴다. 처음에는 Image를 ImageFiled로 변경하고 저장한 DB값 그대로 image_url을 전송하는데 자꾸 Json Serialize가 불가능하다는 에러메시지를 띄웠다..

이를 해결하기 위해 저녁 먹기 전부터 집에 가는 10시까지 어떻게 하면 제대로 data를 전송할 수 있을까?를 생각하며 여러방면으로 시도했다. 그러던 중 static file을 관리하는 것에 대해 조언을 듣고 settings.pyweeteweete/urls.py 까지 세세하게 수정하며 이미지 파일을 다운받는 경로를 설정했다.

집으로 돌아와서도 자기전 제대로 된 url주소를 프론트에게 보내주기 위해 rest_framework 패키지를 받고Serializer를 만들어 FileType Data를 Json Data로 return하도록 했다.

다음날 아침, 우여곡절 끝에 엑박이 아닌 사진을 띄우면서 제대로 된 기능 구현에 성공했다. 사실 중요했던 것은 1. 이미지 파일을 서버의 지정된 경로에 저장 2. 파일이 저장된 서버의 경로를 Front에게 정확히 전달하는 것, 이 두 가지였다. 알고보면 Serializer를 쓸 필요 없이 그냥 FileType의 image_url Field를 image_url.name으로 바꾸면 해결되는 것이어서 Serializer는 제외했다.

프로젝트를 진행하며 몇 번 벽에 부딪혔는데, 그 중 최대 난관이 바로 이 Form Data를 다루는 것이었다. 알고보니 보통 2차 프로젝트에서 다루는 문제고 이렇게 선행하는 경우는 별로 없다하여 기분이 더 좋았다.

End of Project

2차 스프린트에서 장바구니, 상품 후기까지 무사히 구현한 후 최종발표 전까지 프론트와 지속적으로 통신하며 오류를 해결하고, 기능을 간소화하며 코드를 조율했다. 모든 통신이 제대로 작동하는 것을 확인하고, 프론트와 백엔드 각각 발표할 내용을 PPT로 정리하여 물흐르듯 최종발표를 진행했다! 다 끝났다고 생각하니 정말 맘이 편했고, 한편으로는 2차 프로젝트가 기다려지고 설렜다.

체크 리스트를 통해 프로젝트의 목표를 이해하고 달성했는지 살펴보자.

스크럼

Trello를 활용한 스크럼 방식은 이번에 처음 진행해봤다. 프로젝트에서 구현하는 기능을 크게크게 나누는 것은 나쁘지 않게 되었지만, 중간발표에서 다른 팀의 스크럼 방식과 트렐로를 살펴보니 우리(백엔드)의 스크럼 방식이 매우 미흡하다고 생각했다. 2차 프로젝트를 진행할 때는 각 기능을 세부적으로 나누고, 구체적으로 내용을 작성해야겠다.

Standup Meeting

미팅은 항상 정확히 코드카타가 끝난 11시에 이루어졌다. PM인 나현님을 필두로 하여 트렐로를 참고하여 In-Progress와 Done에 대해 이야기하고, 프론트-백엔드 간 소통이 필요한 점에 대해 이야기했다. 항상 모두가 참여하고 적극적으로 진행된 것 같다.

Communication

Cart 부분에서도 언급했지만, 프론트와의 소통이 너무 미흡했다. 그때그때 필요할 때 찾는 것이 아닌, 미리 구체적인 방향으로 소통을 진행했어야 한 것 같아서 아쉽다. 반대로 백엔드인 선호님과의 소통은 너무너무 잘되서 오히려 과했다는 느낌이 들 정도였다. 백엔드 파트너 선정을 정말 잘 해주셨다고 느낀것이, 선호님이 불같은 느낌으로 프로젝트를 달려간다면 내가 옆에서 차가운 물로 진정시키는 역할을 수행했다. 아무래도 내가 부족하다고 느낀 것이 기능을 구현할때 먼저 머리속으로 정리를 하고나서 늦어지는 실행능력이었는데, 선호님이 내 단점을 덮어주는 느낌이 들었다. 함께 했을때 시너지가 잘나오다 보니 기능 구현을 사실상 둘이 함께 한 느낌이 들고, 2차 프로젝트 때는 좀 더 분업을 할 필요성이 있는 것 같다.

Git

Branch를 활용하고 적절한 commit, push, stash를 활용했다고 생각한다. 그런데 백엔드끼리의 branch 분업이 잘 안되었고, conflict를 피하기 위해 hard coding과 같은 맥락으로 프로젝트를 진행했기 때문에 2차 프로젝트에서는 제대로 Git을 활용해야겠다.

문제 해결 능력과 Q&A

처음 보는 에러나 오류를 마주치고 어려운 로직을 구현하는 경우 문제를 해결하는 능력은 부족함이 없다고 생각한다. 오류가 발생하면 침착하게 에러 메시지를 살펴본 후 어디가 문제인지 찾아볼 수 있고, 기능 구현에 있어서도 시간이 걸릴 수 있지만 적절한 검색과 질문을 통해 문제를 해결할 수 있었다.

Backend

Restful API는 경험을 통해 제대로 구현할 수 있을 것 같고, Database 구조와 Django의 기본개념에 대해서는 어느정도 충분히 이해했다고 생각한다. 그렇다고 완전히 이해한 것은 아니고 심화 개념을 공부하기로 마음먹었다.


돌이켜보니 2주라는 시간이 정말 빠르게 지나갔다. 처음 프로젝트 팀이 선정되고 모였을때만 해도 사전스터디를 함께한 윤아님을 제외하고는 가끔 인사만 할 뿐 교류가 없던 팀원 뿐이었다.

생각해보면 프로젝트를 성공적으로 끝마칠 수 있었던 것은 한 명도 빠짐없이 열정적으로 프로젝트에 임했던 팀원들이 있기 때문이 아닌가 생각한다.

PM으로서 역할을 충실히 수행하고 스크럼을 진행해주신 나현님

프론트에서 기둥 역할을 맡고 많은 기능 구현을 리드한 호정님

프로젝트 전 개인사정으로 1주일을 참여하지 못해 그만큼 노력하는 모습이 돋보인 윤아님

자신이 맡은 역할을 수행하기 위해 최선을 다하는 모습이 눈에 보였던 예은님

그리고 백엔드 파트너로서 항상 함께 행동했던 선호님

모두가 자기 위치에서 제 할일을 했기에 모두가 만족할만한 결과물이 나왔고, 개발자로서 더욱 더 동기부여가 된 프로젝트였다. 앞으로도 이 분들과 함꼐 프로젝트를 진행할 수 있으면 좋겠다고 생각한다.

profile
어디를 가든 마음을 다해 가자

10개의 댓글

comment-user-thumbnail
2021년 8월 15일

비밀번호 찾기에 사용하신 uuid 는 저도 다음 프젝에서 활용해보고 싶네요!-!
생생한 후기 잘 읽었습니다!!!

1개의 답글
comment-user-thumbnail
2021년 8월 15일

고생 많으셨어요 종성님 🧚🏻‍♀️

1개의 답글
comment-user-thumbnail
2021년 8월 16일

종성님 짱짱:) 너무 고생많이하셨습니다!!!

1개의 답글
comment-user-thumbnail
2021년 8월 17일

종성님과 함께할 수 있어서 좋았습니다!!! TOKKEN은 잊지못할거에요...ㅋㅋㅋㅋㅋㅋ

1개의 답글
comment-user-thumbnail
2021년 8월 17일

코드 창 이미지는 어떻게 만드신건가요? 그냥 스크린샷은 아닌것 같은데 참고하고 싶습니다 ㅎㅎ

1개의 답글