와인포인트 이미지

길고 길었던 8월 5주차가 끝나가면서 와인포인트에서 개발자로 일했던 1년 6개월의 생활도 마무리가 되어간다.

첫 와인포인트에 입사하고 지금까지 쌓여있던 일을 정신없이 처리했다. 지금와서 지난 1년 반을 되돌아보니 초기에 그렇게 초라하던 소프트웨어가 커져있는 걸 보며 감개무량한 기분을 느낀다. 이 글은 1년 반이라는 기간동안 어떤 성장을 어떤 일을 하면서 이루었는지 회고하는 시간이 될 것이다.

와인포인트

와인포인트는 온라인에서 주류를 구매가 불가능 한 걸 개선하고자 가장 가까운 편의점으로 배송하여 대면결제로 처리하는 프로세스를 구축했다. 이 프로세스 위에서 사용자가 모바일을 통해 와인 리스트 정보를 보고 편하게 구매할 수 있다.

와인포인트 서비스를 제작하기 위해서는 다양한 인프라를 세팅했어야 했는데 인프라를 알아보기에 앞서, 어떤 서비스가 필요했는지 알아볼 필요가 있다.

  1. 데이터 관리자 페이지: 앱 설정 및 데이터를 저장하는 관리자 페이지
  2. 주문 관리자 페이지: 고객들의 주문 정보를 관리하고 FC나 소매점에서 배송 상태를 변경하기 위한 관리자 페이지
  3. 안드로이드, iOS 앱: 사용자가 사용하는 앱

크게 3가지 규모의 작업이 필요했고, 안드로이드 앱을 시작으로 초기 멤버 2명 (CTO님, 개발자 1명) 진행을 했다. 서버 개발 및 안드로이드 어플리케이션 개발을 진행했고 얼마 지나서 내가 들어왔다. 들어와서 임시였던 관리자 페이지를 디자인 작업 및 개발 진행을 했고, 랜딩페이지, 주문 페이지등을 차차 개발해나갔다. 주문 페이지를 개발하던 중, 디자이너 겸 개발을 하시는 분을 새로 모셔왔고 총 4명이서 개발을 진행했다고 보면 된다.

인프라

와인포인트의 AWS를 적극 활용했다. 모든 서비스를 AWS에서 사용하니 서비스에서 서비스로 이동하는 트래픽에 대한 요금을 지불하지 않아도 되었고, 많은 예제가 있어 쉽게 개발이 가능했다. AWS를 기준으로 다양한 서비스 인프라를 갖추게 되었는데 몇 가지를 짚어보도록 하자.

배포 시나리오

와인포인트의 API는 ElasticSearch, LogStash, Kibana를 줄여 ELK라고 부르는 Stack 구현체가 하나 있으며, AWS에서는 ECS를 통해 Blue-Green 배포를 실시하고 있다. 요즘은 AWS Elastic Beanstalk + AWS Code Pipeline을 주로 사용하는 것 같았는데 당시에 구현할 때는 존재하지 않아서 ECS가 최선의 선택이었다.

빌드 프로세스는 개발서버와 실서버를 이용해서 배포하게 되는데, 과정은 아래와 같다.

  1. 작업을 API Github Repository Master branch에 Push혹은 PR Merging
  2. Github Webhooks에서 Master branch push event시 Jenkins에 요청
  3. Jenkins에서 해당 프로젝트를 받고 프로젝트 내의 jenkinsfile 실행
  4. jenkinsfile에서 테스트, 빌드, 개발서버 배포(AWS 동작) 실행
  5. 개발서버 배포, ECS의 기존 인스턴스 내리고 새로운 컨테이너 인스턴스 생성
  6. 개발서버 배포 후 개발서버에서 API 테스트
  7. 테스트 완료 시 실서버 배포 시작, 실서버 배포는 ECS에서 새로운 작업 정의 후, 클러스터에서 실서버 선택 후 업데이트.
  8. 업데이트 시, 해당 클러스터의 내용 시작. Code Deploy로 실서버 배포

파이프라인을 잘게 쪼개놔서 어디서 에러가 났는지 쉬운 탐색이 가능하고, 블루 그린 적용을 해놓았기 때문에 실서버 배포시 배포가 안될 경우 자동으로 롤백이 된다.

API 개발 환경

