상품 피드 1차 개선 — Python 에서 Java 로!

Kahee Yu
29CM TEAM
Published in
8 min readFeb 21, 2021
N 쇼핑사에서 최저가 검색

사고자 하는 물건이 있을때 다들 어디서 어떻게 구매 하시나요? (저는 당연히 29CM 😍) 포털 사이트에서 상품 검색후 최저가를 먼저 알아보시는 경우가 대부분이실텐데요. 한번쯤 위 상품 정보들이 어떻게 관리되고 있는지 궁금하지 않으셨나요? 오늘은 이 상품 정보들이 어떻게 관리되고 29CM가 가지고 있던 어려움을 어떻게 해결했는지 이야기 해보려합니다.

상품 피드란 무엇인가?

네이버 지식 쇼핑과 같은 포털 쇼핑몰에 노출하고 싶은 상품 정보를 모아놓은 텍스트 파일을 ‘상품 피드’ 라고 합니다. 배치를 통해 주기적으로 29CM의 상품 정보를 업데이트한 후 해당 파일을 S3에 업로드 합니다. 제휴 쇼핑몰 측에선 등록된 URL을 통해 해당 피드 정보를 반영하는 것입니다.

29CM 이 겪고 있던 문제 😢

  • 입점한 브랜드들이 많다 보니 브랜드 또는 상품마다 제휴 쇼핑몰에 노출하고자 하는 니즈가 달랐습니다. 예를 들어 A 브랜드 상품 전체는 모두 비노출 하고 싶거나 B 브랜드 상품은 특정 쿠폰 적용을 원하는 것과 같은 다양한 요구사항이 있습니다. 시스템 개선 전까지는 이러한 요구사항을 스프레드시트로 관리하고 개발자가 수동으로 업데이트하고 있었습니다.
  • 또한 일부 상품들은 최저가 계산이 정확하지 않았습니다

이러한 문제가 있음에도 불구하고 여느 회사와 마찬가지로 우선순위 높은 업무들이 생겨나면서 개선작업이 밀리고 있었습니다.

개선전 Fabrica 프로젝트

Fabrica 는 네이버 지식 쇼핑, 인스타그램, 페이스북 등 다양한 제휴 사이트에 29CM 상품을 노출하기 위해 피드를 생성하는 프로젝트입니다. 그림에서처럼 한 번의 쿼리를 통해 상품 피드에 필요한 모든 정보를 가져오는 방식입니다.

잘렸지만… 정말 기나긴 쿼리

DB 커넥션을 최소화 하기 위한 방법이었으나, 이 쿼리는 300줄이 넘는 쿼리였어요 😱

  • 결과적으로 무언가를 새롭게 추가하거나 문제 발생 시, 쿼리를 파악하는 데 드는 비용과 장기적으로 유지보수가 어렵다고 판단하였습니다.
  • 요구사항이 복잡해지면서 이를 빠르게 처리하기 위해 특정 제휴 쇼핑몰 또는 상품만을 위한 하드코딩도 많이 있었습니다.

이런 상황에서 ‘기존 프로젝트를 수정하여 개선하는 것이 맞는가?’ 에 대한 고민이 있었습니다. 당시 29CM 은 monolithic 구조를 MSA(Microservice Architecture) 로 전환하면서 개발 언어도 Java 로 전환하자는 결정을 하였습니다. 그래서 신규 서비스의 경우 Java + Spring 조합으로 구현하자는 원칙이 있었습니다. 이에 따라 개발자가 수기 처리하고 있던 부분을 어드민을 통해 관리할 수 있게 하고, 정확한 상품 계산을 하는 것을 목표 상품 피드 프로젝드도 Java 신규 프로젝트로 이관하게 되었습니다.

초보 자바 개발자

무한 반복되는 심정

학부생 이후로 Java를 사용하지 않았음에도, 신규 프로젝트를 Java 로 구현하자고 결정했을 때에는 ‘그래 해보자'라는 근거 없는 자신감을 가지고 있었습니다. 그러나 프로젝트를 시작하고 나니 어떤 것부터 어떻게 이관해야 할지 막막해지는 순간이 많았습니다. 그때마다 동료가 복지인 29CM 팀원들의 도움으로 차근차근 Java로 이관해나가기 시작했습니다.

복잡해도 너~무 복잡했던 쿼리 안녕 ✋

도메인 단위로 나누면서 훨씬 간단해진 로직

아까 보셨던 300줄 넘는 쿼리는 10개가 넘는 테이블을 조인하고 있었습니다. 조인을 최소화하여 도메인별로 해당 쿼리를 분리하였고, 각 서비스 레이아웃에서 상품 ID를 기준으로 조회를 하고 데이터를 조합하도록 변경하였습니다. (애플리케이션 간의 레이아웃이 궁금하시다면 ‘선물하기 서비스 개발기’ 를 참고해주세요. 😃)

아무래도 상품 수가 많다 보니 쿼리 실행 시간이 길어 문제가 되는 구간들이 있었습니다. Querydsl은 메소드 기반 형태로 컴파일 시 타입을 체크하여 오류를 발견할 수 있는 이점이 있으나, 일부 도메인의 경우 성능을 위해 네이티브 SQL을 사용하였습니다.

