PickHound
구분 | 내용 |
---|---|
프로젝트명 | PickHound |
개발 기간 | 2022.08 ~ 현재 베타 서비스 중 |
가담 인원 (개발/비개발) | 4명/5명 |
개요
PickHound는 쉐퍼드23에서 개발한 Cafe24 온라인 쇼핑몰을 대상으로 하는 상품 추천 플러그인입니다.
Contextual Bandit에 기반해 팝업 배너를 통해 각 쇼핑몰의 상품을 사용자 개인의 선호, 취향 등을 고려한 개인화 상품 추천을 제공합니다.
베타 테스팅 단계를 거치고 있으며, 현재 60곳 이상의 실사용 고객사의 25k 가량의 쇼핑몰 방문객에게 상품 추천 서비스를 제공하고 있습니다. 서비스의 개발, 운영을 총체적으로 담당하면서, 심층 인터뷰 및 고객 데이터 수집을 통한 피드백 수집, 플러그인 및 추천 시스템 개발 및 유지보수, 서비스 운영을 진행하고 있습니다.
위와 같은 과업을 진행하며 현재도 수많은 기술적, 사업적 문제를 맞닥뜨리고, 이를 해결해나가는 과정에서 많은 배움과 성장을 얻고 있습니다.
Showcase
아래 링크에서 PickHound의 실제 서비스를 확인하세요.
아키텍쳐 개요도
아래는 작성자가 PickHound 서비스의 개발 계획을 세우면서 작성한 아키텍쳐 개요도입니다. 아래의 아키텍쳐 구조는 현재까지도 대부분이 유지되고 있습니다.
하위 프로젝트 개략
아래는 아키텍쳐 개요도의 각 프로젝트에 대한 개략적인 설명입니다.
Recomendation API
Recomendation API 는 Cafe24 API와 Firestore DB에서 정보를 읽어오고, 쇼핑몰 관리자와 쇼핑몰 방문객의 JS 클라이언트 (각각 Admin Dashboard 와 Banner Manager)를 위한 REST API를 제공합니다.
NestJS 로 개발되었고, 작성자가 API 일체를 개발했습니다. AI 팀이 웹개발을 전혀 다룰 수 없었기 때문에 굳이 Python 웹 프레임워크로 ML 모델을 포함하는 Monolithic API를 개발하기 보다는, ML 모델은 Flask 기반의 Bandit Engine Microservice로 분리하여 AI 팀이 오로지 ML 모델 개발 및 Fine Tuning에 집중할 수 있게끔 했습니다. HTTP 요청 핸들링 및 데이터 소싱, 포맷팅을 전부 Recommendation API 에서 대신 처리하므로 AI 팀은 Recommendation API 를 일종의 추상화 계층으로 받아들이고 ML 모델 개발에 집중할 수 있었습니다.
구분 | 기술 스택 |
---|---|
언어 | Typescript |
프레임워크 | NestJS |
DB | Firestore |
테스팅 | Jest |
툴링 & 버전 관리 | Lerna, Husky, ESLint, Prettier |
문서화 | Swagger, Typedoc |
CI/CD | Github Actions, Cloud Run, Compute Engine, Cloud Build 외 7개 GCP 서비스 |
Bandit Engine
Bandit Engine은 Contextual Bandit 모델을 제공하는 내부 API입니다.
Flask 로 개발되었고, AI 팀이 머신러닝과 관련된 알고리즘 및 모델 작성을, 작성자는 ML모델을 제외한 REST API 를 개발했습니다. 언급했듯이 AI 팀이 웹개발을 전혀 다룰 수 없었기 때문에, 서비스의 각 엔드포인트는 주어진 입력값 이외에는 다른 DB 나 스토리지에서 데이터 소싱을 하지 않는 단순한 IPO(Input-Process-Output) 프로그램으로 구성하였고, 필요한 데이터는 전부 Recommendation API 에서 수집/정제 후 제공하였습니다. 이를 통해 AI 팀이 웹개발에 익숙치 않아 생기는 개발 병목을 사전에 방지할 수 있었습니다.
구분 | 기술 스택 |
---|---|
언어 | Python |
프레임워크 | Flask |
AI/ML | numpy, pandas, scikit-learn, openai |
테스팅 | pytest |
툴링 & 버전 관리 | poetry, commitizen, yapf, pylint, selenium |
문서화 | Sphinx |
CI/CD | Github Actions, Cloud Run, Cloud Build |
Admin Dashboard
Admin Dashboard는 쇼핑몰 관리자가 쇼핑몰에서 이루어지는 상품 추천과 관련한 설정을 할 수 있는 SPA 입니다.
React
로 개발되었고, 작성자가 대시보 드 일체를 개발했습니다. 개발 자원이 매우 부족한 상황에서, 팀의 제 1 목표는 모델의 실제 환경에서의 성능 검증이였기 때문에 대시보드는 단순히 DB의 데이터를 표시하고 업데이트하는 클라이언트의 역할을 하면 충분했습니다. 따라서 디자인 단계에서부터 불필요한 디테일은 제거하고, 컴포넌트 재사용 가능성을 염두에 두어 디자인하였습니다. 또한 react-toastify, react-select 등 여러 UI 라이브러리를 다수 검토하여 하드코딩 작업을 줄이는 데도 집중하였습니다.
구분 | 기술 스택 |
---|---|
언어 | Typescript |
UI 라이브러리 | React, MUI, TailwindCSS, D3, ... |
상태 관리 & 캐싱 | @reduxjs/toolkit, RTK Query |
번들링 | vite |
테스팅 | Cypress |
툴링 & 버전 관리 | Commitlint, Husky, ESLint, Prettier |
문서화 | Storybook |
CI/CD | Github Actions, Firebase Hosting |
Banner Manager
Banner Manager는 플러그인을 사용하는 쇼핑몰에 Javascript 형태로 직접 삽입되어 Recommendation API 에 상품 추천을 요청하고 브라우저 환경에 따라 추천 상품을 팝업 배너의 형태로 표시하는 스크립트입니다.
StencilJS
로 개발했으며, 작성자가 스크립트 일체를 개발했습니다. 기존에 사용하던 React
대신 StencilJS
를 도입한 것은, PickHound의 스크립트가 기존의 쇼핑몰에 삽입이 되어야하는 상황에 서 최대한 빠르고 가벼운 번들을 만들기 위해서는 브라우저가 기본으로 지원하는 Web Component API 를 활용하는 것이 가장 적합하다고 판단했기 때문입니다. 결과적으로 이러한 선택은 기능이 동일한 타사 추천 플러그인에 비해 본 팀의 스크립트 번들 사이즈가 60% 더 작게 나오는 등의 효과를 가져왔습니다. (See: StencilJS 도입을 통한 번들 크기 및 성능 최적화)
구분 | 기술 스택 |
---|---|
언어 | Typescript |
UI 라이브러리 | StencilJS |
번들링 | Rollup |
툴링 & 버전 관리 | Lerna, Husky, ESLint, Prettier |
CI/CD | Github Actions, Google Cloud Storage |
업무 경험 및 성과
Common
심층 인터뷰를 통한 수요 파악 및 제품 방향성 수립
- 약 1달에 걸쳐 다양한 분야에 종사하는 12명의 쇼핑몰 관리자를 대상으로 인터뷰 진행함.
- 인터뷰를 통한 피드백 수집으로 쇼핑몰의 규모에 따른 서비스의 수요, 운영 방식의 차이 등을 파악할 수 있었음.
- => 정리한 피드백에 기반한 불필요한 개발 단계 제거로 사내 개발 자원 낭비 방지.
아래 링크에서 위와 관련한 더 자세한 내용을 확인할 수 있습니다.
Lerna에 기반한 프로젝트 관리 및 공유 코드 라이브러리화
- Lerna를 활용한 모노리포 구성, 패키지 버저닝 및
commitlint
를 활용한 커밋 메시지 규칙 적용.- Github Actions, Bash Script, Husky를 활용해 버저닝 자동화 및 커밋 메시지 규칙 강제.
- 공유가 필요한 코드는 따로 패키지로 분리해 및 Google Artifact Registry를 활용해 private
npm
패키지 배포. - => 프로젝트 관리 체계화 및 자동화
- => 비효율적인 복사 붙여넣기 방식의 코드 공유를 최소화.
Related
불필요한 코드 빌드 최소화
- 대부분의 CI/CD 빌드 트리거가 Github Actions의
push
이벤트에 의해 발생함. - 모노리포 상황에서 하나의 패키지에만 변경사항이 있는 경우에도 모든 패키지의 빌드가 발생하는 문제가 있었음.
- Lerna를 이용한 버저닝 관리와 함께 패키지 레지스트리에 배포되어 있는 패키지의 버전과 현재 레포지토리의 패키지 버전을 비교해 변경사항이 있는 경우에만 빌드가 발생하도록 구성함.
- => 불필요한 빌드 최소화 및 CI/CD 자원 소비 최소화
publish_if_needed
function publish_if_needed () {
package_name="@$namespace/$1"
package_dir="packages/$1"
published_version=$(npm view $package_name version)
current_version=$(node -pe "require('./package.json').version")
if [ "$published_version" = "$current_version" ]; then
echo "$package_name is already published"
else
echo "Publishing $package_name"
npm publish -w $package_dir
fi
}