와인포인트의 모든 API는(AWS lambda 제외, Python 1.6으로 작성되어 있음.) Node.js와 Express.js로 개발이 되어있다. 개발자가 적다보니 모든 팀원이 쓸 수 있는 JavaScript ES6로 개발이 되었고 이는 웹 프론트앤드와 백앤드를 왔다 갔다 하면서 빠르게 개발을 할 수 있는 동력이 되었다.

B2B API

와인포인트는 유저에게 가장 가까운 이마트24 매장을 선택해서 픽업해가는 서비스이기 때문에, 이마트24쪽과 긴밀한 협업이 일어났어야 했다.

  1. 이마트24 점포의 폐점/개점/변동 데이터
  2. 상품의 점착/발주마감/취소/노쇼 데이터

이런 데이터를 일정 시간에 균일하게 데이터를 serving 했어야 했고, API를 통해 주고받았다.

사용자가 상품을 예약하면 내부에서 일어나는 일

와인포인트 물류 센터에 각 수입사에서 상품을 받는 시간은 이마트24 물류센터에서 물류를 배송하기 전 시각이어야 한다. 그 시각이 오전 10시라고 한다면 우리가 배송 해야하는 시간은 적어도 9시까지는 되야한다.
와인포인트 물류 센터에서 나가는 상품은 발주마감 되어야 하며, 앱에서 사용자가 와인(아이템)을 장바구니에 담아서 구매(예약)하면 하나로 묶여서 상품이 된다. 그렇게 만들어진 상품은 발주요청이 된다.

발주요청된 상품은 새벽에 이마트24 전산에 올라가면서 발주됨 상태가 된다. 발주됨 되기 몇 시간 전에 사용자는 이 상품의 발주요청을 취소할 수 있다. 모바일에서 예약취소라고 불리는 그 것이다. 이 예약취소를 할 수 있는 시간을 지정해놓고, 해당 시간이 지나면 사용자가 구매한다고 생각하여 발주마감을 한다.

발주됨 상품은 와인포인트 물류차를 타고, 이마트24 센터에 도착한다. 이마트24 센터에 도착한 상품은 이마트24 차량에 실려서 각각 예약한 이마트24 점포에 serving된다. 여기까지가 기본적인 이마트24와의 물품 전달 시나리오이다.

상품이 혹여나 잘못될 상황이 있을 수도 있고 어디까지 왔는지 체크도 해야하기 때문에, 와인포인트 내에서 상품 상태를 갖고 있어야 한다. 그래서 상품의 상태를 총 4가지를 갖고 있다.

  1. 발주 상태
  2. 상품 상태
  3. 취소 상태
  4. 노쇼 상태

발주 상태는 위에서 말했듯 이마트24와 상품 상태를 통신하기 위한 상태이다. 위에서 언급했듯 상품이 준비가 되었나에 대한 척도가 되기도 한다. 만약 발주 상태가 발주마감인데 발주될 시간이 지낫다면 해당 물품이 제대로 이마트24에 전달이 안된 것이라고 판단할 수 있다.

상품 상태는 현재 상품이 어떤 위치에 있는가를 알아 낼 수 있는 상태이다. 가장 중요한 상태이기도 한데, 상품 상태는 아래의 몇가지 상태로 나타내어진다.

  1. 준비중
  2. 포장완료
  3. 배송중
  4. 배송완료
  5. 결제완료
  6. 결제취소
  7. 노쇼

예를들어, 배송중 과정에서 며칠이 지나도 응답이 없다면 배송하는 과정인 이마트24 물류에서 혹은 와인포인트 물류에서 빠졌음을 추측하고 대책을 마련할 수 있다. 이렇게 상세하게 상태를 분류를 해놓으면 관리자 페이지에서 어떤 상황이 일어났는지 판단하기 쉬워진다.

취소 상태는 취소에 대한 상태를 가지고 있다. (응? 너무 당연한데..) 이 취소라는게, 와인포인트의 상품에는 와인이 담겨져 있다. 그런데 식품의 특성상 콕트(Corked, 곰팡이 중에 TCA라는 곰팡이가 있는데 이 곰팡이에 감염된 코르크를 사용한 와인이면 와인과 접촉해서 곰팡이 냄새를 내게 한다.)된 와인 혹은 변색 등 다양한 문제가 있을 수 있다. 그래서 상품의 상태도 존재하지만 묶여있는 아이템 단위로도 상태가 존재한다.

  1. 정상
  2. 취소
  3. 노쇼

