데이터베이스 구조 고민과 Shopify App proxy

2024년 2월 26일 월요일

Today I Learned

날짜

2024년 2월 26일 월요일

내용

기존 로직 파악

다음 스프린트 때 구현할 기능들에 대해 코드 초안을 작성하고 있다. 기존에 구현되어 있는 방식을 이해하지 못해 막혀있는 부분과 작성했지만 개선해야 할 부분을 회의를 통해 알게 되었다.

고객의 스토어에 표시할 위젯을 Shopify theme asset에 저장할 수 도 있다. 하지만 이 때 위젯을 가지고 있는 것은 shopify가 된다. 우리 서비스에서 제공하고, 수정 및 변경이 원활하기 위해선 우리가 가지고 있는 것이 바람직하다. 우리 서비스를 설치한 스토어는 테마를 수정하는 에디터에서 앱 블록을 추가할 수 있다. 앱 블록에는 스크립트가 작성되어 있는데, “어떤 위젯이 필요하니 app proxy를 이용해 알파리뷰 서버의 특정 endpoint로 요청하라”고 적혀있다. 우리 서버는 해당 요청을 받으면 이에 맞는 위젯 HTML에 알맞은 데이터를 추가하여 보내준다. 데이터까지 입력된 완성된 HTML을 보내주는 것이다. 앱 블록은 받은 것을 출력하면 된다.

앱 프록시(App Proxies)는 Shopify 앱이 상점의 URL을 통해 외부 서버로 요청을 전달하고, 그 결과를 Shopify 상점 페이지에 직접 표시할 수 있게 해주는 기능이다. 즉, 앱 프록시를 사용하면 Shopify 외부에 호스팅된 웹 페이지나 데이터를 Shopify 상점 내에서 마치 상점의 일부인 것처럼 보여줄 수 있다. 이를 이용한 위젯은 다음과 같이 작동한다.

  1. 소비자가 store에 접속한다.
  2. 작성된 스크립트가 로딩되며 Shopify에 설정해둔 subpath로 요청이 전달된다.
  3. Shopify에선 이 요청을 우리가 미리 설정한 알파리뷰의 리뷰서버로 전달한다.
  4. 알파리뷰의 리뷰서버는 이 요청을 받아 필요한 위젯을 완전하게 렌더링하여 응답한다.
  5. 고객의 화면에 위젯이 출력된다.

고객의 입장에선 Shopify에게 보낸 요청의 응답으로 받은 위젯이다. Shopify가 고객과 우리 서버 사이의 proxy 서버 역할을 해준 셈.

이제 내가 생각해야할 것은, 기존에 존재하는 로직을 그대로(혹은 약간의 수정만으로) 사용할 수 있는 가능성이다. 위젯 자체의 데이터에 sales popup에서 사용하는 실시간 데이터도 여기에 포함되는데 기존처럼 메타필드에 두고 사용하지 않고 우리 데이터베이스에 두어야 한다. 새롭게 생긴 위젯은 어떤 차이가 있는가, 이 부분이 코드 상 어떻게 작용할 것인가에 대해 분명한 이해가 있어야 답이 나오지 않을 듯 싶다.

데이터 구조 고민

이번 기능에서 위젯은 다수의 상품들을 포함한다. 이 위젯을 위해 사용해야 할 데이터들은 상품마다 존재해야 한다. 예를 들어, 위젯에 8개의 상품이 있을 때 한명의 고객이라도 사용할 때를 대비해서 “최근 구매 일자”, “판매량”, “잔고” 등을 가지고 있어야 한다는 뜻이다. 위젯에 따라 사용할 데이터의 종류는 다르더라도, 값은 같을 것이다. 두 위젯에서 사용되는 상품이 어떤 위젯에선 판매량이 300, 다른 위젯에선 판매량이 5000이라고 표시되선 안되기 떄문이다.

나는 “위젯을 위한 데이터 테이블”을 만들고 1개의 상품은 1개의 레코드를 가지도록 구현하고자 했다. 이 테이블에는 상품의 갯수만큼 데이터가 기록되게 된다. 각 위젯은 필요한 데이터를 상품의 id로 찾아 사용하면 된다. 이렇게 설정한 이유는 데이터 중 실시간성이 꽤 중요한 경우가 있었기 떄문이다. 예시로, 최근 주문된 날이 1달의 1번 꼴로 업데이트 된다면 고객의 입장에선 아무 의미없는 표시일 뿐이다. 짧게는 분 단위로 이루어져야 해당 상품이 인기가 많은 것임을 알릴 수 있다. 즉 몇 분 단위로 데이터를 업데이트하기 위해 이 테이블을 순회해야 한다. 이 때 발생하는 비효율성이 성능의 문제로 직결될 것 같았다.

상품이 위젯별로 데이터를 가지게 된다면, 데이터의 갯수는 곱해진다. A라는 상품이 3개의 위젯에서 사용된다면 이 테이블에는 3개의 데이터를 가진다. 첫 번쨰 위젯에서 사용할 데이터, 두 번째 위젯에서 사용할 데이터, 세 번째 위젯에서 사용할 데이터. 물론 내용은 같지만 별도의 데이터가 만들어져 사용될 것이다. 그리고 이 값이 업데이트 될 때는 3개 다 찾아 업데이트해야 한다.

이 방법의 문제점은 위젯 테이블의 데이터에 여러개의 상품 index를 담을 수 없다는 것이다. id가 27인 위젯 테이블이 있다고 가정해보자. 상품 A부터 D까지가 이 위젯에 담긴다.

위젯이 존재하는 widget 테이블

id 27
products {1,2,3,4}

상품 데이터 4개가 있는 product_widget_data 테이블

id name widget_id
1 A 27
2 B 27
3 C 27
4 D 27

이렇게 담을수야 있겠다만, products를 index로 쓰긴 곤란하지 않을까? index는 데이터베이스 내에서 탐색 성능을 높이기 위해 사용한다. 일반적인 필드 값이 일치하는 레코드를 탐색하는 것과 index가 일치하는 레코드를 탐색하는 것은 큰 성능 차이가 있다. 그런 만큼, index를 설정하는 것 자체에도 리소스가 소모되기 때문에 신중해야 한다. 이를 해결할 방법으론, 둘의 관계를 나타내는 테이블을 만들면 되겠다고 생각했다.

관계있는 widget과 product_widget_date의 id를 필드로 가지는 테이블

id widget_id product_widget_data
1 27 1
2 27 2
3 27 3
4 27 4

굳이 이렇게 하지 않아도 다른 방법이 있기 떄문에 이 방법은 철회했다. 위젯에 있는 상품 1개마다 1개의 데이터를 product_widget_data에 만드는 방식의 문제점은 데이터를 업데이트할 때 리소스가 많이 소모된다는 것이었다. 이 문제를 index를 이용하면 해결할 수 있을 거라고 생각했다. 각 레코드에게 shopify에서 부여한 상품 ID를 index로 설정하여 해결하기로 했다. 업데이트할 상품을 찾을 때, index를 이용하면 수정해야할 레코드를 찾는 것이 빨라져 단점을 해결할 수 있다.

이러한 고민은 타의로 하게 되었는데.. 애초에 내가 다 고려해서 결정했어야 하는 과정이다. 아직 멀었다.

회고

열심히 고민한 만큼 좋은 코드가 나오길.