기능 VS 아키텍처

2024년 2월 28일 수요일

Today I Learned

날짜

2024년 2월 28일 수요일

내용

세일즈 팝업

이번 스프린트에서 가장 고민이 깊은 부분은 실시간성 데이터들이다. 상품을 보여주는 위젯에 “5분 전에 춘천 사는 김씨가 샀어!” 라던가, “재고가 5개 밖에 안남았어!” 라고 말해줘야 한다. 이 데이터가 내일 들어와도 “5분 전에 춘천 사는 김씨가 샀어!”라고 고정되어 있다던가, 아직도 5개가 남아있다면 효과가 떨어질 수 밖에 없다. 재고가 1개로 줄어들었다던가, 방금 구매한 고객에 대한 정보가 바뀌어있어야 한다.

기존에 알파리뷰에 있는 세일즈팝업이 이 데이터를 이용한다. 재고, 상품 상세정보 페이지 방문자 수, 판매량, 최근 구매 내역이나 리뷰 작성 내역등이 포함된 팝업이다. 이 위젯은 기존에 있던 다른 위젯들과는 구성이 조금 다른데, 렌더링이 우리 서버에서 발생하지 않는다는 것이다. 기존 위젯은 App proxy를 이용하여 다음과 같이 발생한다.

  1. 고객이 스토어에 접속하면 위젯 스크립트에서 Shopify의 특정 주소로 위젯 렌더링에 관한 요청보낸다.
  2. Shopify는 특정 주소로 온 요청을 미리 약속된 App proxy 설정에 맞게 알파리뷰의 특정 경로로 리다이렉트한다.
  3. 알파리뷰 서버는 받은 요청에 따라 위젯 HTML에 jinja2로 데이터를 추가해 완성된 형태로 응답한다.
  4. Shopify는 알파리뷰에게 받은 응답을 고객에게 보낸다.
  5. 고객의 화면에 위젯이 나타난다.

중요한 부분은, 위젯이 렌더링 되기 위해 “요청”이 발생한다는 것이다.

하지만 세일즈 팝업은 다르다. cron과 내부 로직을 통해, 12시간 간격으로 필요한 데이터를 스토어의 메타필드에 추가해놓는다. 세일즈 팝업은 필요할 때, 메타필드에서 이 데이터를 찾아 화면에 띄운다. 필요할 떄란, 정해놓은 시간주기나 데이터의 변화겠지..?

따라서 세일즈 팝업에 필요한 데이터는 우리 데이터베이스에 없다. 좀 더 자세히 말하자면, 데이터를 연산하기 위해 필요한 재료들은 존재하지만 연산이 완료된 형태로는 없다. 고객이 방문한 상품페이지에 대한 정보, 스토어에서 발생한 주문에 관한 데이터는 가지고 있지만 그래서 A라는 상품을 가장 최근에 구매한 사람이 어느 지역의 누구인지는 아직 모른다. 12시간에 한번 탐색으로 데이터를 연산해 메타필드로 보낼 뿐 우리 데이터베이스에는 저장되지 않는다.

기능 VS 아키텍쳐

위의 이야기를 이어보면, 이번 스프린트에서는 이 실시간성 데이터가 필요하다. 메타필드에서 가져와 사용할 수 없다. 메타필드에 서 데이터를 추가한다는 것은 결국 위젯이 만들어져 출력되는 모든 과정이 우리 영역이 아닌 Shopify에서 이루어진다는 사실이다. 기존 위젯은 우리가 데이터를 넣고 완성된 형태를 보내고, Shopify에서는 말 그대로 고객과 우리 사이에서 “프록시 서버” 역할만 할 뿐이다. 따라서, 기존 위젯에 필요한 데이터도 메타필드가 아닌 우리 데이터베이스에 저장되어 있다. 물론 위젯을 가능한 우리가 컨트롤 하는게 여러모로 바람직하다.

이번 스프린트의 위젯도 기존 위젯과 마찬가지로 우리 서버에서 렌더링하도록 구현할 것이다. 따라서 기존에 메타필드에만 저장되었던 실시간성 데이터들이 우리 서버에도 적절한 형태로 저장되어야 한다. 이 기능 자체는 그리 어렵지 않다. 위에서 말한대로 “필요한 재료”를 수급하는 기능은 이미 있다. webhook으로 주문, 상품 정보가 들어와 저장된다. 필요한 데이터를 위한 쿼리를 작성하면 될 뿐이다.

문제는, 이미 세일즈팝업에 사용되고 있는 코드가 있다는 것과 별개의 영역에서 사용된다는 것이다. 세일즈팝업을 위한 추상클래스가 정의되어 있고 이에 알맞게 상속받은 하위 클래스들이 잘 짜여져있다. 단순히 데이터를 저장하는 메서드만 추가하기엔, 위젯에 관한 데이터가 전혀 다르다. 사용하는 데이터가 같다는 이유만으로 기존에 결합되어있는 모듈을 변경하는 것은 적절하지 않다고 생각한다.

내가 생각한 가장 이상적인 해결책은 기존 모듈을 분리하는 것이다. 실시간성 데이터를 추출하는 것과 세일즈 팝업에 사용하기 위해 데이터를 가공하는 것을 별개로 둔다는 의미이다. 그리하면 같은 실시간성 데이터를 위해 이번 스프린트와 세일즈 팝업은 같은 모듈에 의존하면 된다. 중복코드가 발생하지 않으니 좋다. 이외에 각자 필요한 메서드는 각자 정의하면 된다. 세일즈 팝업에선 팝업에 알맞은 데이터로 가공하고 메타필드에 저장하면 된다. 내가 만들 것은 데이터베이스에 적절한 엔티티로 저장해주면 된다. 최근 클린 아키텍처 스터디에서 보고있는 SOLID 원칙, 특히 추상화, 역전 제어 등을 체득할 수있는 좋은 기회가 될 수 있다.

하지만 방구석에서 나 혼자 하는 개인 프로젝트가 아니니, 정해진 일정이 있는 상황에서 내가 해낼 수 있을지 모르겠다. 좋아지긴 커녕 괜히 잘 있던 세일즈 팝업도 망가지면 여러사람 힘들어지는 일이라… 되기만 한다면야 몇 주를 고생해서라도 해내고 싶다만 시간을 갈아 넣는다고 되는게 아니니 쉽게 결정하기 힘들다. 타협점을 찾아야 하는데, 결국 “얼마나 걸릴지”를 정확히 알고 있는게 가장 중요하지 않을까 싶다.

회고

모든 문제는 “그래서 얼마나 걸려?”에 대답 하지 못해 발생하는 것 같다.