그래서 상태가 좋지못한 아이템은 취소 상태가 되며, 상품의 상태 뒤에 부분 취소 가 븉는다. 예를들어, 아이템 두 개를 묶은 상품을 구매했는데 두 개중 하나가 콕트된 와인이다! 하면, 해당 와인은 부분 취소가 되며 상품 상태에는 결제완료 (부분취소)가 되는 것이고, 해당 상품의 아이템 상태는 1. 정상 2. 취소 가 되는 것이다.

노쇼 상태는 해당 상품을 리콜하기 위한 상태이다. 노쇼가 된 와인도 이마트24 물류에서 수거해서 물류창고에 돌아오게 되는데, 이 것도 다양한 문제가 있었으나 생략.

순탄하면 좋겠지만.. 물류라는게 쉽지않아

위에서 언급한 순서대로 착착착 진행되면 얼마나 좋겠는가? 하지만 사람은 완벽하지 않기 때문에 소프트웨어를 최대한 잘 짜려고 노력해도 실수하는 경우가 있고, 업무를 처리하는데 있어서 문제가 나오는 경우도 비일비재하다. 여러가지 문제가 있었지만 대표적인 문제 한 가지를 살펴보자.

플랫폼 사업을 하면서 여러 회사와 일을 하다보면 어쩔 수 없이 마주하는게 책임이다. 어디에서 문제가 일어났나에 따라 돈이 왔다갔다 하기 때문에 해당 책임을 찾는 일은 매우 중요하다. 그렇기 때문에 Log System은 매우 중요하다. 특히나 와인포인트는 이마트24 물류를 타기 때문에 이마트24와 와인포인트 물류의 사이에 어중간하게 문제가 생기면 로그를 통해서 전수조사를 해야한다. 로그 조사 작업은 백오피스가 잘 되어 있어도 리소스가 많이 투입되는 작업이다.

대표적으로 이마트24에서 고객의 상품이 제대로 전달이 안되는 경우가 있다. 아까의 상태에서 배송 완료가 되지 않고 며칠이 지나도 배송중이 나오는 경우이다. 이런 경우는 몇 가지를 추론할 수 있다.

  1. 이마트24에서 배송완료로 변경을 하지 않음.
  2. 와인포인트의 서버가 장애가 나서 배송완료로 이마트24에서 전달했으나 전달되지 않음
  3. 와인포인트의 관리자가 상태를 강제로 변경

먼저 알아야 할 것은 이마트24에서 요청을 했는가?이다. 와인포인트는 nginx를 사용하므로 nginx 로그를 까서 보면 된다. 해당 일짜에 emart24에서 해당 API를 요청했는지 확인하고 요청한 API의 Body를 까서 확인한다. 이렇게 확인하면 대체적으로 이마트24 에서 요청을 안했다 라는 결론으로 귀결된다 (…)

만약 이마트24에서 요청을 했고, 해당 요청을 정상적으로 이행했으나 바뀐 점이 있다면 와인포인트의 관리자가 상태를 강제로 변경했을 확률이 높다. 이는 와인포인트 관리자 페이지의 로그에서 확인하면 된다. pm2를 사용하므로 pm2 log로 확인하면 된다.

이러한 문제가 아닌데, 유저가 언제 배송되나요? 라고 물어본다면 유저에게 푸쉬 알람이 왔는가를 확인해야 한다. 상태가 변경되면 와인포인트 앱에 push가 가게 된다. 그런데, 모든 사람이 푸쉬 허용을 한 건 아니여서 푸쉬 동의 확인을 하고, 친절하게 알려주면 된다.

DB

공통으로 우리는 관계형 데이터베이스(RDBMS)인 PostgreSQL을 사용했다. DB에 대한 지식이 많이 없었지만 결국에는 다루게 되는 신기한 스타트업 세상.. PostgreSQL은 다른 DB와 다르게 폭넓은 Window Functions을 제공하는데 이게 제법 편하다. jsonb로 만들어서 array 래핑한다음 넘기기도 하고, 다양하게 가공이 가능해서 쉽게 개발을 했다. 다양한 extension도 많아서 시간이 되면 써보는 걸 추천한다.

