그냥 단순하게 코드만 작성해서 혼자 http를 날리면서 테스트 해볼때보다 백엔드가 해야할 일이 무엇인지 조금이나마 더 이해가 되었다.
백엔드로 정하고 나서 python을 공부하기 시작했을때까지만 해도 솔직히 백엔드가 데이터를 다루긴 다룬다는게 뭘 어떻게 다뤄서 어떻게 써먹는다는건지 이해가 잘 안됐었는데.. 역시 백문이 불여일견!!
프로젝트를 한번이라도 진행하고 나니깐 장고의 flow가 조금이나 더 잘 이해가 되었다.
💡 이번 우리 팀이 구현한 기능!
로그인, 회원가입, 상품리스트, 상품들 카테고리 페이지, 상세페이지, 장바구니
이 중에서 내가 맡은 부분은 상품들의 리스트를 보여주는 api를 구현하는 것이었다.
처음 상품 리스트를 보여주는 코드를 짰을때, category 별로 하나 subCategory 별로하나, 메인페이지를 위한 할인율을 기준으로 또 하나 등등.. 기능별로 path parameter를 사용해서 각각의 api로 구현하려고 하니 똑같은 코드들이 반복되기만 했다. 또 for을 중첩으로 사용하다보니 가독성이 많이 떨어졌다..
이를 위한 해결책으로 query string과 list comprehension을 사용했다.
class ProductListView(View):
def get(self, request):
category = request.GET.get('category', None)
sub_category = request.GET.get('sub_category', None)
pick = request.GET.get('pick', None)
discount = request.GET.get('discount', None)
new = request.GET.get('new', None)
if category:
q &= Q(sub_category__category__name=category)
if sub_category:
q &= Q(sub_category__name=sub_category)
products = Product.objects.filter(q)
if pick:
products = products.filter(sub_category__category__name=pick)[:4]
if discount:
products = products.order_by('-discount_rate')[:6]
if new:
products = products.order_by('-created_at')[:4]
result = [{
'id' : product.id,
'created_at' : product.created_at,
'name' : product.name,
'image_url' : [product_image.image_url for product_image in product.productimage_set.all()],
'original_price' : int(product.get_real_price()['original_price']),
'real_price' : int(product.get_real_price()['real_price']),
'discount_rate' : int(product.discount_rate),
} for product in products]
return JsonResponse({'result': result}, status=200)
처음에 이 언더바 두번을 몰랐을때 한테이블에서 참조하는테이블로 한번 그리고 또 그 테이블을 참조하는 테이블에 있던 field 값과 비교할려고 shell에 얼마나 많이 쳐봤는지 모른다.. 그거 하나려고 정말 300번은 넘게 쳐봤던것같다.
지금 생각해보면 참 무식했던것같다. 그냥 구글에 검색 한번 해보지!! 하나에 꽂히면 꼭 답도 없이 그 하나에만 몰두 하는 편인데 그날이 그랬다.. 집에가는 버스에서도 오기가 생겨서 shell에 계속계속 쳐보기만 했던것같다... 결국 내 방식대로 해냈지만 더 좋은 방법이 있었고... 지금 그 코드를 다시보면 헛웃음밖에 나오지 않는다..
class FilterView(View):
def get(self, request):
category = request.GET.get('category')
sub_category = request.GET.get('sub_category')
filter = request.GET.get('filter')
q = Q()
if category:
q &= Q(sub_category__category__name=category)
if sub_category:
q &= Q(sub_category__name=sub_category)
products = Product.objects.filter(q)
if filter:
if filter == '최신순':
products = Product.objects.order_by('-created_at')
if filter == '낮은가격순':
products = sorted(products, key=lambda x: x.original_price)
if filter == '높은가격순':
products = sorted(products, key=lambda x: x.original_price, reverse=True)
result = [{
'id' : product.id,
'created_at' : product.created_at,
'name' : product.name,
'image_url' : [product_image.image_url for product_image in product.productimage_set.all()],
'original_price': product.get_real_price()['original_price'],
'real_price' : int(product.get_real_price()['real_price']),
'discount_rate' : int(product.discount_rate),
} for product in products]
return JsonResponse({'result': result}, status= 200)
def get_real_price(self):
if self.discount_rate == 0:
return {'real_price': self.original_price,
'original_price': int(self.discount_rate)}
else:
return {'real_price': self.original_price * decimal.Decimal(str(1 - self.discount_rate/100)),
'original_price': int(self.original_price)}
상품들을 가격순, 신상품순으로 필터링을 해주어야 하는 기능이 필요했는데, 이 기능은 나중에 꼭 한번 리팩토링을 하고싶다.
우리는 모델에서 할인퍼센트와 원래 가격을 가지고 미리 계산을 하는 함수를 만들어서 그걸 view에서 호출시켜서 최종 가격을 구할 수 있도록 했다. 그래서 정렬할때도, 할인율이 있다면 모델에서 호출한 함수를 호출해서 할인된 가격순으로 정렬을 하고 싶었는데, 내가 잘못 생각해서 지금 위의 코드에서도 결국, 할인가가 먹힌 상태가 아니고 할인률이 있어도 할인되지 않은 원래 가격을 기준으로 정렬이 되었다.
리팩토링을 할때는 꼭 더 생각해서 모델의 함수를 이용해서 가격별 필터링 기능을 구현하고 싶다.
프로젝트를 통해 프론트와의 소통이 얼마나 중요한지 이번에 알게 되었다.
프론트랑 처음으로 같이 프로젝트를 진행하다 보니 서로 무슨 말을 하는지 이해가 안될때도 종종 있었다.
그래서 자꾸 자꾸 듣다보면 하나라도 더 이해가 되는 순간이 오겠지? 하는 생각때문에 우리 팀은 프론트,백엔드가 서로 무슨 말을 하는지 몰라서 이해 못해도 우선은 다 같이 있는 곳에서 이야기 하자! 라고 다짐했다. 우선, 프론트엔드끼리 무슨말을 하는지 이해가 되지 않아도 그 이야기들을 듣고 있으니깐 프론트엔드가 어떤점이 힘들고 어느 부분이 어렵구나.. 하는 점들을 자연스럽게 알게되니깐 서로서로 배려하는것이 가능해졌다.
프론트와의 소통이 얼마나 중요한지 한번 더 깨닫게 된 계기
category랑 subcategory의 이름들에 대한 데이터를 누가 가지고 있을것인가? 에 대한 되게 사소한 문제였는데 이때의 일이 참 기억에 남는다.
우리 팀은 프론트와의 회의를 통해서 백엔드 쪽에서 데이터를 보내주기로 결론은 지은 상태였는데, 백엔드 멘토님들이 오셔서 이거를 왜 우리한테 보내달라하지..? 프론트에서 하드 코딩하는게 더 나을 것같은데..라고 하셔서 프론트 멘토님들께 여쭤보면 백엔드에서 보내주는게 더 나을것같다! 라고 하시니 어느게 정답인지 모르겠어서 더 혼란이 왔다..
결국, 이러한 문제들은 해결책이 없다는 사실을 알게되었다. 그냥 우리의 기획과 우리 팀에 맞도록 프론트와 소통하는것이 제일 중요한것같다. 아주 가벼운 이런 문제를 겪고나니 프론트와의 소통이 얼마나 중요한지 한번 더 깨닫게 되었고 프론트분들의 이야기를 한마디라도 더 주의 깊게 듣을려고 노력 했던것같다.
프로젝트를 하는 내내 우리 팀원들에게 고마웠다. 모르는점이나, 어려운 문제가 생기면 본인일처럼 나서서 설명해주고 같이 고민도 해주고 서로 배려해주려고 노력하는 모습덕분에 이주일 동안 서로 기분 안상하고 끝까지 잘 마무리 할 수 있었다.
솔직히, 처음 프로젝트를 시작할때는 너무 겁먹어서 내가 이런 부분까지 할 수 있을까? 하는 생각이 많이 들었었는데 2차 프로젝트때에는 조금 더 욕심을 내서 조금 더 많은 기능까지 구현해보고 싶다.
어떤 개발자가 되고 싶나요? 라는 질문을 했을때 '같이 일하고 싶은 개발자요'라는 대답을 여기 저기서 많이 봐었는데, 그때까지만 해도 그게 어떤 사람이지..? 라는 생각이 들고 가슴 속으로는 와닿지 않았었는데 이번에 프론트엔드 그리고 다른 백엔드 분들과 팀을 이루어서 프로젝트를 진행해보니 그 답을 개미 눈꼽만큼이라고 이해한것같다.
비록 짧은 경험이지만, 결국 내가 생각하는 같이 일하고 싶은 개발자란 소통이 잘되는 개발자인것같다.
그렇다면, 소통이 잘되는 사람은 어떤 사람일까?
예전부터 내 생각을 말하는것은 참 쉬운데 나와 의견이 다른 사람들의 말을 끝까지 잘 듣고 그것을 수용하는 것은 쉬운일이 아니라는 생각을 하곤했다. 그래서 나는 잘 듣는 사람이 되고 싶다.
나와 생각이 다른 사람들의 의견을 끝까지 잘 듣고 그 의견을 적극적으로 수용할 수 있는 말 그대로 잘 듣고 소통이 잘 되는 개발자가 되기 위해 노력하고 싶다.
지원님과 2주 동안 프론트와 백엔드의 소통 방식을 많이 배운 것 같아서 너무 좋았어요🥰 아이패드로 먼저 "이렇게 해볼까요?"하고 직접 작성해서 보여주시고 계속 소통하려는 지원님을 보면서 같이 일하고 싶은 개발자는 이미 되셨구나 싶었습니다ㅋㅋㅋ😎 지원님과 (맛있는 점심도 먹고)행복했어요ㅋㅋㅋ 저희 수료 후에 추가구현 때 또 소통 많이하고 맛집도 많이 가봐요!! 2주동안 정말 수고 많으셨어용!🙏