또한 사용할 쓰레드 수를 미리 할당하고 테스크와 쓰레드를 관리하는 Executor 를 이용하여 해당 작업을 병렬처리로 변경하였습니다. 데이터를 조회하고 조합하는 부분만 10분이 넘게 걸렸었는데,약 4분 정도로 단축 시킬 수 있었습니다.

정확한 최.저.가 계산

무엇이 무엇이 똑같을까 상품가격이 똑같지요! (왼쪽: N사 쇼핑에 있는 29CM 상품 / 오른쪽: 29CM 상품 페이지)

상품에 적용 가능한 모든 쿠폰을 가져온 후 정확한 최저가 계산이 가능하게 되었습니다. ‘너무 당연한 이야기 아니야?’라고 하실 수도 있지만, 이전 로직의 경우 DISTINCT 조건으로 모든 쿠폰을 사용한 가격 계산이 아니었기 때문에 최대 할인 금액이 정확하지 않았습니다.

가장 어려웠던 부분은 적용 가능한 쿠폰이 무엇인지 판단하는 것이었습니다. 입사한 지 얼마 안 되어 쿠폰 도메인을 정확하게 알지 못했는데요. 그로 인해 수십번의 삽질로 많은 시간을 허비했습니다. 최종적으로는 29CM 쿠폰 비즈니스 로직을 그대로 적용하면서 정확한 상품 가격을 노출 할 수 있게 되었습니다.

상품 노출 관리는 개발자가 아닌 어드민에서!

제휴 쇼핑 노출 관리 어드민 페이지

스프레드시트로 관리하던 브랜드/상품 노출의 경우 19년 말부터 20년도 5월까지 수기처리한 데이터만 무려 1,285건 정도였습니다. 담당자는 바로 처리되지 않아 답답해했고, 이를 매번 수기로 업데이트 하는 개발자는 지쳐갈 수밖에 없었습니다. 그러나 해당 데이터를 관리할 수 있는 신규 테이블을 생성하고, 이를 이용하여 어드민에서 상품 담당자들이 직접 제휴 상품 노출을 관리할 수 있게 되었습니다.

마무리

프로젝트 초기 동료 개발자의 말을 빌려 Python 을 자유주의라고 한다면 Java 는 공산주의라는 고정관념이 조금(?)은 있었습니다. 그러나 프로젝트를 진행하면서, 정적 타입 언어에 대한 이점도 명확하게 알 수 있었고 ‘Python이 낫다, Java가 좋다’ 는 언어적 측면의 이점보다는 신규 프로젝트를 생성하여 문제를 해결한 점에서 많은 이점을 얻었다고 생각합니다.

  • 우선 개선이 시급했던 네이버 쇼핑 피드만 Java 로 이관하였기 때문에 기존 상품 피드들에 영향을 주지 않고 작업을 할 수 있었습니다.
  • 상품 피드 생성에 대한 전체 흐름을 코드로 파악할 수 있게 되었습니다. 이는 다음에 요구사항이 추가되거나 변경되어도 비교적 빠르게 대응이 가능합니다. 그 예로 크리테오 피드가 있었는데요. 최근 30일 이내 구매 및 장바구니 담은 상품으로만 피드를 구성해달라는 요구사항이 있었습니다. 기존 300줄 이상의 쿼리로 구성된 프로젝트였다면 많은 시간이 필요했겠지만, 도메인별로 분리가 잘 되어 있는 신규 프로젝트였기 때문에 일주일도 안 되어 새로운 기능을 추가 할 수 있었습니다.
  • 기존 가격 불일치 문제가 해결되었습니다. 구매를 하는데 있어 가장 중요한건 가격이라고 생각합니다. 그렇기에 이번 프로젝트에서 가장 중점적으로 고치고 싶었던 부분이었습니다.

물론 아쉬운 점도 있었습니다. 개선전 Fabrica 프로젝트로 전체 상품 피드를 생성하는 데 10분이 소요되었다면, Java로 이관하면서 약 7분 정도가 소요됩니다. 기대했던 것보단 실행시간을 많이 단축하지 못한 점이 아쉬웠습니다.

이런 부분이 배포 이후에도 계속 마음에 걸렸었는데 약 3개월 뒤, 21년 1월에 아쉬움을 개선할 수 있는 기회를 갖게 되었습니다. 이에 대한 이야기는 상품 피드 2차 개선 내용으로 블로그를 통해 조만간 이야기해드릴게요!

[함께 성장할 동료를 찾습니다]

29CM ((주)무신사)는 3년 연속 거래액 2배의 성장을 이루었습니다.
이제 더 큰 성장을 위해 기존 모놀리틱 서비스 구조를 마이크로서비스 구조로 전환하고, 앵귤러 기반 프론트엔드 코드를 리액트로 전환하는 등의 기술적인 시도를 진행하고 있습니다. 모바일 앱 내부 구조도 모듈러 아키텍처로 개선하는 과정에 있습니다. 함께 성장하고 유저 가치를 만들어낼 동료 개발자분들을 찾습니다.

🚀 29CM 채용 페이지 : https://www.29cmcareers.co.kr/

--

--