Query Builder로는 Node.js 생태계의 Knex.js를 사용했는데 이게 또 그렇게 편하다. 편한 이유 몇 가지를 보면.

  1. migrations 지원
  2. 함수형 방식의 간단한 함수 호출, SQL Injection 대응
  3. Async Await 문법 지원

다만 PostgreSQL의 특성상 편리한 Window Function이 많아서 knex.raw로 raw 쿼리를 작성했는데, 간단한 쿼리의 경우에는 Knex의 function을 사용해서 작성하면 편하긴 했다. 다만, 일관성 측면에서 knex raw로 통일하는게 PostgreSQL을 사용하는데 있어서 더 용이하다는 생각을 했다. 어느곳은 raw 쿼리, 어느곳은 knex 문법을 사용한 쿼리.. 가독성이 안좋은 코드가 되더라.

예제는 knex.js migrations를 보고 참고하면 된다.

와인포인트 웹은 만들어 질 때 Vue.js를 이용해서 전체 스펙을 작성했다. 이는 내가 SPA 앱을 제대로 다루지 못했기 때문도 있지만, 인원이 부족한 조직 특성상 간단하고 쉽게 개발자 모두가 접할 수 있게 하기 위함이다. Vue.js는 이러한 요구사항에 적합했다. Single File Componenet는 한 파일 내에서 html, css, javascript를 컨트롤하기 쉬웠으며, 귀찮던 css module과 같은 일도 stylescoped 옵션만 주면 쉽게 적용할 수 있었다.

첫 번째 고민, 모든 걸 다 만들자

2018년 3월, 초기 관리자 페이지를 개발할 때 레이아웃 컴포넌트를 vuetify같은 Material UI 기반 프레임워크를 가져다 쓸까 고민을 했다. 하지만 와인이라는 특성상 다양한 정보, 이미지, 일관적이지 않은 레이아웃의 가능성이 높아 Material UI 기반 프레임워크보다 직접 구현하는게 낫다라는 판단을 했고, 이런 판단을 기반으로 Vuex와 같은 상태 관리 프레임워크도 직접 개발하게 되는 단계까지 돌입했다. (아아.. 이때 내 자신을 막았어야 했는데)

당시 프론트앤드 개발 개념이 부족하여 컴포넌트 쪼개는 것은 어느정도 잘 되었으나, Vuex를 개발할 때 매우 큰 문제가 되었다. 아무래도 혼자 observable한 객체를 시간에 쫓기며 개발하다보니 점점 비대해졌고 레이아웃 컴포넌트와 상태 관리 컴포넌트의 레거시가 각각 쌓여갔다. 만약 Vuex를 사용했다면 기능 개발 이슈는 어느정도 해소할 수 있었을텐데 라고 생각했다.

이러한 문제를 해결하고자 대규모로 리펙토링을 진행했다. 커스텀 상태 관리 프레임워크를 제거하고 Vuex를 도입하고, 비동기 통신을 전부 Vuex에 몰아버렸다. 그렇게 리펙토링이 되어 상태 관리가 깔끔하게 이루어졌다. 하지만 다음 문제가 또 생기게 되는데..

두 번째 고민, 레이아웃 컴포넌트에 레거시가 많이 쌓이기 시작

이번에는 여러가지 기능이 추가되면서 중복된 레이아웃 컴포넌트가 많아진다는 문제점이 생겼다. 이를 mixins 혹은 extends로 어느정도 막고는 있었으나 그럼에도 불구하고 쉽지않았다. 그래서 컴포넌트 구조를 어떻게 나눌까 고민을 많이했다. 그러던 차, 레이아웃 컴포넌트와 데이터 컴포넌트를 나누는 Containers & Presentationals 패턴을 발견했다. 그래서 공용으로 사용하는 레이아웃 컴포넌트는 데이터 하나도 없이 공통으로 사용할 수 있게 한 곳에 격리 했으며, 모든 페이지는 해당 레이아웃 컴포넌트만을 사용하는 흐름으로 진행했다.

이 이야기도 상당히 많이 썰을 풀 수 있는데, 다음에 기회가 되면 따로 글을 쓰도록 하겠다.

작년에 Vue.js의 Vuex 의존적인 문제를 해결하기 위해서 NaverD2 - Vue.js를 이용한 백오피스 제작 경험 공유 발표 했던 자료가 있다.

그러면서 겪은 Vue.js의 단점

이러한 Vue.js에도 단점은 있었는데 SFC(Single File Component)html, css, javascript가 붙어있다는 특성상 HOC와 같은 기능을 하는 컴포넌트를 다중으로 래핑해서 사용하기 어렵고 가능이 많아질수록, 컴포넌트를 잘게 쪼개는게 어려워진다. 또 여러가지 레이아웃 컴포넌트를 조합한 컴포넌트의 경우 html, css, javascript 세 가지 파일이 합쳐져있는 특성상 파일도 매우 길어져서 코드 가독성도 안드로메다로 가버리는 경험을 할 수 있다. Containers & Presentationals 패턴을 적용하기도 좀 까다로운데, Containers로 데이터를 주입 해야 하는데 Vue.js는 watch로 상태를 물고 있어야해서 까다로운 점도 있었다.

상태가 변경될 때 마다 상태가 반응하는게 아니어서 조금 번거롭기도 하고. 대신 깊게 사용하지 않는다면 쉽고 빠르게 개발할 수 있는게 장점이긴 하다. 만약 관리자 페이지를 개발하는 목적에 있다면 직접 컴포넌트를 개발하는 것보다 vuetify 사용하는게 더 빠르고 쉽게 개발할 수 있겠다는 생각이 들었다.

Grid System과 Flex

그리드 시스템은 변칙적이지 않은 UI를 그리는데 큰 도움이 된다. 하지만 위에서도 언급했듯 특수한 관리자 페이지 레이아웃을 사용하기 때문에 Grid System보다 Flex가 어울린다고 판단했다. flex는 비록 하위 버전의 브라우저에서는 지원을 못한다는 단점이 있으나 내부에서 관리자페이지는 Chrome으로 대동단결 했기 때문에 큰 문제가 되지 않았다. 여차하면 polyfill을 사용하면 어느정도는 커버할 수 있어서..

flex를 사용해서 관리자 페이지의 모바일 대응도 했다. 반응형 UI 구현은 역시 쉽고 모바일 지원하기도 쉬웠다. 다만 다양한 정보를 보여주는 레이아웃 상, 반응형으로 개발을 해도 레이아웃을 어떻게 해야할까 하는 고민은 존재했다. 이런 상황에서 Grid System을 사용했다면 더 편했을 부분도 있을꺼라 생각했다.

주문 어드민의 등장

위에서 와인포인트의 물류 처리 시나리오를 이야기 했다. 이마트24만 있었다면 물류 센터용 페이지만 만들면 되었을텐데, 동시에 오프라인 매장으로의 확장 이슈가 존재해서 오프라인 매장과 물류 센터에서 동일하게 사용하는 웹 페이지를 만들어야 했다. 그래서 첫 번째로 권한 분리 작업을 했다. 와인포인트 관리자, 물류 창고 관리자와 근무자, 스토어 매니저와 근무자 총 5가지로 권한 분리를 진행했고 해당 권한에 맞게 UI를 제공했다.

쉽게 사용할 수 있도록 센터에서 준비중인 상품만 확인하는 페이지에서는 포장완료로만 변경할 수 있으며, 포장완료인 상품만 확인파는 페이지에서는 배송중으로만 변경할 수 있게 만들었다. 이 전 단계로는 롤백하지 못하며 해당 작업은 개발팀에 의뢰해야하는 형태로 작업하였다.

오프라인 매장에서는 배송중 -> 배송완료, 배송완료 -> 결제완료, 결제완료 -> 취소 및 환불만 가능하도록 카테고리 권한을 제작했다.

이렇게 카테고리 별 기능을 강제한 이유가 두 가지 존재하는데 다음과 같다.

  1. 몇 시에 어떤 작업을 했는지 로그 쌓기의 개념으로써
  2. 다양한 권한의 분리의 목적으로 설계

누군가가 어디서 몇 시에 작업했는지 카테고리를 나누면 구조화가 더 쉬워진다. 그리고, 언제 어떤 권한이 추가 될 지 모르는 상황에서 매장과 물류 센터를 통짜로 두 개를 나눠서 작업하기엔 리스크가 컷다. 그래서 프로세스 별로 제작한 후, 해당 카테고리를 권한 별로 제공했다.

이러한 작업은 데이터 어드민을 개발하는 일보다 적게 걸렸고 빠르게 진행되었다. 데이터 어드민에서 사용하는 레이아웃 컴포넌트를 가져와서 동일하게 사용했으므로 레이아웃을 구성하기만 하면 되었다. 여기서 조금 아쉬운 점은 그러한 Core Component를 공통으로 빼서 사용했으면 유지보수가 더 쉬웠을텐데 하는 점이 있다.

타입스크립트의 필요성

JavaScript로 코딩을 하다보면 정확한 Code Navigation 및 Assist가 안될 때가 많다. 해당 클래스 혹은 Function에 존재하지 않는 변수임에도 보이는 경우도 있고, 없는 경우도 있고 말이다. 이러한 문제를 해결하기 위해 도메인 객체를 설계해서 Assist를 유지하곤 하는데, 이렇게 해결할 수 없는 경우들이 있다.

이렇게 오타 혹은 제대로 작성되지 못한 코드는 오류를 유발하며 빌드 후 에러를 금방 찾을 때도 있지만 시간을 낭비하는 경우들이 꽤나 있다. 사소한 실수지만 제법 시간을 소비하기 때문에 문제를 해결하고자 했고, 이런 의지는 타입스크립트의 필요성을 느끼기에 충분했다. 특히, 도메인 객체를 제작할 때 타입스크립트를 적용해서 코딩을 하면 많은 도움이 되는데 interface, enum 등 다양한 키워드를 통해 명확하게 작성 할 수 있다. 그래서 협업하기 쉬운 코드로 발전된다.

@Type이 없는 Module의 경우에는 TypeScript 적용이 모호해지는 점이 과거에 있었으나 지금은 왠만한 모듈에 @Type이 존재하고 문법적으로도 많은 발전이 되어 과거에 타입스크립트가 애매하다 라는 오명을 벗었다고 생각한다. 타입스크립트 커뮤니티도 제법 커지고 많은 기업에서 타입스크립트를 베이스로 사용하기 때문에 많은 자료가 존재하며, 러닝커브의 문제가 존재한다고 하였으나 그렇게 달라지는 점도 많이 없어서 괜찮음을 느꼈다.

과거 게임 클라이언트 프로그래머로 C#을 주로 썼던 나에게는 정적 타입 언어가 매우 익숙하다. 그렇기에 타입스크립트는 나에게 쉽고 빠르게 다가왔고 어느정도 만족하며 쓰고 있다.

Vuex Dependency VS. Prop Drilling

Vuex에 대해서 위에서 어느정도 이야기는 했다. 하지만 아직까지도 내 물음에 시원하게 답이 나왔던 경우가 없는 이슈가 있는데, 바로 Vuex Dependency VS. Prop Drilling 이슈이다. 조금 더 풀어서 설명하자면, Component가 Vuex module component와 n:n으로 대응이 되는 상황(Vuex Dependency)과 최상단에 데이터 객체를 만들어서 Props로 값을 최하단의 컴포넌트까지 전파하는 방식(Prop Drilling) 두 가지이다.

Vuex Dependency 코드가 용이할 때는 Component의 Depth가 4단계 이상의 깊음(props로 4번 이상 들어가는 경우), 데이터가 즉시 변경되어야 하는 라이프 사이클을 가질 때(컴포넌트 내에서 해당 상태에 대해서 바인딩 될 상황이면 안될 때), watch를 쓰기 애매할 때(상위 데이터 객체에 대한 상태 값 바인딩, 2번째 케이스와 비슷) 등이 있겠다.

Prop Drilling 코드가 용이할 때는 Component의 Depth가 3단계 이하일 때, 레이아웃 컴포넌트에서 상태를 갖고 있지 않아야 할 때(레이아웃 컴포넌트와 데이터 컴포넌트 분리의 용이) 등이 존재하겠다.

처음 Vue에서 상태관리 라이브러리로 Vuex를 사용할 때 느꼇던 점은 굉장히 느슨하다는 점이었다. 기본적으로 Flux라고 일컫는 패턴이 타이트하게 붙어있기보다 어떻게든 확장 가능하도록 열려있었다. 그래서 Redux와 같은 형태가 강제화 되어있는 상태관리 라이브러리보다 이해하고 작업하는데 얼마 안걸렸다는 점이다. 이 말인 즉슨, 자칫 잘못해서 형태를 잡게 된다면 협업 및 유지보수하기 어려워진다는 말과도 일맥상통했다.

그렇기 때문에 레거시가 쌓이기 쉬운 소스(Vuex와 Vue의 중간 역할을 하는 코드들)가 Vuex에 함께 들어있다면 혼잡해질게 뻔했다. 과거에 이러한 형태의 코드를 제어하기 위해 MVC, MVP과 같은 패턴이 등장한 걸 보면 비슷하게 중간 다리 역할이 필요할 만 했다. 그래서 찾던 중 Containers & Presenationals를 발견했다. 위에서 언급했듯 이를 이용해 레이아웃 컴포넌트와 컨테이너(데이터) 컴포넌트로 분리했고, 이러한 데이터 컴포넌트는 레이아웃 컴포넌트와 상태관리 라이브러리의 중간 계층 역할을 훌륭하게 해내었다.

이러한 패턴으로 가면서 나는 점차 Prop Drilling의 형태를 띄게 코딩을 하게 되었고 자연스럽게 Vuex DependencyProp Drilling의 승부에서 자연스럽게 승자가 정해지게 되었다. Prop Drilling의 단점으로 꼽혔던 Depth가 깊어진다는 문제점은 Atomic Design의 형태로 컴포넌트를 구현하니 얕은 Component Depth로(HTML 상의 Depth 문제는 해결을 해야한다.) 어느정도 해결이 되었다.

결론

와인포인트에서 겪은일만 해도 수많은, 말로 표현하기에도 벅찬 경험을 했다. 이런 일을 바탕으로 얻은 경험은 앞으로 내가 회사에서 일을 하는데 있어 수많은 영향을 끼칠 것이라 생각한 것을 써보면 아래와 같다.

  1. 서비스는 유저를 기준으로 쉽고 편하게 개발하여야 한다.
  2. 도메인 모델링 할 때 사용자 중심으로 개발하는 게 좋다.
  3. 간단한 기능을 개발하더라도 생각할 사이드 이펙트가 많다.
  4. 데이터를 기반으로 사용자의 원하는 바를 추측하는게 성공 확률이 가장 높다. 다만 이게 항상 맞는 방법은 아니다.
  5. 로그는 매우 중요하다. 책임이 누구에게 있는지는 많은 것이 달려있다.
  6. 어떤 기술이든 첫 선택은 매우 중요하다. 첫 기술 선택은 대다수가 평생간다. (특히 관리자 페이지)
  7. 프로그래머는 코딩만 하는 직업이 아니다. 사용자 관점에서 누구보다 열심히 생각하고 기획할 줄 알아야 한다.
  8. 기술은 개인의 사리사욕을 충족하면서 적용하면 안된다. 시험적인 기술을 시도하여 개발하는 건 좋지 못하다.
  9. 도메인 지식은 매우 중요하다. 도메인 지식을 모르는 채, 디자인 및 기획, 프로그래밍을 하는 것은 올바른 모델링, 디자인, 기획이 나오지 않는다.
  10. 다양한 기술을 먼저 사이드 프로젝트에서 시도하는 건 좋다. 프론트앤드 개발자라고 백앤드를 모르는 건 틀린 생각이다. 다양한 방면으로 공부할수록 지식의 폭이 확장된다.

가장 중요한 것은 유저 입장에서 생각하라 인 것 같다. 유저를 위해 서비스를 개발하는게 개발자의 일이라고 생각한다. 유저 입장에서 생각해보며 더 좋은 서비스를 제공하기 위해서 어떤 기술을 추가하면 좋을까? 하는 고민을 위해 사이드 프로젝트를 하게 되고 사용자에게 더 좋은 추천을 제공하기 위해서 데이터 사이언스를 공부하게 되고.. 어셈블리 스터디, 데이터사이언스 스터디등 다양한 생각으로의 확장이 가능했던 시간이었다.

앞으로 다닐 우아한형제들에서는 내가 부족했던 대규모 사용자에 대한 경험을 하게 될 거라 생각한다. 이 시간도 결코 쉽지 않겠지만, 더 나은 내가 될거라 생각한다.